blob: 3ef5aaa7a246aa440bb4e160e9420fa37f987b4f [file] [log] [blame]
Yifan Hong25c1eed2017-04-07 13:50:24 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18#define LOG_TAG "libvintf"
19#include <android-base/logging.h>
Yifan Hong23502692020-04-06 18:46:20 -070020#include <android-base/strings.h>
Yifan Hong25c1eed2017-04-07 13:50:24 -070021
22#include "RuntimeInfo.h"
23
24#include "CompatibilityMatrix.h"
Yifan Honge4959a12017-07-05 16:05:09 -070025#include "KernelConfigParser.h"
Yifan Hong25c1eed2017-04-07 13:50:24 -070026#include "parse_string.h"
27
Yifan Hong5075f452017-04-20 14:00:24 -070028#include <dirent.h>
Yifan Hong25c1eed2017-04-07 13:50:24 -070029#include <errno.h>
30#include <sys/utsname.h>
31#include <unistd.h>
32
Yifan Hong242eabf2017-04-20 14:06:26 -070033#include <fstream>
34#include <iostream>
35#include <sstream>
36
Yifan Honge621fb12018-02-28 14:41:38 -080037#include <android-base/properties.h>
Yifan Hong25c1eed2017-04-07 13:50:24 -070038#include <selinux/selinux.h>
39#include <zlib.h>
40
41#define PROC_CONFIG "/proc/config.gz"
42#define BUFFER_SIZE sysconf(_SC_PAGESIZE)
43
Yifan Hong23502692020-04-06 18:46:20 -070044static constexpr char kMainline[] = "-mainline-";
Yifan Honge769d1b2021-10-01 15:26:40 -070045static constexpr char kMainlineSuffix[] = "-mainline";
Yifan Hong23502692020-04-06 18:46:20 -070046
Yifan Hong25c1eed2017-04-07 13:50:24 -070047namespace android {
48namespace vintf {
49
Yifan Hong25c1eed2017-04-07 13:50:24 -070050struct RuntimeInfoFetcher {
51 RuntimeInfoFetcher(RuntimeInfo *ki) : mRuntimeInfo(ki) { }
Yifan Hong1fb004e2017-09-26 15:04:44 -070052 status_t fetchAllInformation(RuntimeInfo::FetchFlags flags);
53
54 private:
Yifan Hong5a5dbef2020-11-10 17:31:47 -080055 status_t fetchVersion(RuntimeInfo::FetchFlags flags);
56 status_t fetchKernelConfigs(RuntimeInfo::FetchFlags flags);
57 status_t fetchCpuInfo(RuntimeInfo::FetchFlags flags);
58 status_t fetchKernelSepolicyVers(RuntimeInfo::FetchFlags flags);
59 status_t fetchAvb(RuntimeInfo::FetchFlags flags);
Yifan Hong25c1eed2017-04-07 13:50:24 -070060 status_t parseKernelVersion();
61 RuntimeInfo *mRuntimeInfo;
Yifan Honge4959a12017-07-05 16:05:09 -070062 KernelConfigParser mConfigParser;
Yifan Hong25c1eed2017-04-07 13:50:24 -070063};
64
65// decompress /proc/config.gz and read its contents.
Yifan Hong5a5dbef2020-11-10 17:31:47 -080066status_t RuntimeInfoFetcher::fetchKernelConfigs(RuntimeInfo::FetchFlags) {
Yifan Hong25c1eed2017-04-07 13:50:24 -070067 gzFile f = gzopen(PROC_CONFIG, "rb");
68 if (f == NULL) {
69 LOG(ERROR) << "Could not open /proc/config.gz: " << errno;
70 return -errno;
71 }
72
73 char buf[BUFFER_SIZE];
74 int len;
75 while ((len = gzread(f, buf, sizeof buf)) > 0) {
Yifan Honge4959a12017-07-05 16:05:09 -070076 mConfigParser.process(buf, len);
Yifan Hong25c1eed2017-04-07 13:50:24 -070077 }
78 status_t err = OK;
79 if (len < 0) {
80 int errnum;
81 const char *errmsg = gzerror(f, &errnum);
82 LOG(ERROR) << "Could not read /proc/config.gz: " << errmsg;
83 err = (errnum == Z_ERRNO ? -errno : errnum);
84 }
Yifan Honge4959a12017-07-05 16:05:09 -070085 mConfigParser.finish();
Yifan Hong25c1eed2017-04-07 13:50:24 -070086 gzclose(f);
Yifan Hong90ed9972018-12-03 15:08:34 -080087 mRuntimeInfo->mKernel.mConfigs = std::move(mConfigParser.configs());
Yifan Hong25c1eed2017-04-07 13:50:24 -070088 return err;
89}
90
Yifan Hong5a5dbef2020-11-10 17:31:47 -080091status_t RuntimeInfoFetcher::fetchCpuInfo(RuntimeInfo::FetchFlags) {
Yifan Hong25c1eed2017-04-07 13:50:24 -070092 // TODO implement this; 32-bit and 64-bit has different format.
Yifan Hong242eabf2017-04-20 14:06:26 -070093 std::ifstream in{"/proc/cpuinfo"};
94 if (!in.is_open()) {
95 LOG(WARNING) << "Cannot read /proc/cpuinfo";
96 return UNKNOWN_ERROR;
97 }
98 std::stringstream sstream;
99 sstream << in.rdbuf();
100 mRuntimeInfo->mCpuInfo = sstream.str();
Yifan Hong25c1eed2017-04-07 13:50:24 -0700101 return OK;
102}
103
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800104status_t RuntimeInfoFetcher::fetchKernelSepolicyVers(RuntimeInfo::FetchFlags) {
Yifan Hong25c1eed2017-04-07 13:50:24 -0700105 int pv;
106#ifdef LIBVINTF_TARGET
107 pv = security_policyvers();
108#else
109 pv = 0;
110#endif
111 if (pv < 0) {
112 return pv;
113 }
114 mRuntimeInfo->mKernelSepolicyVersion = pv;
115 return OK;
116}
117
Yifan Honge3c3d532020-11-10 17:34:24 -0800118status_t RuntimeInfoFetcher::fetchVersion(RuntimeInfo::FetchFlags flags) {
Yifan Hong25c1eed2017-04-07 13:50:24 -0700119 struct utsname buf;
120 if (uname(&buf)) {
121 return -errno;
122 }
123 mRuntimeInfo->mOsName = buf.sysname;
124 mRuntimeInfo->mNodeName = buf.nodename;
125 mRuntimeInfo->mOsRelease = buf.release;
126 mRuntimeInfo->mOsVersion = buf.version;
127 mRuntimeInfo->mHardwareId = buf.machine;
128
Yifan Honge769d1b2021-10-01 15:26:40 -0700129 mRuntimeInfo->mIsMainline = mRuntimeInfo->mOsRelease.find(kMainline) != std::string::npos ||
130 android::base::EndsWith(mRuntimeInfo->mOsRelease, kMainlineSuffix);
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800131
Yifan Honge3c3d532020-11-10 17:34:24 -0800132 status_t err = RuntimeInfo::parseGkiKernelRelease(flags, mRuntimeInfo->mOsRelease,
133 &mRuntimeInfo->mKernel.mVersion,
134 &mRuntimeInfo->mKernel.mLevel);
135 if (err == OK) return OK;
136
137 err = parseKernelVersion();
Yifan Hong25c1eed2017-04-07 13:50:24 -0700138 if (err != OK) {
139 LOG(ERROR) << "Could not parse kernel version from \""
140 << mRuntimeInfo->mOsRelease << "\"";
141 }
142 return err;
143}
144
145status_t RuntimeInfoFetcher::parseKernelVersion() {
146 auto pos = mRuntimeInfo->mOsRelease.find('.');
147 if (pos == std::string::npos) {
148 return UNKNOWN_ERROR;
149 }
150 pos = mRuntimeInfo->mOsRelease.find('.', pos + 1);
151 if (pos == std::string::npos) {
152 return UNKNOWN_ERROR;
153 }
154 pos = mRuntimeInfo->mOsRelease.find_first_not_of("0123456789", pos + 1);
155 // no need to check pos == std::string::npos, because substr will handle this
Yifan Hong90ed9972018-12-03 15:08:34 -0800156 if (!parse(mRuntimeInfo->mOsRelease.substr(0, pos), &mRuntimeInfo->mKernel.mVersion)) {
Yifan Hong25c1eed2017-04-07 13:50:24 -0700157 return UNKNOWN_ERROR;
158 }
159 return OK;
160}
161
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800162status_t RuntimeInfoFetcher::fetchAvb(RuntimeInfo::FetchFlags) {
Yifan Honge621fb12018-02-28 14:41:38 -0800163 std::string prop = android::base::GetProperty("ro.boot.vbmeta.avb_version", "0.0");
Yifan Hong881a9e452017-04-27 19:31:13 -0700164 if (!parse(prop, &mRuntimeInfo->mBootVbmetaAvbVersion)) {
Yifan Hongf3029302017-04-12 17:23:49 -0700165 return UNKNOWN_ERROR;
166 }
Yifan Honge621fb12018-02-28 14:41:38 -0800167 prop = android::base::GetProperty("ro.boot.avb_version", "0.0");
Yifan Hong881a9e452017-04-27 19:31:13 -0700168 if (!parse(prop, &mRuntimeInfo->mBootAvbVersion)) {
Yifan Hongf3029302017-04-12 17:23:49 -0700169 return UNKNOWN_ERROR;
170 }
171 return OK;
172}
173
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800174struct FetchFunction {
175 RuntimeInfo::FetchFlags flags;
176 std::function<status_t(RuntimeInfoFetcher*, RuntimeInfo::FetchFlags)> fetch;
177 std::string description;
178};
Yifan Hong1fb004e2017-09-26 15:04:44 -0700179
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800180status_t RuntimeInfoFetcher::fetchAllInformation(RuntimeInfo::FetchFlags flags) {
Yifan Hong1fb004e2017-09-26 15:04:44 -0700181 using F = RuntimeInfo::FetchFlag;
182 using RF = RuntimeInfoFetcher;
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800183 // clang-format off
184 const static std::vector<FetchFunction> gFetchFunctions({
Yifan Honge3c3d532020-11-10 17:34:24 -0800185 {F::CPU_VERSION | F::KERNEL_FCM, &RF::fetchVersion, "/proc/version"},
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800186 {F::CONFIG_GZ, &RF::fetchKernelConfigs, "/proc/config.gz"},
187 {F::CPU_INFO, &RF::fetchCpuInfo, "/proc/cpuinfo"},
188 {F::POLICYVERS, &RF::fetchKernelSepolicyVers, "kernel sepolicy version"},
189 {F::AVB, &RF::fetchAvb, "avb version"},
Yifan Hong1fb004e2017-09-26 15:04:44 -0700190 });
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800191 // clang-format on
Yifan Hong1fb004e2017-09-26 15:04:44 -0700192
Yifan Hong25c1eed2017-04-07 13:50:24 -0700193 status_t err;
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800194 for (const auto& fetchFunction : gFetchFunctions)
Greg Kaiser8b7fabd2020-11-17 09:01:28 -0800195 if ((flags & fetchFunction.flags) && ((err = fetchFunction.fetch(this, flags)) != OK))
Yifan Hong5a5dbef2020-11-10 17:31:47 -0800196 LOG(WARNING) << "Cannot fetch or parse " << fetchFunction.description << ": "
Yifan Hong1fb004e2017-09-26 15:04:44 -0700197 << strerror(-err);
198
Yifan Hong25c1eed2017-04-07 13:50:24 -0700199 return OK;
200}
201
Yifan Hong1fb004e2017-09-26 15:04:44 -0700202status_t RuntimeInfo::fetchAllInformation(RuntimeInfo::FetchFlags flags) {
203 return RuntimeInfoFetcher(this).fetchAllInformation(flags);
Yifan Hong25c1eed2017-04-07 13:50:24 -0700204}
205
206} // namespace vintf
207} // namespace android