• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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