1 /* 2 * Copyright (C) 2018 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 <strings.h> 20 #include <sys/stat.h> 21 22 #include <ApexProperties.sysprop.h> 23 #include <android-base/logging.h> 24 25 #include "apexd.h" 26 #include "apexd_checkpoint_vold.h" 27 #include "apexd_lifecycle.h" 28 #include "apexd_prepostinstall.h" 29 #include "apexservice.h" 30 31 #include <android-base/properties.h> 32 33 namespace { 34 35 int HandleSubcommand(char** argv) { 36 if (strcmp("--pre-install", argv[1]) == 0) { 37 LOG(INFO) << "Preinstall subcommand detected"; 38 return android::apex::RunPreInstall(argv); 39 } 40 41 if (strcmp("--post-install", argv[1]) == 0) { 42 LOG(INFO) << "Postinstall subcommand detected"; 43 return android::apex::RunPostInstall(argv); 44 } 45 46 if (strcmp("--bootstrap", argv[1]) == 0) { 47 LOG(INFO) << "Bootstrap subcommand detected"; 48 return android::apex::OnBootstrap(); 49 } 50 51 if (strcmp("--unmount-all", argv[1]) == 0) { 52 LOG(INFO) << "Unmount all subcommand detected"; 53 return android::apex::UnmountAll(); 54 } 55 56 if (strcmp("--otachroot-bootstrap", argv[1]) == 0) { 57 LOG(INFO) << "OTA chroot bootstrap subcommand detected"; 58 return android::apex::OnOtaChrootBootstrap(); 59 } 60 61 if (strcmp("--snapshotde", argv[1]) == 0) { 62 LOG(INFO) << "Snapshot DE subcommand detected"; 63 // Need to know if checkpointing is enabled so that a prerestore snapshot 64 // can be taken if it's not. 65 android::base::Result<android::apex::VoldCheckpointInterface> 66 vold_service_st = android::apex::VoldCheckpointInterface::Create(); 67 if (!vold_service_st.ok()) { 68 LOG(ERROR) << "Could not retrieve vold service: " 69 << vold_service_st.error(); 70 } else { 71 android::apex::InitializeVold(&*vold_service_st); 72 } 73 74 int result = android::apex::SnapshotOrRestoreDeUserData(); 75 76 if (result == 0) { 77 // Notify other components (e.g. init) that all APEXs are ready to be used 78 // Note that it's important that the binder service is registered at this 79 // point, since other system services might depend on it. 80 android::apex::OnAllPackagesReady(); 81 } 82 return result; 83 } 84 85 LOG(ERROR) << "Unknown subcommand: " << argv[1]; 86 return 1; 87 } 88 89 void InstallSigtermSignalHandler() { 90 struct sigaction action = {}; 91 action.sa_handler = [](int /*signal*/) { 92 // Handle SIGTERM gracefully. 93 // By default, when SIGTERM is received a process will exit with non-zero 94 // exit code, which will trigger reboot_on_failure handler if one is 95 // defined. This doesn't play well with userspace reboot which might 96 // terminate apexd with SIGTERM if apexd was running at the moment of 97 // userspace reboot, hence this custom handler to exit gracefully. 98 _exit(0); 99 }; 100 sigaction(SIGTERM, &action, nullptr); 101 } 102 103 } // namespace 104 105 int main(int /*argc*/, char** argv) { 106 android::base::InitLogging(argv, &android::base::KernelLogger); 107 // TODO(b/158468454): add a -v flag or an external setting to change severity. 108 android::base::SetMinimumLogSeverity(android::base::INFO); 109 110 // set umask to 022 so that files/dirs created are accessible to other 111 // processes e.g.) apex-info-file.xml is supposed to be read by other 112 // processes 113 umask(022); 114 115 InstallSigtermSignalHandler(); 116 117 android::apex::SetConfig(android::apex::kDefaultConfig); 118 119 android::apex::ApexdLifecycle& lifecycle = 120 android::apex::ApexdLifecycle::GetInstance(); 121 bool booting = lifecycle.IsBooting(); 122 123 const bool has_subcommand = argv[1] != nullptr; 124 if (!android::sysprop::ApexProperties::updatable().value_or(false)) { 125 if (!has_subcommand) { 126 if (!booting) { 127 // We've finished booting, but for some reason somebody tried to start 128 // apexd. Simply exit. 129 return 0; 130 } 131 132 LOG(INFO) << "This device does not support updatable APEX. Exiting"; 133 // Mark apexd as activated so that init can proceed. 134 android::apex::OnAllPackagesActivated(/*is_bootstrap=*/false); 135 } else if (strcmp("--snapshotde", argv[1]) == 0) { 136 LOG(INFO) << "This device does not support updatable APEX. Exiting"; 137 // mark apexd as ready 138 android::apex::OnAllPackagesReady(); 139 } else if (strcmp("--otachroot-bootstrap", argv[1]) == 0) { 140 return android::apex::OnOtaChrootBootstrapFlattenedApex(); 141 } 142 return 0; 143 } 144 145 if (has_subcommand) { 146 return HandleSubcommand(argv); 147 } 148 149 android::base::Result<android::apex::VoldCheckpointInterface> 150 vold_service_st = android::apex::VoldCheckpointInterface::Create(); 151 android::apex::VoldCheckpointInterface* vold_service = nullptr; 152 if (!vold_service_st.ok()) { 153 LOG(ERROR) << "Could not retrieve vold service: " 154 << vold_service_st.error(); 155 } else { 156 vold_service = &*vold_service_st; 157 } 158 android::apex::Initialize(vold_service); 159 160 if (booting) { 161 if (auto res = android::apex::MigrateSessionsDirIfNeeded(); !res.ok()) { 162 LOG(ERROR) << "Failed to migrate sessions to /metadata partition : " 163 << res.error(); 164 } 165 android::apex::OnStart(); 166 } else { 167 // TODO(b/172911822): Trying to use data apex related ApexFileRepository 168 // apis without initializing it should throw error. Also, unit tests should 169 // not pass without initialization. 170 // TODO(b/172911822): Consolidate this with Initialize() when 171 // ApexFileRepository can act as cache and re-scanning is not expensive 172 android::apex::InitializeDataApex(); 173 } 174 android::apex::binder::CreateAndRegisterService(); 175 android::apex::binder::StartThreadPool(); 176 177 if (booting) { 178 // Notify other components (e.g. init) that all APEXs are correctly mounted 179 // and activated (but are not yet ready to be used). Configuration based on 180 // activated APEXs may be performed at this point, but use of APEXs 181 // themselves should wait for the ready status instead, which is set when 182 // the "--snapshotde" subcommand is received and snapshot/restore is 183 // complete. 184 android::apex::OnAllPackagesActivated(/*is_bootstrap=*/false); 185 lifecycle.WaitForBootStatus(android::apex::RevertActiveSessionsAndReboot); 186 } 187 188 // Run cleanup routine before AllowServiceShutdown(), to prevent 189 // service_manager killing apexd in the middle of the cleanup. 190 android::apex::BootCompletedCleanup(); 191 android::apex::binder::AllowServiceShutdown(); 192 193 android::apex::binder::JoinThreadPool(); 194 return 1; 195 } 196