blob: a3651b23e5190c0352abc1e4096c22939f1ce189 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
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
17#include "installd.h"
18
19int install(const char *pkgname, uid_t uid, gid_t gid)
20{
21 char pkgdir[PKG_PATH_MAX];
22 char libdir[PKG_PATH_MAX];
23
24 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
25 LOGE("invalid uid/gid: %d %d\n", uid, gid);
26 return -1;
27
28 }
29 if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
30 return -1;
31 if (create_pkg_path(libdir, PKG_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX))
32 return -1;
33
34 if (mkdir(pkgdir, 0755) < 0) {
35 LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
36 return -errno;
37 }
38 if (chown(pkgdir, uid, gid) < 0) {
39 LOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
40 unlink(pkgdir);
41 return -errno;
42 }
43 if (mkdir(libdir, 0755) < 0) {
44 LOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
45 unlink(pkgdir);
46 return -errno;
47 }
48 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
49 LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
50 unlink(libdir);
51 unlink(pkgdir);
52 return -errno;
53 }
54 return 0;
55}
56
57int uninstall(const char *pkgname)
58{
59 char pkgdir[PKG_PATH_MAX];
60
61 if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
62 return -1;
63
64 /* delete contents AND directory, no exceptions */
65 return delete_dir_contents(pkgdir, 1, 0);
66}
67
68int delete_user_data(const char *pkgname)
69{
70 char pkgdir[PKG_PATH_MAX];
71
72 if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
73 return -1;
74
75 /* delete contents, excluding "lib", but not the directory itself */
76 return delete_dir_contents(pkgdir, 0, "lib");
77}
78
79int delete_cache(const char *pkgname)
80{
81 char cachedir[PKG_PATH_MAX];
82
83 if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX))
84 return -1;
85
86 /* delete contents, not the directory, no exceptions */
87 return delete_dir_contents(cachedir, 0, 0);
88}
89
90
91static int disk_free(void)
92{
93 struct statfs sfs;
94 if (statfs(PKG_DIR_PREFIX, &sfs) == 0) {
95 return sfs.f_bavail * sfs.f_bsize;
96 } else {
97 return -1;
98 }
99}
100
101
102/* Try to ensure free_size bytes of storage are available.
103 * Returns 0 on success.
104 * This is rather simple-minded because doing a full LRU would
105 * be potentially memory-intensive, and without atime it would
106 * also require that apps constantly modify file metadata even
107 * when just reading from the cache, which is pretty awful.
108 */
109int free_cache(int free_size)
110{
111 const char *name;
112 int dfd, subfd;
113 DIR *d;
114 struct dirent *de;
115 int avail;
116
117 avail = disk_free();
118 if (avail < 0) return -1;
119
120 LOGI("free_cache(%d) avail %d\n", free_size, avail);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800121 if (avail >= free_size) return 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700122
123 d = opendir(PKG_DIR_PREFIX);
124 if (d == NULL) {
125 LOGE("cannot open %s\n", PKG_DIR_PREFIX);
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800126 return -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700127 }
128 dfd = dirfd(d);
129
130 while ((de = readdir(d))) {
131 if (de->d_type != DT_DIR) continue;
132 name = de->d_name;
133
134 /* always skip "." and ".." */
135 if (name[0] == '.') {
136 if (name[1] == 0) continue;
137 if ((name[1] == '.') && (name[2] == 0)) continue;
138 }
139
140 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
141 if (subfd < 0) continue;
142
143 delete_dir_contents_fd(subfd, "cache");
144 close(subfd);
145
146 avail = disk_free();
The Android Open Source Projectf1e484a2009-01-22 00:13:42 -0800147 if (avail >= free_size) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700148 closedir(d);
149 return 0;
150 }
151 }
152 closedir(d);
153 return -1;
154}
155
156
157/* used by move_dex, rm_dex, etc to ensure that the provided paths
158 * don't point anywhere other than at the APK_DIR_PREFIX
159 */
160static int is_valid_apk_path(const char *path)
161{
162 int len = strlen(APK_DIR_PREFIX);
163 if (strncmp(path, APK_DIR_PREFIX, len)) {
164 len = strlen(PROTECTED_DIR_PREFIX);
165 if (strncmp(path, PROTECTED_DIR_PREFIX, len)) {
166 LOGE("invalid apk path '%s' (bad prefix)\n", path);
167 return 0;
168 }
169 }
170 if (strchr(path + len, '/')) {
171 LOGE("invalid apk path '%s' (subdir?)\n", path);
172 return 0;
173 }
174 if (path[len] == '.') {
175 LOGE("invalid apk path '%s' (trickery)\n", path);
176 return 0;
177 }
178 return 1;
179}
180
181int move_dex(const char *src, const char *dst)
182{
183 char src_dex[PKG_PATH_MAX];
184 char dst_dex[PKG_PATH_MAX];
185
186 if (!is_valid_apk_path(src)) return -1;
187 if (!is_valid_apk_path(dst)) return -1;
188
189 if (create_cache_path(src_dex, src)) return -1;
190 if (create_cache_path(dst_dex, dst)) return -1;
191
192 LOGI("move %s -> %s\n", src_dex, dst_dex);
193 if (rename(src_dex, dst_dex) < 0) {
194 return -1;
195 } else {
196 return 0;
197 }
198}
199
200int rm_dex(const char *path)
201{
202 char dex_path[PKG_PATH_MAX];
203
204 if (!is_valid_apk_path(path)) return -1;
205 if (create_cache_path(dex_path, path)) return -1;
206
207 LOGI("unlink %s\n", dex_path);
208 if (unlink(dex_path) < 0) {
209 return -1;
210 } else {
211 return 0;
212 }
213}
214
215int protect(char *pkgname, gid_t gid)
216{
217 struct stat s;
218 char pkgpath[PKG_PATH_MAX];
219
220 if (gid < AID_SYSTEM) return -1;
221
222 if (create_pkg_path(pkgpath, PROTECTED_DIR_PREFIX, pkgname, ".apk"))
223 return -1;
224
225 if (stat(pkgpath, &s) < 0) return -1;
226
227 if (chown(pkgpath, s.st_uid, gid) < 0) {
228 LOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
229 return -1;
230 }
231
232 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
233 LOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
234 return -1;
235 }
236
237 return 0;
238}
239
240static int stat_size(struct stat *s)
241{
242 int blksize = s->st_blksize;
243 int size = s->st_size;
244
245 if (blksize) {
246 /* round up to filesystem block size */
247 size = (size + blksize - 1) & (~(blksize - 1));
248 }
249
250 return size;
251}
252
253static int calculate_dir_size(int dfd)
254{
255 int size = 0;
256 struct stat s;
257 DIR *d;
258 struct dirent *de;
259
260 d = fdopendir(dfd);
261 if (d == NULL) {
262 close(dfd);
263 return 0;
264 }
265
266 while ((de = readdir(d))) {
267 const char *name = de->d_name;
268 if (de->d_type == DT_DIR) {
269 int subfd;
270 /* always skip "." and ".." */
271 if (name[0] == '.') {
272 if (name[1] == 0) continue;
273 if ((name[1] == '.') && (name[2] == 0)) continue;
274 }
275 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
276 if (subfd >= 0) {
277 size += calculate_dir_size(subfd);
278 }
279 } else {
280 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
281 size += stat_size(&s);
282 }
283 }
284 }
285 closedir(d);
286 return size;
287}
288
289int get_size(const char *pkgname, const char *apkpath,
290 const char *fwdlock_apkpath,
291 int *_codesize, int *_datasize, int *_cachesize)
292{
293 DIR *d;
294 int dfd;
295 struct dirent *de;
296 struct stat s;
297 char path[PKG_PATH_MAX];
298
299 int codesize = 0;
300 int datasize = 0;
301 int cachesize = 0;
302
303 /* count the source apk as code -- but only if it's not
304 * on the /system partition
305 */
306 if (strncmp(apkpath, "/system", 7) != 0) {
307 if (stat(apkpath, &s) == 0) {
308 codesize += stat_size(&s);
309 }
310 }
311 /* count the forward locked apk as code if it is given
312 */
313 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
314 if (stat(fwdlock_apkpath, &s) == 0) {
315 codesize += stat_size(&s);
316 }
317 }
318
319
320 /* count the cached dexfile as code */
321 if (!create_cache_path(path, apkpath)) {
322 if (stat(path, &s) == 0) {
323 codesize += stat_size(&s);
324 }
325 }
326
327 if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) {
328 goto done;
329 }
330
331 d = opendir(path);
332 if (d == NULL) {
333 goto done;
334 }
335 dfd = dirfd(d);
336
337 /* most stuff in the pkgdir is data, except for the "cache"
338 * directory and below, which is cache, and the "lib" directory
339 * and below, which is code...
340 */
341 while ((de = readdir(d))) {
342 const char *name = de->d_name;
343
344 if (de->d_type == DT_DIR) {
345 int subfd;
346 /* always skip "." and ".." */
347 if (name[0] == '.') {
348 if (name[1] == 0) continue;
349 if ((name[1] == '.') && (name[2] == 0)) continue;
350 }
351 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
352 if (subfd >= 0) {
353 int size = calculate_dir_size(subfd);
354 if (!strcmp(name,"lib")) {
355 codesize += size;
356 } else if(!strcmp(name,"cache")) {
357 cachesize += size;
358 } else {
359 datasize += size;
360 }
361 }
362 } else {
363 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
364 datasize += stat_size(&s);
365 }
366 }
367 }
368 closedir(d);
369done:
370 *_codesize = codesize;
371 *_datasize = datasize;
372 *_cachesize = cachesize;
373 return 0;
374}
375
376
377/* a simpler version of dexOptGenerateCacheFileName() */
378int create_cache_path(char path[PKG_PATH_MAX], const char *src)
379{
380 char *tmp;
381 int srclen;
382 int dstlen;
383
384 srclen = strlen(src);
385
386 /* demand that we are an absolute path */
387 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
388 return -1;
389 }
390
391 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
392 return -1;
393 }
394
395 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
396 strlen(DALVIK_CACHE_POSTFIX) + 1;
397
398 if (dstlen > PKG_PATH_MAX) {
399 return -1;
400 }
401
402 sprintf(path,"%s%s%s",
403 DALVIK_CACHE_PREFIX,
404 src + 1, /* skip the leading / */
405 DALVIK_CACHE_POSTFIX);
406
407 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
408 if (*tmp == '/') {
409 *tmp = '@';
410 }
411 }
412
413 return 0;
414}
415
416static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name)
417{
418 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
419 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
420 char zip_num[MAX_INT_LEN];
421 char odex_num[MAX_INT_LEN];
422
423 sprintf(zip_num, "%d", zip_fd);
424 sprintf(odex_num, "%d", odex_fd);
425
426 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
427 (char*) NULL);
428 LOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
429}
430
431static int wait_dexopt(pid_t pid, const char* apk_path)
432{
433 int status;
434 pid_t got_pid;
435
436 /*
437 * Wait for the optimization process to finish.
438 */
439 while (1) {
440 got_pid = waitpid(pid, &status, 0);
441 if (got_pid == -1 && errno == EINTR) {
442 printf("waitpid interrupted, retrying\n");
443 } else {
444 break;
445 }
446 }
447 if (got_pid != pid) {
448 LOGW("waitpid failed: wanted %d, got %d: %s\n",
449 (int) pid, (int) got_pid, strerror(errno));
450 return 1;
451 }
452
453 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
454 LOGD("DexInv: --- END '%s' (success) ---\n", apk_path);
455 return 0;
456 } else {
457 LOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
458 apk_path, status);
459 return status; /* always nonzero */
460 }
461}
462
463int dexopt(const char *apk_path, uid_t uid, int is_public)
464{
465 struct utimbuf ut;
466 struct stat apk_stat, dex_stat;
467 char dex_path[PKG_PATH_MAX];
468 char *end;
469 int res, zip_fd=-1, odex_fd=-1;
470
471 /* Before anything else: is there a .odex file? If so, we have
472 * pre-optimized the apk and there is nothing to do here.
473 */
474 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
475 return -1;
476 }
477
478 strcpy(dex_path, apk_path);
479 end = strrchr(dex_path, '.');
480 if (end != NULL) {
481 strcpy(end, ".odex");
482 if (stat(dex_path, &dex_stat) == 0) {
483 return 0;
484 }
485 }
486
487 if (create_cache_path(dex_path, apk_path)) {
488 return -1;
489 }
490
491 memset(&apk_stat, 0, sizeof(apk_stat));
492 stat(apk_path, &apk_stat);
493
494 zip_fd = open(apk_path, O_RDONLY, 0);
495 if (zip_fd < 0) {
496 LOGE("dexopt cannot open '%s' for input\n", apk_path);
497 return -1;
498 }
499
500 unlink(dex_path);
501 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
502 if (odex_fd < 0) {
503 LOGE("dexopt cannot open '%s' for output\n", dex_path);
504 goto fail;
505 }
506 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
507 LOGE("dexopt cannot chown '%s'\n", dex_path);
508 goto fail;
509 }
510 if (fchmod(odex_fd,
511 S_IRUSR|S_IWUSR|S_IRGRP |
512 (is_public ? S_IROTH : 0)) < 0) {
513 LOGE("dexopt cannot chmod '%s'\n", dex_path);
514 goto fail;
515 }
516
517 LOGD("DexInv: --- BEGIN '%s' ---\n", apk_path);
518
519 pid_t pid;
520 pid = fork();
521 if (pid == 0) {
522 /* child -- drop privileges before continuing */
523 if (setgid(uid) != 0) {
524 LOGE("setgid(%d) failed during dexopt\n", uid);
525 exit(64);
526 }
527 if (setuid(uid) != 0) {
528 LOGE("setuid(%d) during dexopt\n", uid);
529 exit(65);
530 }
531 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
532 LOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
533 exit(66);
534 }
535
536 run_dexopt(zip_fd, odex_fd, apk_path); /* does not return */
537 exit(67);
538 } else {
539 res = wait_dexopt(pid, apk_path);
540 if (res != 0) {
541 LOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
542 goto fail;
543 }
544 }
545
546 ut.actime = apk_stat.st_atime;
547 ut.modtime = apk_stat.st_mtime;
548 utime(dex_path, &ut);
549
550 close(odex_fd);
551 close(zip_fd);
552 return 0;
553
554fail:
555 if (odex_fd >= 0) {
556 close(odex_fd);
557 unlink(dex_path);
558 }
559 if (zip_fd >= 0) {
560 close(zip_fd);
561 }
562 return -1;
563}