1/*
2** Copyright 2008, 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#define LOG_TAG "installd"
17
18#include <fcntl.h>
19#include <selinux/android.h>
20#include <selinux/avc.h>
21#include <sys/capability.h>
22#include <sys/fsuid.h>
23#include <sys/prctl.h>
24#include <sys/stat.h>
25
26#include <android-base/logging.h>
27#include <cutils/fs.h>
28#include <cutils/properties.h>
29#include <log/log.h>              // TODO: Move everything to base::logging.
30#include <private/android_filesystem_config.h>
31
32#include "InstalldNativeService.h"
33#include "dexopt.h"
34#include "globals.h"
35#include "installd_constants.h"
36#include "installd_deps.h"  // Need to fill in requirements of commands.
37#include "utils.h"
38
39namespace android {
40namespace installd {
41
42// Check that installd-deps sizes match cutils sizes.
43static_assert(kPropertyKeyMax == PROPERTY_KEY_MAX, "Size mismatch.");
44static_assert(kPropertyValueMax == PROPERTY_VALUE_MAX, "Size mismatch.");
45
46////////////////////////
47// Plug-in functions. //
48////////////////////////
49
50int get_property(const char *key, char *value, const char *default_value) {
51    return property_get(key, value, default_value);
52}
53
54bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
55        const char *instruction_set) {
56    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
57}
58
59bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
60        const char *instruction_set) {
61    return calculate_odex_file_path_default(path, apk_path, instruction_set);
62}
63
64bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
65    return create_cache_path_default(path, src, instruction_set);
66}
67
68static bool initialize_globals() {
69    return init_globals_from_data_and_root();
70}
71
72static int initialize_directories() {
73    int res = -1;
74
75    // Read current filesystem layout version to handle upgrade paths
76    char version_path[PATH_MAX];
77    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str());
78
79    int oldVersion;
80    if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
81        oldVersion = 0;
82    }
83    int version = oldVersion;
84
85    if (version < 2) {
86        SLOGD("Assuming that device has multi-user storage layout; upgrade no longer supported");
87        version = 2;
88    }
89
90    if (ensure_config_user_dirs(0) == -1) {
91        SLOGE("Failed to setup misc for user 0");
92        goto fail;
93    }
94
95    if (version == 2) {
96        SLOGD("Upgrading to /data/misc/user directories");
97
98        char misc_dir[PATH_MAX];
99        snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str());
100
101        char keychain_added_dir[PATH_MAX];
102        snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
103
104        char keychain_removed_dir[PATH_MAX];
105        snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir);
106
107        DIR *dir;
108        struct dirent *dirent;
109        dir = opendir("/data/user");
110        if (dir != NULL) {
111            while ((dirent = readdir(dir))) {
112                const char *name = dirent->d_name;
113
114                // skip "." and ".."
115                if (name[0] == '.') {
116                    if (name[1] == 0) continue;
117                    if ((name[1] == '.') && (name[2] == 0)) continue;
118                }
119
120                uint32_t user_id = std::stoi(name);
121
122                // /data/misc/user/<user_id>
123                if (ensure_config_user_dirs(user_id) == -1) {
124                    goto fail;
125                }
126
127                char misc_added_dir[PATH_MAX];
128                snprintf(misc_added_dir, PATH_MAX, "%s/user/%s/cacerts-added", misc_dir, name);
129
130                char misc_removed_dir[PATH_MAX];
131                snprintf(misc_removed_dir, PATH_MAX, "%s/user/%s/cacerts-removed", misc_dir, name);
132
133                uid_t uid = multiuser_get_uid(user_id, AID_SYSTEM);
134                gid_t gid = uid;
135                if (access(keychain_added_dir, F_OK) == 0) {
136                    if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) {
137                        SLOGE("Some files failed to copy");
138                    }
139                }
140                if (access(keychain_removed_dir, F_OK) == 0) {
141                    if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) {
142                        SLOGE("Some files failed to copy");
143                    }
144                }
145            }
146            closedir(dir);
147
148            if (access(keychain_added_dir, F_OK) == 0) {
149                delete_dir_contents(keychain_added_dir, 1, 0);
150            }
151            if (access(keychain_removed_dir, F_OK) == 0) {
152                delete_dir_contents(keychain_removed_dir, 1, 0);
153            }
154        }
155
156        version = 3;
157    }
158
159    // Persist layout version if changed
160    if (version != oldVersion) {
161        if (fs_write_atomic_int(version_path, version) == -1) {
162            SLOGE("Failed to save version to %s: %s", version_path, strerror(errno));
163            goto fail;
164        }
165    }
166
167    // Success!
168    res = 0;
169
170fail:
171    return res;
172}
173
174static int log_callback(int type, const char *fmt, ...) { // NOLINT
175    va_list ap;
176    int priority;
177
178    switch (type) {
179    case SELINUX_WARNING:
180        priority = ANDROID_LOG_WARN;
181        break;
182    case SELINUX_INFO:
183        priority = ANDROID_LOG_INFO;
184        break;
185    default:
186        priority = ANDROID_LOG_ERROR;
187        break;
188    }
189    va_start(ap, fmt);
190    LOG_PRI_VA(priority, "SELinux", fmt, ap);
191    va_end(ap);
192    return 0;
193}
194
195static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {
196    int ret;
197    int selinux_enabled = (is_selinux_enabled() > 0);
198
199    setenv("ANDROID_LOG_TAGS", "*:v", 1);
200    android::base::InitLogging(argv);
201
202    SLOGI("installd firing up");
203
204    union selinux_callback cb;
205    cb.func_log = log_callback;
206    selinux_set_callback(SELINUX_CB_LOG, cb);
207
208    if (!initialize_globals()) {
209        SLOGE("Could not initialize globals; exiting.\n");
210        exit(1);
211    }
212
213    if (initialize_directories() < 0) {
214        SLOGE("Could not create directories; exiting.\n");
215        exit(1);
216    }
217
218    if (selinux_enabled && selinux_status_open(true) < 0) {
219        SLOGE("Could not open selinux status; exiting.\n");
220        exit(1);
221    }
222
223    if ((ret = InstalldNativeService::start()) != android::OK) {
224        SLOGE("Unable to start InstalldNativeService: %d", ret);
225        exit(1);
226    }
227
228    IPCThreadState::self()->joinThreadPool();
229
230    LOG(INFO) << "installd shutting down";
231
232    return 0;
233}
234
235}  // namespace installd
236}  // namespace android
237
238int main(const int argc, char *argv[]) {
239    return android::installd::installd_main(argc, argv);
240}
241