1 /*
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>
20 #include <android-base/strings.h>
21
22 #include "RuntimeInfo.h"
23
24 #include "CompatibilityMatrix.h"
25 #include "KernelConfigParser.h"
26 #include "parse_string.h"
27
28 #include <dirent.h>
29 #include <errno.h>
30 #include <sys/utsname.h>
31 #include <unistd.h>
32
33 #include <fstream>
34 #include <iostream>
35 #include <sstream>
36
37 #include <android-base/properties.h>
38 #include <selinux/selinux.h>
39 #include <zlib.h>
40
41 #define PROC_CONFIG "/proc/config.gz"
42 #define BUFFER_SIZE sysconf(_SC_PAGESIZE)
43
44 static constexpr char kMainline[] = "-mainline-";
45
46 namespace android {
47 namespace vintf {
48
49 struct RuntimeInfoFetcher {
RuntimeInfoFetcherandroid::vintf::RuntimeInfoFetcher50 RuntimeInfoFetcher(RuntimeInfo *ki) : mRuntimeInfo(ki) { }
51 status_t fetchAllInformation(RuntimeInfo::FetchFlags flags);
52
53 private:
54 status_t fetchVersion(RuntimeInfo::FetchFlags flags);
55 status_t fetchKernelConfigs(RuntimeInfo::FetchFlags flags);
56 status_t fetchCpuInfo(RuntimeInfo::FetchFlags flags);
57 status_t fetchKernelSepolicyVers(RuntimeInfo::FetchFlags flags);
58 status_t fetchAvb(RuntimeInfo::FetchFlags flags);
59 status_t parseKernelVersion();
60 RuntimeInfo *mRuntimeInfo;
61 KernelConfigParser mConfigParser;
62 };
63
64 // decompress /proc/config.gz and read its contents.
fetchKernelConfigs(RuntimeInfo::FetchFlags)65 status_t RuntimeInfoFetcher::fetchKernelConfigs(RuntimeInfo::FetchFlags) {
66 gzFile f = gzopen(PROC_CONFIG, "rb");
67 if (f == NULL) {
68 LOG(ERROR) << "Could not open /proc/config.gz: " << errno;
69 return -errno;
70 }
71
72 char buf[BUFFER_SIZE];
73 int len;
74 while ((len = gzread(f, buf, sizeof buf)) > 0) {
75 mConfigParser.process(buf, len);
76 }
77 status_t err = OK;
78 if (len < 0) {
79 int errnum;
80 const char *errmsg = gzerror(f, &errnum);
81 LOG(ERROR) << "Could not read /proc/config.gz: " << errmsg;
82 err = (errnum == Z_ERRNO ? -errno : errnum);
83 }
84 mConfigParser.finish();
85 gzclose(f);
86 mRuntimeInfo->mKernel.mConfigs = std::move(mConfigParser.configs());
87 return err;
88 }
89
fetchCpuInfo(RuntimeInfo::FetchFlags)90 status_t RuntimeInfoFetcher::fetchCpuInfo(RuntimeInfo::FetchFlags) {
91 // TODO implement this; 32-bit and 64-bit has different format.
92 std::ifstream in{"/proc/cpuinfo"};
93 if (!in.is_open()) {
94 LOG(WARNING) << "Cannot read /proc/cpuinfo";
95 return UNKNOWN_ERROR;
96 }
97 std::stringstream sstream;
98 sstream << in.rdbuf();
99 mRuntimeInfo->mCpuInfo = sstream.str();
100 return OK;
101 }
102
fetchKernelSepolicyVers(RuntimeInfo::FetchFlags)103 status_t RuntimeInfoFetcher::fetchKernelSepolicyVers(RuntimeInfo::FetchFlags) {
104 int pv;
105 #ifdef LIBVINTF_TARGET
106 pv = security_policyvers();
107 #else
108 pv = 0;
109 #endif
110 if (pv < 0) {
111 return pv;
112 }
113 mRuntimeInfo->mKernelSepolicyVersion = pv;
114 return OK;
115 }
116
fetchVersion(RuntimeInfo::FetchFlags flags)117 status_t RuntimeInfoFetcher::fetchVersion(RuntimeInfo::FetchFlags flags) {
118 struct utsname buf;
119 if (uname(&buf)) {
120 return -errno;
121 }
122 mRuntimeInfo->mOsName = buf.sysname;
123 mRuntimeInfo->mNodeName = buf.nodename;
124 mRuntimeInfo->mOsRelease = buf.release;
125 mRuntimeInfo->mOsVersion = buf.version;
126 mRuntimeInfo->mHardwareId = buf.machine;
127
128 mRuntimeInfo->mIsMainline = mRuntimeInfo->mOsRelease.find(kMainline) != std::string::npos;
129
130 status_t err = RuntimeInfo::parseGkiKernelRelease(flags, mRuntimeInfo->mOsRelease,
131 &mRuntimeInfo->mKernel.mVersion,
132 &mRuntimeInfo->mKernel.mLevel);
133 if (err == OK) return OK;
134
135 err = parseKernelVersion();
136 if (err != OK) {
137 LOG(ERROR) << "Could not parse kernel version from \""
138 << mRuntimeInfo->mOsRelease << "\"";
139 }
140 return err;
141 }
142
parseKernelVersion()143 status_t RuntimeInfoFetcher::parseKernelVersion() {
144 auto pos = mRuntimeInfo->mOsRelease.find('.');
145 if (pos == std::string::npos) {
146 return UNKNOWN_ERROR;
147 }
148 pos = mRuntimeInfo->mOsRelease.find('.', pos + 1);
149 if (pos == std::string::npos) {
150 return UNKNOWN_ERROR;
151 }
152 pos = mRuntimeInfo->mOsRelease.find_first_not_of("0123456789", pos + 1);
153 // no need to check pos == std::string::npos, because substr will handle this
154 if (!parse(mRuntimeInfo->mOsRelease.substr(0, pos), &mRuntimeInfo->mKernel.mVersion)) {
155 return UNKNOWN_ERROR;
156 }
157 return OK;
158 }
159
fetchAvb(RuntimeInfo::FetchFlags)160 status_t RuntimeInfoFetcher::fetchAvb(RuntimeInfo::FetchFlags) {
161 std::string prop = android::base::GetProperty("ro.boot.vbmeta.avb_version", "0.0");
162 if (!parse(prop, &mRuntimeInfo->mBootVbmetaAvbVersion)) {
163 return UNKNOWN_ERROR;
164 }
165 prop = android::base::GetProperty("ro.boot.avb_version", "0.0");
166 if (!parse(prop, &mRuntimeInfo->mBootAvbVersion)) {
167 return UNKNOWN_ERROR;
168 }
169 return OK;
170 }
171
172 struct FetchFunction {
173 RuntimeInfo::FetchFlags flags;
174 std::function<status_t(RuntimeInfoFetcher*, RuntimeInfo::FetchFlags)> fetch;
175 std::string description;
176 };
177
fetchAllInformation(RuntimeInfo::FetchFlags flags)178 status_t RuntimeInfoFetcher::fetchAllInformation(RuntimeInfo::FetchFlags flags) {
179 using F = RuntimeInfo::FetchFlag;
180 using RF = RuntimeInfoFetcher;
181 // clang-format off
182 const static std::vector<FetchFunction> gFetchFunctions({
183 {F::CPU_VERSION | F::KERNEL_FCM, &RF::fetchVersion, "/proc/version"},
184 {F::CONFIG_GZ, &RF::fetchKernelConfigs, "/proc/config.gz"},
185 {F::CPU_INFO, &RF::fetchCpuInfo, "/proc/cpuinfo"},
186 {F::POLICYVERS, &RF::fetchKernelSepolicyVers, "kernel sepolicy version"},
187 {F::AVB, &RF::fetchAvb, "avb version"},
188 });
189 // clang-format on
190
191 status_t err;
192 for (const auto& fetchFunction : gFetchFunctions)
193 if ((flags & fetchFunction.flags) && ((err = fetchFunction.fetch(this, flags)) != OK))
194 LOG(WARNING) << "Cannot fetch or parse " << fetchFunction.description << ": "
195 << strerror(-err);
196
197 return OK;
198 }
199
fetchAllInformation(RuntimeInfo::FetchFlags flags)200 status_t RuntimeInfo::fetchAllInformation(RuntimeInfo::FetchFlags flags) {
201 return RuntimeInfoFetcher(this).fetchAllInformation(flags);
202 }
203
204 } // namespace vintf
205 } // namespace android
206