xref: /aosp_15_r20/system/apex/apexd/apexd_main.cpp (revision 33f3758387333dbd2962d7edbd98681940d895da)
1*33f37583SAndroid Build Coastguard Worker /*
2*33f37583SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*33f37583SAndroid Build Coastguard Worker  *
4*33f37583SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*33f37583SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*33f37583SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*33f37583SAndroid Build Coastguard Worker  *
8*33f37583SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*33f37583SAndroid Build Coastguard Worker  *
10*33f37583SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*33f37583SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*33f37583SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*33f37583SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*33f37583SAndroid Build Coastguard Worker  * limitations under the License.
15*33f37583SAndroid Build Coastguard Worker  */
16*33f37583SAndroid Build Coastguard Worker 
17*33f37583SAndroid Build Coastguard Worker #define LOG_TAG "apexd"
18*33f37583SAndroid Build Coastguard Worker 
19*33f37583SAndroid Build Coastguard Worker #include <android-base/logging.h>
20*33f37583SAndroid Build Coastguard Worker #include <android-base/properties.h>
21*33f37583SAndroid Build Coastguard Worker #include <selinux/android.h>
22*33f37583SAndroid Build Coastguard Worker #include <strings.h>
23*33f37583SAndroid Build Coastguard Worker #include <sys/stat.h>
24*33f37583SAndroid Build Coastguard Worker 
25*33f37583SAndroid Build Coastguard Worker #include <memory>
26*33f37583SAndroid Build Coastguard Worker 
27*33f37583SAndroid Build Coastguard Worker #include "apex_file_repository.h"
28*33f37583SAndroid Build Coastguard Worker #include "apexd.h"
29*33f37583SAndroid Build Coastguard Worker #include "apexd_checkpoint_vold.h"
30*33f37583SAndroid Build Coastguard Worker #include "apexd_lifecycle.h"
31*33f37583SAndroid Build Coastguard Worker #include "apexd_metrics_stats.h"
32*33f37583SAndroid Build Coastguard Worker #include "apexservice.h"
33*33f37583SAndroid Build Coastguard Worker #include "com_android_apex_flags.h"
34*33f37583SAndroid Build Coastguard Worker 
35*33f37583SAndroid Build Coastguard Worker namespace flags = com::android::apex::flags;
36*33f37583SAndroid Build Coastguard Worker 
37*33f37583SAndroid Build Coastguard Worker namespace {
38*33f37583SAndroid Build Coastguard Worker 
39*33f37583SAndroid Build Coastguard Worker using android::base::SetDefaultTag;
40*33f37583SAndroid Build Coastguard Worker 
HandleSubcommand(int argc,char ** argv)41*33f37583SAndroid Build Coastguard Worker int HandleSubcommand(int argc, char** argv) {
42*33f37583SAndroid Build Coastguard Worker   if (strcmp("--bootstrap", argv[1]) == 0) {
43*33f37583SAndroid Build Coastguard Worker     SetDefaultTag("apexd-bootstrap");
44*33f37583SAndroid Build Coastguard Worker     return android::apex::OnBootstrap();
45*33f37583SAndroid Build Coastguard Worker   }
46*33f37583SAndroid Build Coastguard Worker 
47*33f37583SAndroid Build Coastguard Worker   if (strcmp("--unmount-all", argv[1]) == 0) {
48*33f37583SAndroid Build Coastguard Worker     SetDefaultTag("apexd-unmount-all");
49*33f37583SAndroid Build Coastguard Worker     bool also_include_staged_apexes =
50*33f37583SAndroid Build Coastguard Worker         argc >= 3 && strcmp("--also-include-staged-apexes", argv[2]) == 0;
51*33f37583SAndroid Build Coastguard Worker     std::unique_ptr<android::apex::ApexSessionManager> session_manager;
52*33f37583SAndroid Build Coastguard Worker     if (also_include_staged_apexes) {
53*33f37583SAndroid Build Coastguard Worker       session_manager = android::apex::ApexSessionManager::Create(
54*33f37583SAndroid Build Coastguard Worker           android::apex::GetSessionsDir());
55*33f37583SAndroid Build Coastguard Worker       android::apex::InitializeSessionManager(session_manager.get());
56*33f37583SAndroid Build Coastguard Worker     }
57*33f37583SAndroid Build Coastguard Worker     return android::apex::UnmountAll(also_include_staged_apexes);
58*33f37583SAndroid Build Coastguard Worker   }
59*33f37583SAndroid Build Coastguard Worker 
60*33f37583SAndroid Build Coastguard Worker   if (strcmp("--otachroot-bootstrap", argv[1]) == 0) {
61*33f37583SAndroid Build Coastguard Worker     SetDefaultTag("apexd-otachroot");
62*33f37583SAndroid Build Coastguard Worker     bool also_include_staged_apexes =
63*33f37583SAndroid Build Coastguard Worker         argc >= 3 && strcmp("--also-include-staged-apexes", argv[2]) == 0;
64*33f37583SAndroid Build Coastguard Worker     std::unique_ptr<android::apex::ApexSessionManager> session_manager;
65*33f37583SAndroid Build Coastguard Worker     if (also_include_staged_apexes) {
66*33f37583SAndroid Build Coastguard Worker       session_manager = android::apex::ApexSessionManager::Create(
67*33f37583SAndroid Build Coastguard Worker           android::apex::GetSessionsDir());
68*33f37583SAndroid Build Coastguard Worker       android::apex::InitializeSessionManager(session_manager.get());
69*33f37583SAndroid Build Coastguard Worker     }
70*33f37583SAndroid Build Coastguard Worker     return android::apex::OnOtaChrootBootstrap(also_include_staged_apexes);
71*33f37583SAndroid Build Coastguard Worker   }
72*33f37583SAndroid Build Coastguard Worker 
73*33f37583SAndroid Build Coastguard Worker   if (strcmp("--snapshotde", argv[1]) == 0) {
74*33f37583SAndroid Build Coastguard Worker     SetDefaultTag("apexd-snapshotde");
75*33f37583SAndroid Build Coastguard Worker     // Need to know if checkpointing is enabled so that a prerestore snapshot
76*33f37583SAndroid Build Coastguard Worker     // can be taken if it's not.
77*33f37583SAndroid Build Coastguard Worker     android::base::Result<android::apex::VoldCheckpointInterface>
78*33f37583SAndroid Build Coastguard Worker         vold_service_st = android::apex::VoldCheckpointInterface::Create();
79*33f37583SAndroid Build Coastguard Worker     if (!vold_service_st.ok()) {
80*33f37583SAndroid Build Coastguard Worker       LOG(ERROR) << "Could not retrieve vold service: "
81*33f37583SAndroid Build Coastguard Worker                  << vold_service_st.error();
82*33f37583SAndroid Build Coastguard Worker     } else {
83*33f37583SAndroid Build Coastguard Worker       android::apex::InitializeVold(&*vold_service_st);
84*33f37583SAndroid Build Coastguard Worker     }
85*33f37583SAndroid Build Coastguard Worker 
86*33f37583SAndroid Build Coastguard Worker     // We are running regular apexd, which starts after /metadata/apex/sessions
87*33f37583SAndroid Build Coastguard Worker     // and /data/apex/sessions have been created by init. It is safe to create
88*33f37583SAndroid Build Coastguard Worker     // ApexSessionManager.
89*33f37583SAndroid Build Coastguard Worker     auto session_manager = android::apex::ApexSessionManager::Create(
90*33f37583SAndroid Build Coastguard Worker         android::apex::GetSessionsDir());
91*33f37583SAndroid Build Coastguard Worker     android::apex::InitializeSessionManager(session_manager.get());
92*33f37583SAndroid Build Coastguard Worker 
93*33f37583SAndroid Build Coastguard Worker     int result = android::apex::SnapshotOrRestoreDeUserData();
94*33f37583SAndroid Build Coastguard Worker 
95*33f37583SAndroid Build Coastguard Worker     if (result == 0) {
96*33f37583SAndroid Build Coastguard Worker       // Notify other components (e.g. init) that all APEXs are ready to be used
97*33f37583SAndroid Build Coastguard Worker       // Note that it's important that the binder service is registered at this
98*33f37583SAndroid Build Coastguard Worker       // point, since other system services might depend on it.
99*33f37583SAndroid Build Coastguard Worker       android::apex::OnAllPackagesReady();
100*33f37583SAndroid Build Coastguard Worker     }
101*33f37583SAndroid Build Coastguard Worker     return result;
102*33f37583SAndroid Build Coastguard Worker   }
103*33f37583SAndroid Build Coastguard Worker 
104*33f37583SAndroid Build Coastguard Worker   if (strcmp("--vm", argv[1]) == 0) {
105*33f37583SAndroid Build Coastguard Worker     SetDefaultTag("apexd-vm");
106*33f37583SAndroid Build Coastguard Worker     return android::apex::OnStartInVmMode();
107*33f37583SAndroid Build Coastguard Worker   }
108*33f37583SAndroid Build Coastguard Worker 
109*33f37583SAndroid Build Coastguard Worker   LOG(ERROR) << "Unknown subcommand: " << argv[1];
110*33f37583SAndroid Build Coastguard Worker   return 1;
111*33f37583SAndroid Build Coastguard Worker }
112*33f37583SAndroid Build Coastguard Worker 
InstallSigtermSignalHandler()113*33f37583SAndroid Build Coastguard Worker void InstallSigtermSignalHandler() {
114*33f37583SAndroid Build Coastguard Worker   struct sigaction action = {};
115*33f37583SAndroid Build Coastguard Worker   action.sa_handler = [](int /*signal*/) {
116*33f37583SAndroid Build Coastguard Worker     // Handle SIGTERM gracefully.
117*33f37583SAndroid Build Coastguard Worker     // By default, when SIGTERM is received a process will exit with non-zero
118*33f37583SAndroid Build Coastguard Worker     // exit code, which will trigger reboot_on_failure handler if one is
119*33f37583SAndroid Build Coastguard Worker     // defined. This doesn't play well with userspace reboot which might
120*33f37583SAndroid Build Coastguard Worker     // terminate apexd with SIGTERM if apexd was running at the moment of
121*33f37583SAndroid Build Coastguard Worker     // userspace reboot, hence this custom handler to exit gracefully.
122*33f37583SAndroid Build Coastguard Worker     _exit(0);
123*33f37583SAndroid Build Coastguard Worker   };
124*33f37583SAndroid Build Coastguard Worker   sigaction(SIGTERM, &action, nullptr);
125*33f37583SAndroid Build Coastguard Worker }
126*33f37583SAndroid Build Coastguard Worker 
InstallSelinuxLogging()127*33f37583SAndroid Build Coastguard Worker void InstallSelinuxLogging() {
128*33f37583SAndroid Build Coastguard Worker   union selinux_callback cb;
129*33f37583SAndroid Build Coastguard Worker   cb.func_log = selinux_log_callback;
130*33f37583SAndroid Build Coastguard Worker   selinux_set_callback(SELINUX_CB_LOG, cb);
131*33f37583SAndroid Build Coastguard Worker }
132*33f37583SAndroid Build Coastguard Worker 
133*33f37583SAndroid Build Coastguard Worker }  // namespace
134*33f37583SAndroid Build Coastguard Worker 
main(int argc,char ** argv)135*33f37583SAndroid Build Coastguard Worker int main(int argc, char** argv) {
136*33f37583SAndroid Build Coastguard Worker   android::base::InitLogging(argv, &android::base::KernelLogger);
137*33f37583SAndroid Build Coastguard Worker   // TODO(b/158468454): add a -v flag or an external setting to change severity.
138*33f37583SAndroid Build Coastguard Worker   android::base::SetMinimumLogSeverity(android::base::INFO);
139*33f37583SAndroid Build Coastguard Worker 
140*33f37583SAndroid Build Coastguard Worker   // Two flags are used here:
141*33f37583SAndroid Build Coastguard Worker   // CLI flag `--enable-brand-new-apex`: used to control the feature usage in
142*33f37583SAndroid Build Coastguard Worker   // individual targets
143*33f37583SAndroid Build Coastguard Worker   // AConfig flag `enable_brand_new_apex`: used to advance
144*33f37583SAndroid Build Coastguard Worker   // the feature to different release stages, and applies to all targets
145*33f37583SAndroid Build Coastguard Worker   if (flags::enable_brand_new_apex()) {
146*33f37583SAndroid Build Coastguard Worker     if (argv[1] != nullptr && strcmp("--enable-brand-new-apex", argv[1]) == 0) {
147*33f37583SAndroid Build Coastguard Worker       android::apex::ApexFileRepository::EnableBrandNewApex();
148*33f37583SAndroid Build Coastguard Worker       argc--;
149*33f37583SAndroid Build Coastguard Worker       argv++;
150*33f37583SAndroid Build Coastguard Worker     }
151*33f37583SAndroid Build Coastguard Worker   }
152*33f37583SAndroid Build Coastguard Worker 
153*33f37583SAndroid Build Coastguard Worker   const bool has_subcommand = argv[1] != nullptr;
154*33f37583SAndroid Build Coastguard Worker   LOG(INFO) << "Started. subcommand = "
155*33f37583SAndroid Build Coastguard Worker             << (has_subcommand ? argv[1] : "(null)");
156*33f37583SAndroid Build Coastguard Worker 
157*33f37583SAndroid Build Coastguard Worker   // set umask to 022 so that files/dirs created are accessible to other
158*33f37583SAndroid Build Coastguard Worker   // processes e.g.) /apex/apex-info-list.xml is supposed to be read by other
159*33f37583SAndroid Build Coastguard Worker   // processes
160*33f37583SAndroid Build Coastguard Worker   umask(022);
161*33f37583SAndroid Build Coastguard Worker 
162*33f37583SAndroid Build Coastguard Worker   // In some scenarios apexd needs to adjust the selinux label of the files.
163*33f37583SAndroid Build Coastguard Worker   // Install the selinux logging callback so that we can catch potential errors.
164*33f37583SAndroid Build Coastguard Worker   InstallSelinuxLogging();
165*33f37583SAndroid Build Coastguard Worker 
166*33f37583SAndroid Build Coastguard Worker   InstallSigtermSignalHandler();
167*33f37583SAndroid Build Coastguard Worker 
168*33f37583SAndroid Build Coastguard Worker   android::apex::SetConfig(android::apex::kDefaultConfig);
169*33f37583SAndroid Build Coastguard Worker 
170*33f37583SAndroid Build Coastguard Worker   android::apex::ApexdLifecycle& lifecycle =
171*33f37583SAndroid Build Coastguard Worker       android::apex::ApexdLifecycle::GetInstance();
172*33f37583SAndroid Build Coastguard Worker   bool booting = lifecycle.IsBooting();
173*33f37583SAndroid Build Coastguard Worker 
174*33f37583SAndroid Build Coastguard Worker   if (has_subcommand) {
175*33f37583SAndroid Build Coastguard Worker     return HandleSubcommand(argc, argv);
176*33f37583SAndroid Build Coastguard Worker   }
177*33f37583SAndroid Build Coastguard Worker 
178*33f37583SAndroid Build Coastguard Worker   // We are running regular apexd, which starts after /metadata/apex/sessions
179*33f37583SAndroid Build Coastguard Worker   // and /data/apex/sessions have been created by init. It is safe to create
180*33f37583SAndroid Build Coastguard Worker   // ApexSessionManager.
181*33f37583SAndroid Build Coastguard Worker   auto session_manager = android::apex::ApexSessionManager::Create(
182*33f37583SAndroid Build Coastguard Worker       android::apex::GetSessionsDir());
183*33f37583SAndroid Build Coastguard Worker   android::apex::InitializeSessionManager(session_manager.get());
184*33f37583SAndroid Build Coastguard Worker 
185*33f37583SAndroid Build Coastguard Worker   android::base::Result<android::apex::VoldCheckpointInterface>
186*33f37583SAndroid Build Coastguard Worker       vold_service_st = android::apex::VoldCheckpointInterface::Create();
187*33f37583SAndroid Build Coastguard Worker   android::apex::VoldCheckpointInterface* vold_service = nullptr;
188*33f37583SAndroid Build Coastguard Worker   if (!vold_service_st.ok()) {
189*33f37583SAndroid Build Coastguard Worker     LOG(ERROR) << "Could not retrieve vold service: "
190*33f37583SAndroid Build Coastguard Worker                << vold_service_st.error();
191*33f37583SAndroid Build Coastguard Worker   } else {
192*33f37583SAndroid Build Coastguard Worker     vold_service = &*vold_service_st;
193*33f37583SAndroid Build Coastguard Worker   }
194*33f37583SAndroid Build Coastguard Worker   android::apex::Initialize(vold_service);
195*33f37583SAndroid Build Coastguard Worker   android::apex::InitMetrics(std::make_unique<android::apex::StatsLog>());
196*33f37583SAndroid Build Coastguard Worker 
197*33f37583SAndroid Build Coastguard Worker   if (booting) {
198*33f37583SAndroid Build Coastguard Worker     auto res = session_manager->MigrateFromOldSessionsDir(
199*33f37583SAndroid Build Coastguard Worker         android::apex::kOldApexSessionsDir);
200*33f37583SAndroid Build Coastguard Worker     if (!res.ok()) {
201*33f37583SAndroid Build Coastguard Worker       LOG(ERROR) << "Failed to migrate sessions to /metadata partition : "
202*33f37583SAndroid Build Coastguard Worker                  << res.error();
203*33f37583SAndroid Build Coastguard Worker     }
204*33f37583SAndroid Build Coastguard Worker     android::apex::OnStart();
205*33f37583SAndroid Build Coastguard Worker   } else {
206*33f37583SAndroid Build Coastguard Worker     // TODO(b/172911822): Trying to use data apex related ApexFileRepository
207*33f37583SAndroid Build Coastguard Worker     //  apis without initializing it should throw error. Also, unit tests should
208*33f37583SAndroid Build Coastguard Worker     //  not pass without initialization.
209*33f37583SAndroid Build Coastguard Worker     // TODO(b/172911822): Consolidate this with Initialize() when
210*33f37583SAndroid Build Coastguard Worker     //  ApexFileRepository can act as cache and re-scanning is not expensive
211*33f37583SAndroid Build Coastguard Worker     android::apex::InitializeDataApex();
212*33f37583SAndroid Build Coastguard Worker   }
213*33f37583SAndroid Build Coastguard Worker   // start apexservice before ApexdLifecycle::WaitForBootStatus which waits for
214*33f37583SAndroid Build Coastguard Worker   // IApexService::markBootComplete().
215*33f37583SAndroid Build Coastguard Worker   android::apex::binder::CreateAndRegisterService();
216*33f37583SAndroid Build Coastguard Worker   android::apex::binder::StartThreadPool();
217*33f37583SAndroid Build Coastguard Worker 
218*33f37583SAndroid Build Coastguard Worker   if (booting) {
219*33f37583SAndroid Build Coastguard Worker     // Notify other components (e.g. init) that all APEXs are correctly mounted
220*33f37583SAndroid Build Coastguard Worker     // and activated (but are not yet ready to be used). Configuration based on
221*33f37583SAndroid Build Coastguard Worker     // activated APEXs may be performed at this point, but use of APEXs
222*33f37583SAndroid Build Coastguard Worker     // themselves should wait for the ready status instead, which is set when
223*33f37583SAndroid Build Coastguard Worker     // the "--snapshotde" subcommand is received and snapshot/restore is
224*33f37583SAndroid Build Coastguard Worker     // complete.
225*33f37583SAndroid Build Coastguard Worker     android::apex::OnAllPackagesActivated(/*is_bootstrap=*/false);
226*33f37583SAndroid Build Coastguard Worker     lifecycle.WaitForBootStatus(session_manager->HasActiveSession());
227*33f37583SAndroid Build Coastguard Worker     // Run cleanup routine on boot complete.
228*33f37583SAndroid Build Coastguard Worker     // This should run before AllowServiceShutdown() to prevent
229*33f37583SAndroid Build Coastguard Worker     // service_manager killing apexd in the middle of the cleanup.
230*33f37583SAndroid Build Coastguard Worker     android::apex::BootCompletedCleanup();
231*33f37583SAndroid Build Coastguard Worker   }
232*33f37583SAndroid Build Coastguard Worker 
233*33f37583SAndroid Build Coastguard Worker   android::apex::binder::AllowServiceShutdown();
234*33f37583SAndroid Build Coastguard Worker 
235*33f37583SAndroid Build Coastguard Worker   android::apex::binder::JoinThreadPool();
236*33f37583SAndroid Build Coastguard Worker   return 1;
237*33f37583SAndroid Build Coastguard Worker }
238