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