blob: 6c49aa3d48432b0d38d729b5f71d8a32ef2963b4 [file] [log] [blame]
Mike Lockwood94afecf2012-10-24 10:45:23 -07001/*
2** Copyright 2008, The Android Open Source Project
3**
Jeff Sharkey19803802015-04-07 12:44:51 -07004** 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
Mike Lockwood94afecf2012-10-24 10:45:23 -07007**
Jeff Sharkey19803802015-04-07 12:44:51 -07008** http://www.apache.org/licenses/LICENSE-2.0
Mike Lockwood94afecf2012-10-24 10:45:23 -07009**
Jeff Sharkey19803802015-04-07 12:44:51 -070010** 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
Mike Lockwood94afecf2012-10-24 10:45:23 -070014** limitations under the License.
15*/
16
Andreas Gampe02d0de52015-11-11 20:43:16 -080017#include <fcntl.h>
Stephen Smalleybd558d62013-04-16 12:16:50 -040018#include <selinux/android.h>
19#include <selinux/avc.h>
Andreas Gampe02d0de52015-11-11 20:43:16 -080020#include <sys/capability.h>
Jeff Sharkeyc7d1b222016-01-11 13:07:09 -070021#include <sys/fsuid.h>
Andreas Gampe02d0de52015-11-11 20:43:16 -080022#include <sys/prctl.h>
Andreas Gampe02d0de52015-11-11 20:43:16 -080023#include <sys/stat.h>
24
25#include <android-base/logging.h>
26#include <cutils/fs.h>
27#include <cutils/log.h> // TODO: Move everything to base::logging.
28#include <cutils/properties.h>
Andreas Gampe02d0de52015-11-11 20:43:16 -080029#include <private/android_filesystem_config.h>
30
Jeff Sharkeyf3e30b92016-12-09 17:06:57 -070031#include "InstalldNativeService.h"
32#include "globals.h"
33#include "installd_constants.h"
34#include "installd_deps.h" // Need to fill in requirements of commands.
35#include "utils.h"
Andreas Gampe02d0de52015-11-11 20:43:16 -080036
37#ifndef LOG_TAG
38#define LOG_TAG "installd"
39#endif
Mike Lockwood94afecf2012-10-24 10:45:23 -070040
Andreas Gampe02d0de52015-11-11 20:43:16 -080041namespace android {
42namespace installd {
43
44// Check that installd-deps sizes match cutils sizes.
45static_assert(kPropertyKeyMax == PROPERTY_KEY_MAX, "Size mismatch.");
46static_assert(kPropertyValueMax == PROPERTY_VALUE_MAX, "Size mismatch.");
47
48////////////////////////
49// Plug-in functions. //
50////////////////////////
51
52int get_property(const char *key, char *value, const char *default_value) {
53 return property_get(key, value, default_value);
54}
55
56// Compute the output path of
57bool calculate_oat_file_path(char path[PKG_PATH_MAX],
58 const char *oat_dir,
59 const char *apk_path,
60 const char *instruction_set) {
Dan Austin63235022016-03-28 15:09:02 -070061 const char *file_name_start;
62 const char *file_name_end;
Andreas Gampe02d0de52015-11-11 20:43:16 -080063
64 file_name_start = strrchr(apk_path, '/');
65 if (file_name_start == NULL) {
66 ALOGE("apk_path '%s' has no '/'s in it\n", apk_path);
67 return false;
68 }
69 file_name_end = strrchr(apk_path, '.');
70 if (file_name_end < file_name_start) {
71 ALOGE("apk_path '%s' has no extension\n", apk_path);
72 return false;
73 }
74
75 // Calculate file_name
76 int file_name_len = file_name_end - file_name_start - 1;
77 char file_name[file_name_len + 1];
78 memcpy(file_name, file_name_start + 1, file_name_len);
79 file_name[file_name_len] = '\0';
80
81 // <apk_parent_dir>/oat/<isa>/<file_name>.odex
82 snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name);
83 return true;
84}
85
86/*
87 * Computes the odex file for the given apk_path and instruction_set.
88 * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
89 *
90 * Returns false if it failed to determine the odex file path.
91 */
92bool calculate_odex_file_path(char path[PKG_PATH_MAX],
93 const char *apk_path,
94 const char *instruction_set) {
95 if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
96 + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
97 ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
98 return false;
99 }
100
101 strcpy(path, apk_path);
102 char *end = strrchr(path, '/');
103 if (end == NULL) {
104 ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
105 return false;
106 }
107 const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
108
109 strcpy(end + 1, "oat/"); // path = /system/framework/oat/\0
110 strcat(path, instruction_set); // path = /system/framework/oat/<isa>\0
111 strcat(path, apk_end); // path = /system/framework/oat/<isa>/whatever.jar\0
112 end = strrchr(path, '.');
113 if (end == NULL) {
114 ALOGE("apk_path '%s' has no extension.\n", apk_path);
115 return false;
116 }
117 strcpy(end + 1, "odex");
118 return true;
119}
120
121bool create_cache_path(char path[PKG_PATH_MAX],
122 const char *src,
123 const char *instruction_set) {
Greg Kaiser00087b72016-03-14 13:29:10 -0700124 /* demand that we are an absolute path */
125 if ((src == nullptr) || (src[0] != '/') || strstr(src,"..")) {
Andreas Gampe02d0de52015-11-11 20:43:16 -0800126 return false;
127 }
128
Greg Kaiser00087b72016-03-14 13:29:10 -0700129 size_t srclen = strlen(src);
130
Andreas Gampe02d0de52015-11-11 20:43:16 -0800131 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
132 return false;
133 }
134
135 size_t dstlen =
136 android_data_dir.len +
137 strlen(DALVIK_CACHE) +
138 1 +
139 strlen(instruction_set) +
140 srclen +
141 strlen(DALVIK_CACHE_POSTFIX) + 2;
142
143 if (dstlen > PKG_PATH_MAX) {
144 return false;
145 }
146
David Brazdil249c1792016-09-06 15:35:28 +0100147 sprintf(path,"%s%s/%s/%s",
Andreas Gampe02d0de52015-11-11 20:43:16 -0800148 android_data_dir.path,
149 DALVIK_CACHE,
150 instruction_set,
David Brazdil249c1792016-09-06 15:35:28 +0100151 src + 1 /* skip the leading / */);
Andreas Gampe02d0de52015-11-11 20:43:16 -0800152
153 char* tmp =
154 path +
155 android_data_dir.len +
156 strlen(DALVIK_CACHE) +
157 1 +
158 strlen(instruction_set) + 1;
159
160 for(; *tmp; tmp++) {
161 if (*tmp == '/') {
162 *tmp = '@';
163 }
164 }
165
David Brazdil249c1792016-09-06 15:35:28 +0100166 strcat(path, DALVIK_CACHE_POSTFIX);
Andreas Gampe02d0de52015-11-11 20:43:16 -0800167 return true;
168}
169
Andreas Gamped089ca12016-06-27 14:25:30 -0700170static bool initialize_globals() {
Andreas Gampe02d0de52015-11-11 20:43:16 -0800171 const char* data_path = getenv("ANDROID_DATA");
172 if (data_path == nullptr) {
173 ALOGE("Could not find ANDROID_DATA");
174 return false;
175 }
176 const char* root_path = getenv("ANDROID_ROOT");
177 if (root_path == nullptr) {
178 ALOGE("Could not find ANDROID_ROOT");
179 return false;
Mike Lockwood94afecf2012-10-24 10:45:23 -0700180 }
181
Andreas Gampe02d0de52015-11-11 20:43:16 -0800182 return init_globals_from_data_and_root(data_path, root_path);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700183}
184
Andreas Gampe02d0de52015-11-11 20:43:16 -0800185static int initialize_directories() {
Mike Lockwood94afecf2012-10-24 10:45:23 -0700186 int res = -1;
187
188 // Read current filesystem layout version to handle upgrade paths
189 char version_path[PATH_MAX];
190 snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);
191
192 int oldVersion;
193 if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
194 oldVersion = 0;
195 }
196 int version = oldVersion;
197
Jeff Sharkeye02657d2016-01-13 09:37:46 -0700198 if (version < 2) {
199 SLOGD("Assuming that device has multi-user storage layout; upgrade no longer supported");
Mike Lockwood94afecf2012-10-24 10:45:23 -0700200 version = 2;
201 }
202
Robin Lee07053fc2014-04-29 19:42:01 +0100203 if (ensure_config_user_dirs(0) == -1) {
204 ALOGE("Failed to setup misc for user 0");
205 goto fail;
206 }
207
Robin Lee095c7632014-04-25 15:05:19 +0100208 if (version == 2) {
209 ALOGD("Upgrading to /data/misc/user directories");
210
Robin Lee60fd3fe2014-10-07 16:55:02 +0100211 char misc_dir[PATH_MAX];
212 snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
213
214 char keychain_added_dir[PATH_MAX];
215 snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
216
217 char keychain_removed_dir[PATH_MAX];
218 snprintf(keychain_removed_dir, PATH_MAX, "%s/keychain/cacerts-removed", misc_dir);
219
Robin Lee095c7632014-04-25 15:05:19 +0100220 DIR *dir;
221 struct dirent *dirent;
Jeff Sharkeye02657d2016-01-13 09:37:46 -0700222 dir = opendir("/data/user");
Robin Lee095c7632014-04-25 15:05:19 +0100223 if (dir != NULL) {
224 while ((dirent = readdir(dir))) {
Robin Lee60fd3fe2014-10-07 16:55:02 +0100225 const char *name = dirent->d_name;
Robin Lee095c7632014-04-25 15:05:19 +0100226
Robin Lee60fd3fe2014-10-07 16:55:02 +0100227 // skip "." and ".."
228 if (name[0] == '.') {
229 if (name[1] == 0) continue;
230 if ((name[1] == '.') && (name[2] == 0)) continue;
231 }
232
233 uint32_t user_id = atoi(name);
234
235 // /data/misc/user/<user_id>
236 if (ensure_config_user_dirs(user_id) == -1) {
237 goto fail;
238 }
239
240 char misc_added_dir[PATH_MAX];
241 snprintf(misc_added_dir, PATH_MAX, "%s/user/%s/cacerts-added", misc_dir, name);
242
243 char misc_removed_dir[PATH_MAX];
244 snprintf(misc_removed_dir, PATH_MAX, "%s/user/%s/cacerts-removed", misc_dir, name);
245
246 uid_t uid = multiuser_get_uid(user_id, AID_SYSTEM);
247 gid_t gid = uid;
248 if (access(keychain_added_dir, F_OK) == 0) {
249 if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) {
250 ALOGE("Some files failed to copy");
Robin Lee095c7632014-04-25 15:05:19 +0100251 }
Robin Lee60fd3fe2014-10-07 16:55:02 +0100252 }
253 if (access(keychain_removed_dir, F_OK) == 0) {
254 if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) {
255 ALOGE("Some files failed to copy");
Robin Lee095c7632014-04-25 15:05:19 +0100256 }
257 }
258 }
259 closedir(dir);
Robin Lee095c7632014-04-25 15:05:19 +0100260
Robin Lee60fd3fe2014-10-07 16:55:02 +0100261 if (access(keychain_added_dir, F_OK) == 0) {
262 delete_dir_contents(keychain_added_dir, 1, 0);
Robin Lee07053fc2014-04-29 19:42:01 +0100263 }
Robin Lee60fd3fe2014-10-07 16:55:02 +0100264 if (access(keychain_removed_dir, F_OK) == 0) {
265 delete_dir_contents(keychain_removed_dir, 1, 0);
Robin Lee07053fc2014-04-29 19:42:01 +0100266 }
267 }
268
269 version = 3;
Robin Lee095c7632014-04-25 15:05:19 +0100270 }
271
Mike Lockwood94afecf2012-10-24 10:45:23 -0700272 // Persist layout version if changed
273 if (version != oldVersion) {
274 if (fs_write_atomic_int(version_path, version) == -1) {
275 ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
276 goto fail;
277 }
278 }
279
280 // Success!
281 res = 0;
282
283fail:
Mike Lockwood94afecf2012-10-24 10:45:23 -0700284 return res;
285}
286
Stephen Smalley7abb52b2014-03-26 09:30:37 -0400287static int log_callback(int type, const char *fmt, ...) {
288 va_list ap;
289 int priority;
290
291 switch (type) {
292 case SELINUX_WARNING:
293 priority = ANDROID_LOG_WARN;
294 break;
295 case SELINUX_INFO:
296 priority = ANDROID_LOG_INFO;
297 break;
298 default:
299 priority = ANDROID_LOG_ERROR;
300 break;
301 }
302 va_start(ap, fmt);
303 LOG_PRI_VA(priority, "SELinux", fmt, ap);
304 va_end(ap);
305 return 0;
306}
307
Andreas Gampe02d0de52015-11-11 20:43:16 -0800308static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {
Jeff Sharkey6c2c0562016-12-07 12:12:00 -0700309 int ret;
Stephen Smalleybd558d62013-04-16 12:16:50 -0400310 int selinux_enabled = (is_selinux_enabled() > 0);
Mike Lockwood94afecf2012-10-24 10:45:23 -0700311
Jeff Sharkeye3637242015-04-08 20:56:42 -0700312 setenv("ANDROID_LOG_TAGS", "*:v", 1);
313 android::base::InitLogging(argv);
314
Jeff Sharkey6c2c0562016-12-07 12:12:00 -0700315 LOG(INFO) << "installd firing up";
Mike Lockwood94afecf2012-10-24 10:45:23 -0700316
Stephen Smalley7abb52b2014-03-26 09:30:37 -0400317 union selinux_callback cb;
318 cb.func_log = log_callback;
319 selinux_set_callback(SELINUX_CB_LOG, cb);
320
Andreas Gampe02d0de52015-11-11 20:43:16 -0800321 if (!initialize_globals()) {
Mike Lockwood94afecf2012-10-24 10:45:23 -0700322 ALOGE("Could not initialize globals; exiting.\n");
323 exit(1);
324 }
325
326 if (initialize_directories() < 0) {
327 ALOGE("Could not create directories; exiting.\n");
328 exit(1);
329 }
330
Stephen Smalleybd558d62013-04-16 12:16:50 -0400331 if (selinux_enabled && selinux_status_open(true) < 0) {
332 ALOGE("Could not open selinux status; exiting.\n");
333 exit(1);
334 }
335
Jeff Sharkey90874002016-12-05 11:18:55 -0700336 if ((ret = InstalldNativeService::start()) != android::OK) {
337 ALOGE("Unable to start InstalldNativeService: %d", ret);
338 exit(1);
339 }
340
Jeff Sharkey6c2c0562016-12-07 12:12:00 -0700341 IPCThreadState::self()->joinThreadPool();
Mike Lockwood94afecf2012-10-24 10:45:23 -0700342
Jeff Sharkey6c2c0562016-12-07 12:12:00 -0700343 LOG(INFO) << "installd shutting down";
Mike Lockwood94afecf2012-10-24 10:45:23 -0700344
345 return 0;
346}
Andreas Gampe02d0de52015-11-11 20:43:16 -0800347
348} // namespace installd
349} // namespace android
350
351int main(const int argc, char *argv[]) {
352 return android::installd::installd_main(argc, argv);
353}