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 <android-base/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(RuntimeInfo::FetchFlags flags); 49 50 private: 51 status_t fetchVersion(); 52 status_t fetchKernelConfigs(); 53 status_t fetchCpuInfo(); 54 status_t fetchKernelSepolicyVers(); 55 status_t fetchAvb(); 56 status_t parseKernelVersion(); 57 RuntimeInfo *mRuntimeInfo; 58 KernelConfigParser mConfigParser; 59 }; 60 61 // decompress /proc/config.gz and read its contents. 62 status_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) { 72 mConfigParser.process(buf, len); 73 } 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 } 81 mConfigParser.finish(); 82 gzclose(f); 83 mRuntimeInfo->mKernelConfigs = std::move(mConfigParser.configs()); 84 return err; 85 } 86 87 status_t RuntimeInfoFetcher::fetchCpuInfo() { 88 // TODO implement this; 32-bit and 64-bit has different format. 89 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(); 97 return OK; 98 } 99 100 status_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 114 status_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 133 status_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 150 status_t RuntimeInfoFetcher::fetchAvb() { 151 std::string prop = android::base::GetProperty("ro.boot.vbmeta.avb_version", "0.0"); 152 if (!parse(prop, &mRuntimeInfo->mBootVbmetaAvbVersion)) { 153 return UNKNOWN_ERROR; 154 } 155 prop = android::base::GetProperty("ro.boot.avb_version", "0.0"); 156 if (!parse(prop, &mRuntimeInfo->mBootAvbVersion)) { 157 return UNKNOWN_ERROR; 158 } 159 return OK; 160 } 161 162 status_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 176 status_t err; 177 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 182 return OK; 183 } 184 185 status_t RuntimeInfo::fetchAllInformation(RuntimeInfo::FetchFlags flags) { 186 return RuntimeInfoFetcher(this).fetchAllInformation(flags); 187 } 188 189 } // namespace vintf 190 } // namespace android 191