blob: e073562a6a28617692bafe0a237f9f343fffac48 [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"
24#include "parse_string.h"
25
26#include <errno.h>
27#include <sys/utsname.h>
28#include <unistd.h>
29
Yifan Hongf3029302017-04-12 17:23:49 -070030#include <cutils/properties.h>
Yifan Hong25c1eed2017-04-07 13:50:24 -070031#include <selinux/selinux.h>
32#include <zlib.h>
33
34#define PROC_CONFIG "/proc/config.gz"
35#define BUFFER_SIZE sysconf(_SC_PAGESIZE)
36
37namespace android {
38namespace vintf {
39
40static void removeTrailingComments(std::string *s) {
41 size_t sharpPos = s->find('#');
42 if (sharpPos != std::string::npos) {
43 s->erase(sharpPos);
44 }
45}
46static void trim(std::string *s) {
47 auto l = s->begin();
48 for (; l != s->end() && std::isspace(*l); ++l);
49 s->erase(s->begin(), l);
50 auto r = s->rbegin();
51 for (; r != s->rend() && std::isspace(*r); ++r);
52 s->erase(r.base(), s->end());
53}
54
55struct RuntimeInfoFetcher {
56 RuntimeInfoFetcher(RuntimeInfo *ki) : mRuntimeInfo(ki) { }
57 status_t fetchAllInformation();
58private:
59 void streamConfig(const char *buf, size_t len);
60 void parseConfig(std::string *s);
61 status_t fetchVersion();
62 status_t fetchKernelConfigs();
63 status_t fetchCpuInfo();
64 status_t fetchKernelSepolicyVers();
65 status_t fetchSepolicyFiles();
Yifan Hongf3029302017-04-12 17:23:49 -070066 status_t fetchAvb();
Yifan Hong25c1eed2017-04-07 13:50:24 -070067 status_t parseKernelVersion();
68 RuntimeInfo *mRuntimeInfo;
69 std::string mRemaining;
70};
71
72// decompress /proc/config.gz and read its contents.
73status_t RuntimeInfoFetcher::fetchKernelConfigs() {
74 gzFile f = gzopen(PROC_CONFIG, "rb");
75 if (f == NULL) {
76 LOG(ERROR) << "Could not open /proc/config.gz: " << errno;
77 return -errno;
78 }
79
80 char buf[BUFFER_SIZE];
81 int len;
82 while ((len = gzread(f, buf, sizeof buf)) > 0) {
83 streamConfig(buf, len);
84 }
85 status_t err = OK;
86 if (len < 0) {
87 int errnum;
88 const char *errmsg = gzerror(f, &errnum);
89 LOG(ERROR) << "Could not read /proc/config.gz: " << errmsg;
90 err = (errnum == Z_ERRNO ? -errno : errnum);
91 }
92
93 // stream a "\n" to end the stream to finish the last line.
94 streamConfig("\n", 1 /* sizeof "\n" */);
95
96 gzclose(f);
97 return err;
98}
99
100void RuntimeInfoFetcher::parseConfig(std::string *s) {
101 removeTrailingComments(s);
102 trim(s);
103 if (s->empty()) {
104 return;
105 }
106 size_t equalPos = s->find('=');
107 if (equalPos == std::string::npos) {
108 LOG(WARNING) << "Unrecognized line in /proc/config.gz: " << *s;
109 return;
110 }
111 std::string key = s->substr(0, equalPos);
112 std::string value = s->substr(equalPos + 1);
113 if (!mRuntimeInfo->mKernelConfigs.emplace(std::move(key), std::move(value)).second) {
114 LOG(WARNING) << "Duplicated key in /proc/config.gz: " << s->substr(0, equalPos);
115 return;
116 }
117}
118
119void RuntimeInfoFetcher::streamConfig(const char *buf, size_t len) {
120 const char *begin = buf;
121 const char *end = buf;
122 const char *stop = buf + len;
123 while (end < stop) {
124 if (*end == '\n') {
125 mRemaining.insert(mRemaining.size(), begin, end - begin);
126 parseConfig(&mRemaining);
127 mRemaining.clear();
128 begin = end + 1;
129 }
130 end++;
131 }
132 mRemaining.insert(mRemaining.size(), begin, end - begin);
133}
134
135status_t RuntimeInfoFetcher::fetchCpuInfo() {
136 // TODO implement this; 32-bit and 64-bit has different format.
137 return OK;
138}
139
140status_t RuntimeInfoFetcher::fetchKernelSepolicyVers() {
141 int pv;
142#ifdef LIBVINTF_TARGET
143 pv = security_policyvers();
144#else
145 pv = 0;
146#endif
147 if (pv < 0) {
148 return pv;
149 }
150 mRuntimeInfo->mKernelSepolicyVersion = pv;
151 return OK;
152}
153
154status_t RuntimeInfoFetcher::fetchVersion() {
155 struct utsname buf;
156 if (uname(&buf)) {
157 return -errno;
158 }
159 mRuntimeInfo->mOsName = buf.sysname;
160 mRuntimeInfo->mNodeName = buf.nodename;
161 mRuntimeInfo->mOsRelease = buf.release;
162 mRuntimeInfo->mOsVersion = buf.version;
163 mRuntimeInfo->mHardwareId = buf.machine;
164
165 status_t err = parseKernelVersion();
166 if (err != OK) {
167 LOG(ERROR) << "Could not parse kernel version from \""
168 << mRuntimeInfo->mOsRelease << "\"";
169 }
170 return err;
171}
172
173status_t RuntimeInfoFetcher::parseKernelVersion() {
174 auto pos = mRuntimeInfo->mOsRelease.find('.');
175 if (pos == std::string::npos) {
176 return UNKNOWN_ERROR;
177 }
178 pos = mRuntimeInfo->mOsRelease.find('.', pos + 1);
179 if (pos == std::string::npos) {
180 return UNKNOWN_ERROR;
181 }
182 pos = mRuntimeInfo->mOsRelease.find_first_not_of("0123456789", pos + 1);
183 // no need to check pos == std::string::npos, because substr will handle this
184 if (!parse(mRuntimeInfo->mOsRelease.substr(0, pos), &mRuntimeInfo->mKernelVersion)) {
185 return UNKNOWN_ERROR;
186 }
187 return OK;
188}
189
Yifan Hongfa2b18b2017-04-12 19:40:00 -0700190// Grab sepolicy file paths.
Yifan Hong25c1eed2017-04-07 13:50:24 -0700191status_t RuntimeInfoFetcher::fetchSepolicyFiles() {
Yifan Hongfa2b18b2017-04-12 19:40:00 -0700192 mRuntimeInfo->mSepolicyFilePaths = {
193 // TODO(b/36456394) need a list of sepolicy files
194 };
Yifan Hong25c1eed2017-04-07 13:50:24 -0700195 return OK;
196}
197
Yifan Hongf3029302017-04-12 17:23:49 -0700198status_t RuntimeInfoFetcher::fetchAvb() {
199 char prop[PROPERTY_VALUE_MAX];
200 property_get("ro.boot.vbmeta.avb_version", prop, "0.0");
201 if (!parse(prop, &mRuntimeInfo->mAvbBootVersion)) {
202 return UNKNOWN_ERROR;
203 }
204 property_get("ro.boot.avb_version", prop, "0.0");
205 if (!parse(prop, &mRuntimeInfo->mAvbInitVersion)) {
206 return UNKNOWN_ERROR;
207 }
208 return OK;
209}
210
Yifan Hong25c1eed2017-04-07 13:50:24 -0700211status_t RuntimeInfoFetcher::fetchAllInformation() {
212 status_t err;
213 if ((err = fetchVersion()) != OK) {
214 return err;
215 }
216 if ((err = fetchKernelConfigs()) != OK) {
217 return err;
218 }
219 if ((err = fetchCpuInfo()) != OK) {
220 return err;
221 }
222 if ((err = fetchKernelSepolicyVers()) != OK) {
223 return err;
224 }
225 if ((err = fetchSepolicyFiles()) != OK) {
226 return err;
227 }
Yifan Hongf3029302017-04-12 17:23:49 -0700228 if ((err = fetchAvb()) != OK) {
229 return err;
230 }
Yifan Hong25c1eed2017-04-07 13:50:24 -0700231 return OK;
232}
233
234status_t RuntimeInfo::fetchAllInformation() {
235 return RuntimeInfoFetcher(this).fetchAllInformation();
236}
237
238} // namespace vintf
239} // namespace android