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