| /* |
| * dexopt invocation test. |
| * |
| * You must have BOOTCLASSPATH defined. On the simulator, you will also |
| * need ANDROID_ROOT. |
| */ |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <sys/file.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| |
| #include "cutils/properties.h" |
| |
| //using namespace android; |
| |
| /* |
| * Privilege reduction function. |
| * |
| * Returns 0 on success, nonzero on failure. |
| */ |
| static int privFunc(void) |
| { |
| printf("--- would reduce privs here\n"); |
| return 0; |
| } |
| |
| /* |
| * We're in the child process. exec dexopt. |
| */ |
| static void runDexopt(int zipFd, int odexFd, const char* inputFileName) |
| { |
| static const char* kDexOptBin = "/bin/dexopt"; |
| static const int kMaxIntLen = 12; // '-'+10dig+'\0' -OR- 0x+8dig |
| char zipNum[kMaxIntLen]; |
| char odexNum[kMaxIntLen]; |
| char dexoptFlags[PROPERTY_VALUE_MAX]; |
| const char* androidRoot; |
| char* execFile; |
| |
| /* pull optional configuration tweaks out of properties */ |
| property_get("dalvik.vm.dexopt-flags", dexoptFlags, ""); |
| |
| /* find dexopt executable; this exists for simulator compatibility */ |
| androidRoot = getenv("ANDROID_ROOT"); |
| if (androidRoot == NULL) |
| androidRoot = "/system"; |
| execFile = (char*) malloc(strlen(androidRoot) + strlen(kDexOptBin) +1); |
| sprintf(execFile, "%s%s", androidRoot, kDexOptBin); |
| |
| sprintf(zipNum, "%d", zipFd); |
| sprintf(odexNum, "%d", odexFd); |
| |
| execl(execFile, execFile, "--zip", zipNum, odexNum, inputFileName, |
| dexoptFlags, (char*) NULL); |
| fprintf(stderr, "execl(%s) failed: %s\n", kDexOptBin, strerror(errno)); |
| } |
| |
| /* |
| * Run dexopt on the specified Jar/APK. |
| * |
| * This uses fork() and exec() to mimic the way this would work in an |
| * installer; in practice for something this simple you could just exec() |
| * unless you really wanted the status messages. |
| * |
| * Returns 0 on success. |
| */ |
| int doStuff(const char* zipName, const char* odexName) |
| { |
| int zipFd, odexFd; |
| |
| /* |
| * Open the zip archive and the odex file, creating the latter (and |
| * failing if it already exists). This must be done while we still |
| * have sufficient privileges to read the source file and create a file |
| * in the target directory. The "classes.dex" file will be extracted. |
| */ |
| zipFd = open(zipName, O_RDONLY, 0); |
| if (zipFd < 0) { |
| fprintf(stderr, "Unable to open '%s': %s\n", zipName, strerror(errno)); |
| return 1; |
| } |
| |
| odexFd = open(odexName, O_RDWR | O_CREAT | O_EXCL, 0644); |
| if (odexFd < 0) { |
| fprintf(stderr, "Unable to create '%s': %s\n", |
| odexName, strerror(errno)); |
| close(zipFd); |
| return 1; |
| } |
| |
| printf("--- BEGIN '%s' (bootstrap=%d) ---\n", zipName, 0); |
| |
| /* |
| * Fork a child process. |
| */ |
| pid_t pid = fork(); |
| if (pid == 0) { |
| /* child -- drop privs */ |
| if (privFunc() != 0) |
| exit(66); |
| |
| /* lock the input file */ |
| if (flock(odexFd, LOCK_EX | LOCK_NB) != 0) { |
| fprintf(stderr, "Unable to lock '%s': %s\n", |
| odexName, strerror(errno)); |
| exit(65); |
| } |
| |
| runDexopt(zipFd, odexFd, zipName); /* does not return */ |
| exit(67); /* usually */ |
| } else { |
| /* parent -- wait for child to finish */ |
| printf("waiting for verify+opt, pid=%d\n", (int) pid); |
| int status, oldStatus; |
| pid_t gotPid; |
| |
| close(zipFd); |
| close(odexFd); |
| |
| /* |
| * Wait for the optimization process to finish. |
| */ |
| while (true) { |
| gotPid = waitpid(pid, &status, 0); |
| if (gotPid == -1 && errno == EINTR) { |
| printf("waitpid interrupted, retrying\n"); |
| } else { |
| break; |
| } |
| } |
| if (gotPid != pid) { |
| fprintf(stderr, "waitpid failed: wanted %d, got %d: %s\n", |
| (int) pid, (int) gotPid, strerror(errno)); |
| return 1; |
| } |
| |
| if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { |
| printf("--- END '%s' (success) ---\n", zipName); |
| return 0; |
| } else { |
| printf("--- END '%s' --- status=0x%04x, process failed\n", |
| zipName, status); |
| return 1; |
| } |
| } |
| |
| /* notreached */ |
| } |
| |
| /* |
| * Parse args, do stuff. |
| */ |
| int main(int argc, char** argv) |
| { |
| if (argc < 3 || argc > 4) { |
| fprintf(stderr, "Usage: %s <input jar/apk> <output odex> " |
| "[<bootclasspath>]\n\n", argv[0]); |
| fprintf(stderr, "Example: dexopttest " |
| "/system/app/NotePad.apk /system/app/NotePad.odex\n"); |
| return 2; |
| } |
| |
| if (argc > 3) { |
| setenv("BOOTCLASSPATH", argv[3], 1); |
| } |
| |
| return (doStuff(argv[1], argv[2]) != 0); |
| } |