blob: 102cf0e7c4b4f4e6fa8fa78cf7963cdf98e8197e [file] [log] [blame]
The Android Open Source Project88b60792009-03-03 19:28:42 -08001/*
2 * dexopt invocation test.
3 *
4 * You must have BOOTCLASSPATH defined. On the simulator, you will also
5 * need ANDROID_ROOT.
6 */
7#include <stdlib.h>
8#include <stdio.h>
9#include <unistd.h>
10#include <string.h>
11#include <sys/types.h>
12#include <sys/wait.h>
13#include <sys/file.h>
14#include <fcntl.h>
15#include <errno.h>
16
17#include "cutils/properties.h"
18
19//using namespace android;
20
21/*
22 * Privilege reduction function.
23 *
24 * Returns 0 on success, nonzero on failure.
25 */
26static int privFunc(void)
27{
28 printf("--- would reduce privs here\n");
29 return 0;
30}
31
32/*
33 * We're in the child process. exec dexopt.
34 */
35static void runDexopt(int zipFd, int odexFd, const char* inputFileName)
36{
37 static const char* kDexOptBin = "/bin/dexopt";
38 static const int kMaxIntLen = 12; // '-'+10dig+'\0' -OR- 0x+8dig
39 char zipNum[kMaxIntLen];
40 char odexNum[kMaxIntLen];
41 char dexoptFlags[PROPERTY_VALUE_MAX];
42 const char* androidRoot;
43 char* execFile;
44
45 /* pull optional configuration tweaks out of properties */
46 property_get("dalvik.vm.dexopt-flags", dexoptFlags, "");
47
48 /* find dexopt executable; this exists for simulator compatibility */
49 androidRoot = getenv("ANDROID_ROOT");
50 if (androidRoot == NULL)
51 androidRoot = "/system";
52 execFile = (char*) malloc(strlen(androidRoot) + strlen(kDexOptBin) +1);
53 sprintf(execFile, "%s%s", androidRoot, kDexOptBin);
54
55 sprintf(zipNum, "%d", zipFd);
56 sprintf(odexNum, "%d", odexFd);
57
58 execl(execFile, execFile, "--zip", zipNum, odexNum, inputFileName,
59 dexoptFlags, (char*) NULL);
60 fprintf(stderr, "execl(%s) failed: %s\n", kDexOptBin, strerror(errno));
61}
62
63/*
64 * Run dexopt on the specified Jar/APK.
65 *
66 * This uses fork() and exec() to mimic the way this would work in an
67 * installer; in practice for something this simple you could just exec()
68 * unless you really wanted the status messages.
69 *
70 * Returns 0 on success.
71 */
72int doStuff(const char* zipName, const char* odexName)
73{
74 int zipFd, odexFd;
75
76 /*
77 * Open the zip archive and the odex file, creating the latter (and
78 * failing if it already exists). This must be done while we still
79 * have sufficient privileges to read the source file and create a file
80 * in the target directory. The "classes.dex" file will be extracted.
81 */
82 zipFd = open(zipName, O_RDONLY, 0);
83 if (zipFd < 0) {
84 fprintf(stderr, "Unable to open '%s': %s\n", zipName, strerror(errno));
85 return 1;
86 }
87
88 odexFd = open(odexName, O_RDWR | O_CREAT | O_EXCL, 0644);
89 if (odexFd < 0) {
90 fprintf(stderr, "Unable to create '%s': %s\n",
91 odexName, strerror(errno));
92 close(zipFd);
93 return 1;
94 }
95
96 printf("--- BEGIN '%s' (bootstrap=%d) ---\n", zipName, 0);
97
98 /*
99 * Fork a child process.
100 */
101 pid_t pid = fork();
102 if (pid == 0) {
103 /* child -- drop privs */
104 if (privFunc() != 0)
105 exit(66);
106
107 /* lock the input file */
108 if (flock(odexFd, LOCK_EX | LOCK_NB) != 0) {
109 fprintf(stderr, "Unable to lock '%s': %s\n",
110 odexName, strerror(errno));
111 exit(65);
112 }
113
114 runDexopt(zipFd, odexFd, zipName); /* does not return */
115 exit(67); /* usually */
116 } else {
117 /* parent -- wait for child to finish */
The Android Open Source Project6bce2052009-03-13 13:04:19 -0700118 printf("--- waiting for verify+opt, pid=%d\n", (int) pid);
The Android Open Source Project88b60792009-03-03 19:28:42 -0800119 int status, oldStatus;
120 pid_t gotPid;
121
122 close(zipFd);
123 close(odexFd);
124
125 /*
126 * Wait for the optimization process to finish.
127 */
128 while (true) {
129 gotPid = waitpid(pid, &status, 0);
130 if (gotPid == -1 && errno == EINTR) {
131 printf("waitpid interrupted, retrying\n");
132 } else {
133 break;
134 }
135 }
136 if (gotPid != pid) {
137 fprintf(stderr, "waitpid failed: wanted %d, got %d: %s\n",
138 (int) pid, (int) gotPid, strerror(errno));
139 return 1;
140 }
141
142 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
143 printf("--- END '%s' (success) ---\n", zipName);
144 return 0;
145 } else {
146 printf("--- END '%s' --- status=0x%04x, process failed\n",
147 zipName, status);
148 return 1;
149 }
150 }
151
152 /* notreached */
153}
154
155/*
156 * Parse args, do stuff.
157 */
158int main(int argc, char** argv)
159{
160 if (argc < 3 || argc > 4) {
161 fprintf(stderr, "Usage: %s <input jar/apk> <output odex> "
162 "[<bootclasspath>]\n\n", argv[0]);
163 fprintf(stderr, "Example: dexopttest "
164 "/system/app/NotePad.apk /system/app/NotePad.odex\n");
165 return 2;
166 }
167
168 if (argc > 3) {
169 setenv("BOOTCLASSPATH", argv[3], 1);
170 }
171
172 return (doStuff(argv[1], argv[2]) != 0);
173}