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