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