• 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 
21 #include <ApexProperties.sysprop.h>
22 #include <android-base/logging.h>
23 
24 #include "apexd.h"
25 #include "apexd_checkpoint_vold.h"
26 #include "apexd_prepostinstall.h"
27 #include "apexd_prop.h"
28 #include "apexservice.h"
29 
30 #include <android-base/properties.h>
31 
32 namespace {
33 
HandleSubcommand(char ** argv)34 int HandleSubcommand(char** argv) {
35   if (strcmp("--pre-install", argv[1]) == 0) {
36     LOG(INFO) << "Preinstall subcommand detected";
37     return android::apex::RunPreInstall(argv);
38   }
39 
40   if (strcmp("--post-install", argv[1]) == 0) {
41     LOG(INFO) << "Postinstall subcommand detected";
42     return android::apex::RunPostInstall(argv);
43   }
44 
45   if (strcmp("--bootstrap", argv[1]) == 0) {
46     LOG(INFO) << "Bootstrap subcommand detected";
47     return android::apex::onBootstrap();
48   }
49 
50   if (strcmp("--unmount-all", argv[1]) == 0) {
51     LOG(INFO) << "Unmount all subcommand detected";
52     return android::apex::unmountAll();
53   }
54 
55   if (strcmp("--snapshotde", argv[1]) == 0) {
56     LOG(INFO) << "Snapshot DE subcommand detected";
57     // Need to know if checkpointing is enabled so that a prerestore snapshot
58     // can be taken if it's not.
59     android::base::Result<android::apex::VoldCheckpointInterface>
60         vold_service_st = android::apex::VoldCheckpointInterface::Create();
61     if (!vold_service_st.ok()) {
62       LOG(ERROR) << "Could not retrieve vold service: "
63                  << vold_service_st.error();
64     } else {
65       android::apex::initializeVold(&*vold_service_st);
66     }
67 
68     int result = android::apex::snapshotOrRestoreDeUserData();
69 
70     if (result == 0) {
71       // Notify other components (e.g. init) that all APEXs are ready to be used
72       // Note that it's important that the binder service is registered at this
73       // point, since other system services might depend on it.
74       android::apex::onAllPackagesReady();
75     }
76     return result;
77   }
78 
79   LOG(ERROR) << "Unknown subcommand: " << argv[1];
80   return 1;
81 }
82 
InstallSigtermSignalHandler()83 void InstallSigtermSignalHandler() {
84   struct sigaction action = {};
85   action.sa_handler = [](int /*signal*/) {
86     // Handle SIGTERM gracefully.
87     // By default, when SIGTERM is received a process will exit with non-zero
88     // exit code, which will trigger reboot_on_failure handler if one is
89     // defined. This doesn't play well with userspace reboot which might
90     // terminate apexd with SIGTERM if apexd was running at the moment of
91     // userspace reboot, hence this custom handler to exit gracefully.
92     _exit(0);
93   };
94   sigaction(SIGTERM, &action, nullptr);
95 }
96 
97 }  // namespace
98 
main(int,char ** argv)99 int main(int /*argc*/, char** argv) {
100   android::base::InitLogging(argv, &android::base::KernelLogger);
101   // TODO: add a -v flag or an external setting to change LogSeverity.
102   android::base::SetMinimumLogSeverity(android::base::VERBOSE);
103 
104   InstallSigtermSignalHandler();
105 
106   const bool has_subcommand = argv[1] != nullptr;
107   if (!android::sysprop::ApexProperties::updatable().value_or(false)) {
108     LOG(INFO) << "This device does not support updatable APEX. Exiting";
109     if (!has_subcommand) {
110       // mark apexd as activated so that init can proceed
111       android::apex::onAllPackagesActivated();
112     } else if (strcmp("--snapshotde", argv[1]) == 0) {
113       // mark apexd as ready
114       android::apex::onAllPackagesReady();
115     }
116     return 0;
117   }
118 
119   if (has_subcommand) {
120     return HandleSubcommand(argv);
121   }
122 
123   android::base::Result<android::apex::VoldCheckpointInterface>
124       vold_service_st = android::apex::VoldCheckpointInterface::Create();
125   android::apex::VoldCheckpointInterface* vold_service = nullptr;
126   if (!vold_service_st.ok()) {
127     LOG(ERROR) << "Could not retrieve vold service: "
128                << vold_service_st.error();
129   } else {
130     vold_service = &*vold_service_st;
131   }
132   android::apex::initialize(vold_service);
133 
134   bool booting = android::apex::isBooting();
135   if (booting) {
136     if (auto res = android::apex::migrateSessionsDirIfNeeded(); !res.ok()) {
137       LOG(ERROR) << "Failed to migrate sessions to /metadata partition : "
138                  << res.error();
139     }
140     android::apex::onStart();
141   }
142   android::apex::binder::CreateAndRegisterService();
143   android::apex::binder::StartThreadPool();
144 
145   if (booting) {
146     // Notify other components (e.g. init) that all APEXs are correctly mounted
147     // and activated (but are not yet ready to be used). Configuration based on
148     // activated APEXs may be performed at this point, but use of APEXs
149     // themselves should wait for the ready status instead, which is set when
150     // the "--snapshotde" subcommand is received and snapshot/restore is
151     // complete.
152     android::apex::onAllPackagesActivated();
153     android::apex::waitForBootStatus(
154         android::apex::revertActiveSessionsAndReboot,
155         android::apex::bootCompletedCleanup);
156   }
157 
158   android::apex::binder::AllowServiceShutdown();
159 
160   android::apex::binder::JoinThreadPool();
161   return 1;
162 }
163