/*
* 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);
}