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