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 #include "first_stage_init.h"
18 
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <paths.h>
22 #include <stdlib.h>
23 #include <sys/mount.h>
24 #include <sys/stat.h>
25 #include <sys/sysmacros.h>
26 #include <sys/types.h>
27 #include <sys/utsname.h>
28 #include <unistd.h>
29 
30 #include <chrono>
31 #include <filesystem>
32 #include <string>
33 #include <thread>
34 #include <vector>
35 
36 #include <android-base/chrono_utils.h>
37 #include <android-base/file.h>
38 #include <android-base/logging.h>
39 #include <android-base/stringprintf.h>
40 #include <android/avf_cc_flags.h>
41 #include <modprobe/modprobe.h>
42 #include <private/android_filesystem_config.h>
43 
44 #include "debug_ramdisk.h"
45 #include "first_stage_console.h"
46 #include "first_stage_mount.h"
47 #include "reboot_utils.h"
48 #include "second_stage_resources.h"
49 #include "snapuserd_transition.h"
50 #include "switch_root.h"
51 #include "util.h"
52 
53 using android::base::boot_clock;
54 
55 using namespace std::literals;
56 
57 namespace fs = std::filesystem;
58 
59 namespace android {
60 namespace init {
61 
62 namespace {
63 
64 enum class BootMode {
65     NORMAL_MODE,
66     RECOVERY_MODE,
67     CHARGER_MODE,
68 };
69 
FreeRamdisk(DIR * dir,dev_t dev)70 void FreeRamdisk(DIR* dir, dev_t dev) {
71     int dfd = dirfd(dir);
72 
73     dirent* de = nullptr;
74     while ((de = readdir(dir)) != nullptr) {
75         if (de->d_name == "."s || de->d_name == ".."s) {
76             continue;
77         }
78 
79         bool is_dir = false;
80 
81         if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
82             struct stat info {};
83             if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
84                 continue;
85             }
86 
87             if (info.st_dev != dev) {
88                 continue;
89             }
90 
91             if (S_ISDIR(info.st_mode)) {
92                 is_dir = true;
93                 auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
94                 if (fd >= 0) {
95                     auto subdir =
96                             std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
97                     if (subdir) {
98                         FreeRamdisk(subdir.get(), dev);
99                     } else {
100                         close(fd);
101                     }
102                 }
103             }
104         } else if (de->d_type == DT_REG) {
105             // Do not free snapuserd if we will need the ramdisk copy during the
106             // selinux transition.
107             if (de->d_name == "snapuserd"s && IsFirstStageSnapuserdRunning()) {
108                 continue;
109             }
110         }
111         unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
112     }
113 }
114 
ForceNormalBoot(const std::string & cmdline,const std::string & bootconfig)115 bool ForceNormalBoot(const std::string& cmdline, const std::string& bootconfig) {
116     return bootconfig.find("androidboot.force_normal_boot = \"1\"") != std::string::npos ||
117            cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
118 }
119 
Copy(const char * src,const char * dst)120 static void Copy(const char* src, const char* dst) {
121     if (link(src, dst) == 0) {
122         LOG(INFO) << "hard linking " << src << " to " << dst << " succeeded";
123         return;
124     }
125     PLOG(FATAL) << "hard linking " << src << " to " << dst << " failed";
126 }
127 
128 // Move snapuserd before switching root, so that it is available at the same path
129 // after switching root.
PrepareSwitchRoot()130 void PrepareSwitchRoot() {
131     static constexpr const auto& snapuserd = "/system/bin/snapuserd";
132     static constexpr const auto& snapuserd_ramdisk = "/system/bin/snapuserd_ramdisk";
133     static constexpr const auto& dst = "/first_stage_ramdisk/system/bin/snapuserd";
134 
135     if (access(dst, X_OK) == 0) {
136         LOG(INFO) << dst << " already exists and it can be executed";
137         return;
138     }
139     auto dst_dir = android::base::Dirname(dst);
140     std::error_code ec;
141     if (access(dst_dir.c_str(), F_OK) != 0) {
142         if (!fs::create_directories(dst_dir, ec)) {
143             LOG(FATAL) << "Cannot create " << dst_dir << ": " << ec.message();
144         }
145     }
146 
147     // prefer the generic ramdisk copy of snapuserd, because that's on system side of treble
148     // boundary, and therefore is more likely to be updated along with the Android platform.
149     // The vendor ramdisk copy might be under vendor freeze, or vendor might choose not to update
150     // it.
151     if (access(snapuserd_ramdisk, F_OK) == 0) {
152         LOG(INFO) << "Using generic ramdisk copy of snapuserd " << snapuserd_ramdisk;
153         Copy(snapuserd_ramdisk, dst);
154     } else if (access(snapuserd, F_OK) == 0) {
155         LOG(INFO) << "Using vendor ramdisk copy of snapuserd " << snapuserd;
156         Copy(snapuserd, dst);
157     }
158 }
159 
GetPageSizeSuffix()160 std::string GetPageSizeSuffix() {
161     static const size_t page_size = sysconf(_SC_PAGE_SIZE);
162     if (page_size <= 4096) {
163         return "";
164     }
165     return android::base::StringPrintf("_%zuk", page_size / 1024);
166 }
167 
EndsWith(const std::string_view str,const std::string_view suffix)168 constexpr bool EndsWith(const std::string_view str, const std::string_view suffix) {
169     return str.size() >= suffix.size() &&
170            0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
171 }
172 
GetPageSizeSuffix(std::string_view dirname)173 constexpr std::string_view GetPageSizeSuffix(std::string_view dirname) {
174     if (EndsWith(dirname, "_16k")) {
175         return "_16k";
176     }
177     if (EndsWith(dirname, "_64k")) {
178         return "_64k";
179     }
180     return "";
181 }
182 
183 }  // namespace
184 
GetModuleLoadList(BootMode boot_mode,const std::string & dir_path)185 std::string GetModuleLoadList(BootMode boot_mode, const std::string& dir_path) {
186     std::string module_load_file;
187 
188     switch (boot_mode) {
189         case BootMode::NORMAL_MODE:
190             module_load_file = "modules.load";
191             break;
192         case BootMode::RECOVERY_MODE:
193             module_load_file = "modules.load.recovery";
194             break;
195         case BootMode::CHARGER_MODE:
196             module_load_file = "modules.load.charger";
197             break;
198     }
199 
200     if (module_load_file != "modules.load") {
201         struct stat fileStat {};
202         std::string load_path = dir_path + "/" + module_load_file;
203         // Fall back to modules.load if the other files aren't accessible
204         if (stat(load_path.c_str(), &fileStat)) {
205             module_load_file = "modules.load";
206         }
207     }
208 
209     return module_load_file;
210 }
211 
212 #define MODULE_BASE_DIR "/lib/modules"
LoadKernelModules(BootMode boot_mode,bool want_console,bool want_parallel,int & modules_loaded)213 bool LoadKernelModules(BootMode boot_mode, bool want_console, bool want_parallel,
214                        int& modules_loaded) {
215     struct utsname uts {};
216     if (uname(&uts)) {
217         LOG(FATAL) << "Failed to get kernel version.";
218     }
219     int major = 0, minor = 0;
220     if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
221         LOG(FATAL) << "Failed to parse kernel version " << uts.release;
222     }
223 
224     std::unique_ptr<DIR, decltype(&closedir)> base_dir(opendir(MODULE_BASE_DIR), closedir);
225     if (!base_dir) {
226         LOG(INFO) << "Unable to open /lib/modules, skipping module loading.";
227         return true;
228     }
229     dirent* entry = nullptr;
230     std::vector<std::string> module_dirs;
231     const auto page_size_suffix = GetPageSizeSuffix();
232     const std::string release_specific_module_dir = uts.release + page_size_suffix;
233     while ((entry = readdir(base_dir.get()))) {
234         if (entry->d_type != DT_DIR) {
235             continue;
236         }
237         if (entry->d_name == release_specific_module_dir) {
238             LOG(INFO) << "Release specific kernel module dir " << release_specific_module_dir
239                       << " found, loading modules from here with no fallbacks.";
240             module_dirs.clear();
241             module_dirs.emplace_back(entry->d_name);
242             break;
243         }
244         // Is a directory does not have page size suffix, it does not mean this directory is for 4K
245         // kernels. Certain 16K kernel builds put all modules in /lib/modules/`uname -r` without any
246         // suffix. Therefore, only ignore a directory if it has _16k/_64k suffix and the suffix does
247         // not match system page size.
248         const auto dir_page_size_suffix = GetPageSizeSuffix(entry->d_name);
249         if (!dir_page_size_suffix.empty() && dir_page_size_suffix != page_size_suffix) {
250             continue;
251         }
252         int dir_major = 0, dir_minor = 0;
253         if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major ||
254             dir_minor != minor) {
255             continue;
256         }
257         module_dirs.emplace_back(entry->d_name);
258     }
259 
260     // Sort the directories so they are iterated over during module loading
261     // in a consistent order. Alphabetical sorting is fine here because the
262     // kernel version at the beginning of the directory name must match the
263     // current kernel version, so the sort only applies to a label that
264     // follows the kernel version, for example /lib/modules/5.4 vs.
265     // /lib/modules/5.4-gki.
266     std::sort(module_dirs.begin(), module_dirs.end());
267 
268     for (const auto& module_dir : module_dirs) {
269         std::string dir_path = MODULE_BASE_DIR "/";
270         dir_path.append(module_dir);
271         Modprobe m({dir_path}, GetModuleLoadList(boot_mode, dir_path));
272         bool retval = m.LoadListedModules(!want_console);
273         modules_loaded = m.GetModuleCount();
274         if (modules_loaded > 0) {
275             LOG(INFO) << "Loaded " << modules_loaded << " modules from " << dir_path;
276             return retval;
277         }
278     }
279 
280     Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(boot_mode, MODULE_BASE_DIR));
281     bool retval = (want_parallel) ? m.LoadModulesParallel(std::thread::hardware_concurrency())
282                                   : m.LoadListedModules(!want_console);
283     modules_loaded = m.GetModuleCount();
284     if (modules_loaded > 0) {
285         LOG(INFO) << "Loaded " << modules_loaded << " modules from " << MODULE_BASE_DIR;
286         return retval;
287     }
288     return true;
289 }
290 
IsChargerMode(const std::string & cmdline,const std::string & bootconfig)291 static bool IsChargerMode(const std::string& cmdline, const std::string& bootconfig) {
292     return bootconfig.find("androidboot.mode = \"charger\"") != std::string::npos ||
293             cmdline.find("androidboot.mode=charger") != std::string::npos;
294 }
295 
GetBootMode(const std::string & cmdline,const std::string & bootconfig)296 static BootMode GetBootMode(const std::string& cmdline, const std::string& bootconfig)
297 {
298     if (IsChargerMode(cmdline, bootconfig))
299         return BootMode::CHARGER_MODE;
300     else if (IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig))
301         return BootMode::RECOVERY_MODE;
302 
303     return BootMode::NORMAL_MODE;
304 }
305 
CreateFirstStageMount(const std::string & cmdline)306 static std::unique_ptr<FirstStageMount> CreateFirstStageMount(const std::string& cmdline) {
307     auto ret = FirstStageMount::Create(cmdline);
308     if (ret.ok()) {
309         return std::move(*ret);
310     } else {
311         LOG(ERROR) << "Failed to create FirstStageMount : " << ret.error();
312         return nullptr;
313     }
314 }
315 
FirstStageMain(int argc,char ** argv)316 int FirstStageMain(int argc, char** argv) {
317     if (REBOOT_BOOTLOADER_ON_PANIC) {
318         InstallRebootSignalHandlers();
319     }
320 
321     boot_clock::time_point start_time = boot_clock::now();
322 
323     std::vector<std::pair<std::string, int>> errors;
324 #define CHECKCALL(x) \
325     if ((x) != 0) errors.emplace_back(#x " failed", errno);
326 
327     // Clear the umask.
328     umask(0);
329 
330     CHECKCALL(clearenv());
331     CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
332     // Get the basic filesystem setup we need put together in the initramdisk
333     // on / and then we'll let the rc file figure out the rest.
334     CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
335     CHECKCALL(mkdir("/dev/pts", 0755));
336     CHECKCALL(mkdir("/dev/socket", 0755));
337     CHECKCALL(mkdir("/dev/dm-user", 0755));
338     CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
339 #define MAKE_STR(x) __STRING(x)
340     CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)));
341 #undef MAKE_STR
342     // Don't expose the raw commandline to unprivileged processes.
343     CHECKCALL(chmod("/proc/cmdline", 0440));
344     std::string cmdline;
345     android::base::ReadFileToString("/proc/cmdline", &cmdline);
346     // Don't expose the raw bootconfig to unprivileged processes.
347     chmod("/proc/bootconfig", 0440);
348     std::string bootconfig;
349     android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
350     gid_t groups[] = {AID_READPROC};
351     CHECKCALL(setgroups(arraysize(groups), groups));
352     CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL));
353     CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL));
354 
355     CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11)));
356 
357     if constexpr (WORLD_WRITABLE_KMSG) {
358         CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11)));
359     }
360 
361     CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8)));
362     CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9)));
363 
364     // This is needed for log wrapper, which gets called before ueventd runs.
365     CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
366     CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
367 
368     // These below mounts are done in first stage init so that first stage mount can mount
369     // subdirectories of /mnt/{vendor,product}/.  Other mounts, not required by first stage mount,
370     // should be done in rc files.
371     // Mount staging areas for devices managed by vold
372     // See storage config details at http://source.android.com/devices/storage/
373     CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
374                     "mode=0755,uid=0,gid=1000"));
375     // /mnt/vendor is used to mount vendor-specific partitions that can not be
376     // part of the vendor partition, e.g. because they are mounted read-write.
377     CHECKCALL(mkdir("/mnt/vendor", 0755));
378     // /mnt/product is used to mount product-specific partitions that can not be
379     // part of the product partition, e.g. because they are mounted read-write.
380     CHECKCALL(mkdir("/mnt/product", 0755));
381 
382     // /debug_ramdisk is used to preserve additional files from the debug ramdisk
383     CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
384                     "mode=0755,uid=0,gid=0"));
385 
386     // /second_stage_resources is used to preserve files from first to second
387     // stage init
388     CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
389                     "mode=0755,uid=0,gid=0"));
390 
391     if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
392         CHECKCALL(mount("tmpfs", "/microdroid_resources", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
393                         "mode=0750,uid=0,gid=0"));
394     }
395 #undef CHECKCALL
396 
397     SetStdioToDevNull(argv);
398     // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
399     // talk to the outside world...
400     InitKernelLogging(argv);
401 
402     if (!errors.empty()) {
403         for (const auto& [error_string, error_errno] : errors) {
404             LOG(ERROR) << error_string << " " << strerror(error_errno);
405         }
406         LOG(FATAL) << "Init encountered errors starting first stage, aborting";
407     }
408 
409     LOG(INFO) << "init first stage started!";
410 
411     auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
412     if (!old_root_dir) {
413         PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
414     }
415 
416     struct stat old_root_info {};
417     if (stat("/", &old_root_info) != 0) {
418         PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
419         old_root_dir.reset();
420     }
421 
422     auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0;
423     auto want_parallel =
424             bootconfig.find("androidboot.load_modules_parallel = \"true\"") != std::string::npos;
425 
426     boot_clock::time_point module_start_time = boot_clock::now();
427     int module_count = 0;
428     BootMode boot_mode = GetBootMode(cmdline, bootconfig);
429     if (!LoadKernelModules(boot_mode, want_console,
430                            want_parallel, module_count)) {
431         if (want_console != FirstStageConsoleParam::DISABLED) {
432             LOG(ERROR) << "Failed to load kernel modules, starting console";
433         } else {
434             LOG(FATAL) << "Failed to load kernel modules";
435         }
436     }
437     if (module_count > 0) {
438         auto module_elapse_time = std::chrono::duration_cast<std::chrono::milliseconds>(
439                 boot_clock::now() - module_start_time);
440         setenv(kEnvInitModuleDurationMs, std::to_string(module_elapse_time.count()).c_str(), 1);
441         LOG(INFO) << "Loaded " << module_count << " kernel modules took "
442                   << module_elapse_time.count() << " ms";
443     }
444 
445     std::unique_ptr<FirstStageMount> fsm;
446 
447     bool created_devices = false;
448     if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
449         if (!IsRecoveryMode()) {
450             fsm = CreateFirstStageMount(cmdline);
451             if (fsm) {
452                 created_devices = fsm->DoCreateDevices();
453                 if (!created_devices) {
454                     LOG(ERROR) << "Failed to create device nodes early";
455                 }
456             }
457         }
458         StartConsole(cmdline);
459     }
460 
461     if (access(kBootImageRamdiskProp, F_OK) == 0) {
462         std::string dest = GetRamdiskPropForSecondStage();
463         std::string dir = android::base::Dirname(dest);
464         std::error_code ec;
465         if (!fs::create_directories(dir, ec) && !!ec) {
466             LOG(FATAL) << "Can't mkdir " << dir << ": " << ec.message();
467         }
468         if (!fs::copy_file(kBootImageRamdiskProp, dest, ec)) {
469             LOG(FATAL) << "Can't copy " << kBootImageRamdiskProp << " to " << dest << ": "
470                        << ec.message();
471         }
472         LOG(INFO) << "Copied ramdisk prop to " << dest;
473     }
474 
475     // If "/force_debuggable" is present, the second-stage init will use a userdebug
476     // sepolicy and load adb_debug.prop to allow adb root, if the device is unlocked.
477     if (access("/force_debuggable", F_OK) == 0) {
478         constexpr const char adb_debug_prop_src[] = "/adb_debug.prop";
479         constexpr const char userdebug_plat_sepolicy_cil_src[] = "/userdebug_plat_sepolicy.cil";
480         std::error_code ec;  // to invoke the overloaded copy_file() that won't throw.
481         if (access(adb_debug_prop_src, F_OK) == 0 &&
482             !fs::copy_file(adb_debug_prop_src, kDebugRamdiskProp, ec)) {
483             LOG(WARNING) << "Can't copy " << adb_debug_prop_src << " to " << kDebugRamdiskProp
484                          << ": " << ec.message();
485         }
486         if (access(userdebug_plat_sepolicy_cil_src, F_OK) == 0 &&
487             !fs::copy_file(userdebug_plat_sepolicy_cil_src, kDebugRamdiskSEPolicy, ec)) {
488             LOG(WARNING) << "Can't copy " << userdebug_plat_sepolicy_cil_src << " to "
489                          << kDebugRamdiskSEPolicy << ": " << ec.message();
490         }
491         // setenv for second-stage init to read above kDebugRamdisk* files.
492         setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
493     }
494 
495     if (ForceNormalBoot(cmdline, bootconfig)) {
496         mkdir("/first_stage_ramdisk", 0755);
497         PrepareSwitchRoot();
498         // SwitchRoot() must be called with a mount point as the target, so we bind mount the
499         // target directory to itself here.
500         if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
501             PLOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
502         }
503         SwitchRoot("/first_stage_ramdisk");
504     }
505 
506     if (IsRecoveryMode()) {
507         LOG(INFO) << "First stage mount skipped (recovery mode)";
508     } else {
509         if (!fsm) {
510             fsm = CreateFirstStageMount(cmdline);
511         }
512         if (!fsm) {
513             LOG(FATAL) << "FirstStageMount not available";
514         }
515 
516         if (!created_devices && !fsm->DoCreateDevices()) {
517             LOG(FATAL) << "Failed to create devices required for first stage mount";
518         }
519 
520         if (!fsm->DoFirstStageMount()) {
521             LOG(FATAL) << "Failed to mount required partitions early ...";
522         }
523     }
524 
525     struct stat new_root_info {};
526     if (stat("/", &new_root_info) != 0) {
527         PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
528         old_root_dir.reset();
529     }
530 
531     if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
532         FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
533     }
534 
535     SetInitAvbVersionInRecovery();
536 
537     setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(),
538            1);
539 
540     const char* path = "/system/bin/init";
541     const char* args[] = {path, "selinux_setup", nullptr};
542     auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
543     dup2(fd, STDOUT_FILENO);
544     dup2(fd, STDERR_FILENO);
545     close(fd);
546     execv(path, const_cast<char**>(args));
547 
548     // execv() only returns if an error happened, in which case we
549     // panic and never fall through this conditional.
550     PLOG(FATAL) << "execv(\"" << path << "\") failed";
551 
552     return 1;
553 }
554 
555 }  // namespace init
556 }  // namespace android
557