blob: 6f2e9e80eb5a08797a27c849727fc1c248b330b8 [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>
20
21#include "RuntimeInfo.h"
22
23#include "CompatibilityMatrix.h"
Yifan Honge4959a12017-07-05 16:05:09 -070024#include "KernelConfigParser.h"
Yifan Hong25c1eed2017-04-07 13:50:24 -070025#include "parse_string.h"
26
Yifan Hong5075f452017-04-20 14:00:24 -070027#include <dirent.h>
Yifan Hong25c1eed2017-04-07 13:50:24 -070028#include <errno.h>
29#include <sys/utsname.h>
30#include <unistd.h>
31
Yifan Hong242eabf2017-04-20 14:06:26 -070032#include <fstream>
33#include <iostream>
34#include <sstream>
35
Yifan Honge621fb12018-02-28 14:41:38 -080036#include <android-base/properties.h>
Yifan Hong25c1eed2017-04-07 13:50:24 -070037#include <selinux/selinux.h>
38#include <zlib.h>
39
40#define PROC_CONFIG "/proc/config.gz"
41#define BUFFER_SIZE sysconf(_SC_PAGESIZE)
42
43namespace android {
44namespace vintf {
45
Yifan Hong25c1eed2017-04-07 13:50:24 -070046struct RuntimeInfoFetcher {
47 RuntimeInfoFetcher(RuntimeInfo *ki) : mRuntimeInfo(ki) { }
Yifan Hong1fb004e2017-09-26 15:04:44 -070048 status_t fetchAllInformation(RuntimeInfo::FetchFlags flags);
49
50 private:
Yifan Hong25c1eed2017-04-07 13:50:24 -070051 status_t fetchVersion();
52 status_t fetchKernelConfigs();
53 status_t fetchCpuInfo();
54 status_t fetchKernelSepolicyVers();
Yifan Hongf3029302017-04-12 17:23:49 -070055 status_t fetchAvb();
Yifan Hong25c1eed2017-04-07 13:50:24 -070056 status_t parseKernelVersion();
57 RuntimeInfo *mRuntimeInfo;
Yifan Honge4959a12017-07-05 16:05:09 -070058 KernelConfigParser mConfigParser;
Yifan Hong25c1eed2017-04-07 13:50:24 -070059};
60
61// decompress /proc/config.gz and read its contents.
62status_t RuntimeInfoFetcher::fetchKernelConfigs() {
63 gzFile f = gzopen(PROC_CONFIG, "rb");
64 if (f == NULL) {
65 LOG(ERROR) << "Could not open /proc/config.gz: " << errno;
66 return -errno;
67 }
68
69 char buf[BUFFER_SIZE];
70 int len;
71 while ((len = gzread(f, buf, sizeof buf)) > 0) {
Yifan Honge4959a12017-07-05 16:05:09 -070072 mConfigParser.process(buf, len);
Yifan Hong25c1eed2017-04-07 13:50:24 -070073 }
74 status_t err = OK;
75 if (len < 0) {
76 int errnum;
77 const char *errmsg = gzerror(f, &errnum);
78 LOG(ERROR) << "Could not read /proc/config.gz: " << errmsg;
79 err = (errnum == Z_ERRNO ? -errno : errnum);
80 }
Yifan Honge4959a12017-07-05 16:05:09 -070081 mConfigParser.finish();
Yifan Hong25c1eed2017-04-07 13:50:24 -070082 gzclose(f);
Yifan Honge4959a12017-07-05 16:05:09 -070083 mRuntimeInfo->mKernelConfigs = std::move(mConfigParser.configs());
Yifan Hong25c1eed2017-04-07 13:50:24 -070084 return err;
85}
86
Yifan Hong25c1eed2017-04-07 13:50:24 -070087status_t RuntimeInfoFetcher::fetchCpuInfo() {
88 // TODO implement this; 32-bit and 64-bit has different format.
Yifan Hong242eabf2017-04-20 14:06:26 -070089 std::ifstream in{"/proc/cpuinfo"};
90 if (!in.is_open()) {
91 LOG(WARNING) << "Cannot read /proc/cpuinfo";
92 return UNKNOWN_ERROR;
93 }
94 std::stringstream sstream;
95 sstream << in.rdbuf();
96 mRuntimeInfo->mCpuInfo = sstream.str();
Yifan Hong25c1eed2017-04-07 13:50:24 -070097 return OK;
98}
99
100status_t RuntimeInfoFetcher::fetchKernelSepolicyVers() {
101 int pv;
102#ifdef LIBVINTF_TARGET
103 pv = security_policyvers();
104#else
105 pv = 0;
106#endif
107 if (pv < 0) {
108 return pv;
109 }
110 mRuntimeInfo->mKernelSepolicyVersion = pv;
111 return OK;
112}
113
114status_t RuntimeInfoFetcher::fetchVersion() {
115 struct utsname buf;
116 if (uname(&buf)) {
117 return -errno;
118 }
119 mRuntimeInfo->mOsName = buf.sysname;
120 mRuntimeInfo->mNodeName = buf.nodename;
121 mRuntimeInfo->mOsRelease = buf.release;
122 mRuntimeInfo->mOsVersion = buf.version;
123 mRuntimeInfo->mHardwareId = buf.machine;
124
125 status_t err = parseKernelVersion();
126 if (err != OK) {
127 LOG(ERROR) << "Could not parse kernel version from \""
128 << mRuntimeInfo->mOsRelease << "\"";
129 }
130 return err;
131}
132
133status_t RuntimeInfoFetcher::parseKernelVersion() {
134 auto pos = mRuntimeInfo->mOsRelease.find('.');
135 if (pos == std::string::npos) {
136 return UNKNOWN_ERROR;
137 }
138 pos = mRuntimeInfo->mOsRelease.find('.', pos + 1);
139 if (pos == std::string::npos) {
140 return UNKNOWN_ERROR;
141 }
142 pos = mRuntimeInfo->mOsRelease.find_first_not_of("0123456789", pos + 1);
143 // no need to check pos == std::string::npos, because substr will handle this
144 if (!parse(mRuntimeInfo->mOsRelease.substr(0, pos), &mRuntimeInfo->mKernelVersion)) {
145 return UNKNOWN_ERROR;
146 }
147 return OK;
148}
149
Yifan Hongf3029302017-04-12 17:23:49 -0700150status_t RuntimeInfoFetcher::fetchAvb() {
Yifan Honge621fb12018-02-28 14:41:38 -0800151 std::string prop = android::base::GetProperty("ro.boot.vbmeta.avb_version", "0.0");
Yifan Hong881a9e452017-04-27 19:31:13 -0700152 if (!parse(prop, &mRuntimeInfo->mBootVbmetaAvbVersion)) {
Yifan Hongf3029302017-04-12 17:23:49 -0700153 return UNKNOWN_ERROR;
154 }
Yifan Honge621fb12018-02-28 14:41:38 -0800155 prop = android::base::GetProperty("ro.boot.avb_version", "0.0");
Yifan Hong881a9e452017-04-27 19:31:13 -0700156 if (!parse(prop, &mRuntimeInfo->mBootAvbVersion)) {
Yifan Hongf3029302017-04-12 17:23:49 -0700157 return UNKNOWN_ERROR;
158 }
159 return OK;
160}
161
Yifan Hong1fb004e2017-09-26 15:04:44 -0700162status_t RuntimeInfoFetcher::fetchAllInformation(RuntimeInfo::FetchFlags flags) {
163
164 using F = RuntimeInfo::FetchFlag;
165 using RF = RuntimeInfoFetcher;
166 using FetchFunction = status_t(RF::*)();
167 const static std::vector<std::tuple<F, FetchFunction, std::string>> gFetchFunctions({
168 // flag fetch function description
169 {F::CPU_VERSION, &RF::fetchVersion, "/proc/version"},
170 {F::CONFIG_GZ, &RF::fetchKernelConfigs, "/proc/config.gz"},
171 {F::CPU_INFO, &RF::fetchCpuInfo, "/proc/cpuinfo"},
172 {F::POLICYVERS, &RF::fetchKernelSepolicyVers, "kernel sepolicy version"},
173 {F::AVB, &RF::fetchAvb, "avb version"},
174 });
175
Yifan Hong25c1eed2017-04-07 13:50:24 -0700176 status_t err;
Yifan Hong1fb004e2017-09-26 15:04:44 -0700177 for (const auto& tuple : gFetchFunctions)
178 if ((flags & std::get<0>(tuple)) && (err = (*this.*std::get<1>(tuple))()) != OK)
179 LOG(WARNING) << "Cannot fetch or parse " << std::get<2>(tuple) << ": "
180 << strerror(-err);
181
Yifan Hong25c1eed2017-04-07 13:50:24 -0700182 return OK;
183}
184
Yifan Hong1fb004e2017-09-26 15:04:44 -0700185status_t RuntimeInfo::fetchAllInformation(RuntimeInfo::FetchFlags flags) {
186 return RuntimeInfoFetcher(this).fetchAllInformation(flags);
Yifan Hong25c1eed2017-04-07 13:50:24 -0700187}
188
189} // namespace vintf
190} // namespace android