1 /* 2 * Copyright (C) 2019 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 #define LOG_TAG "apexd" 18 19 #include "apex_preinstalled_data.h" 20 21 #include <unordered_map> 22 23 #include <android-base/file.h> 24 #include <android-base/result.h> 25 #include <android-base/strings.h> 26 27 #include "apex_constants.h" 28 #include "apex_file.h" 29 #include "apexd_utils.h" 30 #include "string_log.h" 31 32 using android::base::Error; 33 using android::base::Result; 34 35 namespace android { 36 namespace apex { 37 38 namespace { 39 40 struct ApexPreinstalledData { 41 std::string name; 42 std::string key; 43 std::string path; 44 }; 45 46 std::unordered_map<std::string, ApexPreinstalledData> gScannedPreinstalledData; 47 collectPreinstalleDataFromDir(const std::string & dir)48Result<std::vector<ApexPreinstalledData>> collectPreinstalleDataFromDir( 49 const std::string& dir) { 50 LOG(INFO) << "Scanning " << dir << " for preinstalled data"; 51 std::vector<ApexPreinstalledData> ret; 52 if (access(dir.c_str(), F_OK) != 0 && errno == ENOENT) { 53 LOG(INFO) << "... does not exist. Skipping"; 54 return ret; 55 } 56 const bool scanBuiltinApexes = isPathForBuiltinApexes(dir); 57 if (!scanBuiltinApexes) { 58 return Error() << "Can't scan preinstalled APEX data from " << dir; 59 } 60 Result<std::vector<std::string>> apex_files = FindApexFilesByName(dir); 61 if (!apex_files.ok()) { 62 return apex_files.error(); 63 } 64 65 for (const auto& file : *apex_files) { 66 Result<ApexFile> apex_file = ApexFile::Open(file); 67 if (!apex_file.ok()) { 68 return Error() << "Failed to open " << file << " : " << apex_file.error(); 69 } 70 ApexPreinstalledData apexPreInstalledData; 71 apexPreInstalledData.name = apex_file->GetManifest().name(); 72 apexPreInstalledData.key = apex_file->GetBundledPublicKey(); 73 apexPreInstalledData.path = apex_file->GetPath(); 74 ret.push_back(apexPreInstalledData); 75 } 76 return ret; 77 } 78 updatePreinstalledData(const std::vector<ApexPreinstalledData> & apexes)79Result<void> updatePreinstalledData( 80 const std::vector<ApexPreinstalledData>& apexes) { 81 for (const ApexPreinstalledData& apex : apexes) { 82 if (gScannedPreinstalledData.find(apex.name) == 83 gScannedPreinstalledData.end()) { 84 gScannedPreinstalledData.insert({apex.name, apex}); 85 } else { 86 const std::string& existing_key = 87 gScannedPreinstalledData.at(apex.name).key; 88 if (existing_key != apex.key) { 89 return Error() << "Key for package " << apex.name 90 << " does not match with previously scanned key"; 91 } 92 } 93 } 94 return {}; 95 } 96 97 } // namespace 98 collectPreinstalledData(const std::vector<std::string> & dirs)99Result<void> collectPreinstalledData(const std::vector<std::string>& dirs) { 100 for (const auto& dir : dirs) { 101 Result<std::vector<ApexPreinstalledData>> preinstalledData = 102 collectPreinstalleDataFromDir(dir); 103 if (!preinstalledData.ok()) { 104 return Error() << "Failed to collect keys from " << dir << " : " 105 << preinstalledData.error(); 106 } 107 Result<void> st = updatePreinstalledData(*preinstalledData); 108 if (!st.ok()) { 109 return st; 110 } 111 } 112 return {}; 113 } 114 getApexKey(const std::string & name)115Result<const std::string> getApexKey(const std::string& name) { 116 if (gScannedPreinstalledData.find(name) == gScannedPreinstalledData.end()) { 117 return Error() << "No preinstalled data found for package " << name; 118 } 119 return gScannedPreinstalledData[name].key; 120 } 121 getApexPreinstalledPath(const std::string & name)122Result<const std::string> getApexPreinstalledPath(const std::string& name) { 123 if (gScannedPreinstalledData.find(name) == gScannedPreinstalledData.end()) { 124 return Error() << "No preinstalled data found for package " << name; 125 } 126 return gScannedPreinstalledData[name].path; 127 } 128 HasPreInstalledVersion(const std::string & name)129bool HasPreInstalledVersion(const std::string& name) { 130 return gScannedPreinstalledData.find(name) != gScannedPreinstalledData.end(); 131 } 132 133 } // namespace apex 134 } // namespace android 135