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