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
HandleSubcommand(char ** argv)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
InstallSigtermSignalHandler()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
main(int,char ** argv)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