diff options
Diffstat (limited to 'cmds')
-rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 306 | ||||
-rw-r--r-- | cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java | 15 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 2 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.c | 30 | ||||
-rwxr-xr-x[-rw-r--r--] | cmds/input/input | 0 | ||||
-rw-r--r-- | cmds/installd/commands.c | 302 | ||||
-rw-r--r-- | cmds/installd/installd.c | 50 | ||||
-rw-r--r-- | cmds/installd/installd.h | 25 | ||||
-rw-r--r-- | cmds/installd/utils.c | 8 | ||||
-rw-r--r-- | cmds/keystore/keystore.c | 97 | ||||
-rw-r--r-- | cmds/keystore/keystore_get.h | 5 | ||||
-rw-r--r-- | cmds/screencap/Android.mk | 18 | ||||
-rw-r--r-- | cmds/screencap/screencap.cpp | 42 | ||||
-rw-r--r-- | cmds/servicemanager/bctest.c | 3 | ||||
-rw-r--r-- | cmds/servicemanager/service_manager.c | 9 | ||||
-rw-r--r-- | cmds/stagefright/Android.mk | 13 | ||||
-rw-r--r-- | cmds/stagefright/record.cpp | 85 | ||||
-rw-r--r-- | cmds/stagefright/stagefright.cpp | 400 | ||||
-rw-r--r-- | cmds/surfaceflinger/main_surfaceflinger.cpp | 31 | ||||
-rw-r--r-- | cmds/svc/src/com/android/commands/svc/PowerCommand.java | 2 | ||||
-rw-r--r-- | cmds/system_server/library/Android.mk | 2 | ||||
-rw-r--r-- | cmds/system_server/library/system_init.cpp | 4 |
22 files changed, 1259 insertions, 190 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 301883f..f2aa91f 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -19,6 +19,7 @@ package com.android.commands.am; import android.app.ActivityManagerNative; +import android.app.IActivityController; import android.app.IActivityManager; import android.app.IInstrumentationWatcher; import android.app.Instrumentation; @@ -33,8 +34,11 @@ import android.os.ServiceManager; import android.util.AndroidException; import android.view.IWindowManager; +import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintStream; import java.net.URISyntaxException; import java.util.Iterator; @@ -98,6 +102,8 @@ public class Am { sendBroadcast(); } else if (op.equals("profile")) { runProfile(); + } else if (op.equals("monitor")) { + runMonitor(); } else { throw new IllegalArgumentException("Unknown command: " + op); } @@ -424,6 +430,303 @@ public class Am { } } + class MyActivityController extends IActivityController.Stub { + final String mGdbPort; + + static final int STATE_NORMAL = 0; + static final int STATE_CRASHED = 1; + static final int STATE_EARLY_ANR = 2; + static final int STATE_ANR = 3; + + int mState; + + static final int RESULT_DEFAULT = 0; + + static final int RESULT_CRASH_DIALOG = 0; + static final int RESULT_CRASH_KILL = 1; + + static final int RESULT_EARLY_ANR_CONTINUE = 0; + static final int RESULT_EARLY_ANR_KILL = 1; + + static final int RESULT_ANR_DIALOG = 0; + static final int RESULT_ANR_KILL = 1; + static final int RESULT_ANR_WAIT = 1; + + int mResult; + + Process mGdbProcess; + Thread mGdbThread; + boolean mGotGdbPrint; + + MyActivityController(String gdbPort) { + mGdbPort = gdbPort; + } + + @Override + public boolean activityResuming(String pkg) throws RemoteException { + synchronized (this) { + System.out.println("** Activity resuming: " + pkg); + } + return true; + } + + @Override + public boolean activityStarting(Intent intent, String pkg) throws RemoteException { + synchronized (this) { + System.out.println("** Activity starting: " + pkg); + } + return true; + } + + @Override + public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg, + long timeMillis, String stackTrace) throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: PROCESS CRASHED"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("shortMsg: " + shortMsg); + System.out.println("longMsg: " + longMsg); + System.out.println("timeMillis: " + timeMillis); + System.out.println("stack:"); + System.out.print(stackTrace); + System.out.println("#"); + int result = waitControllerLocked(pid, STATE_CRASHED); + return result == RESULT_CRASH_KILL ? false : true; + } + } + + @Override + public int appEarlyNotResponding(String processName, int pid, String annotation) + throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("annotation: " + annotation); + int result = waitControllerLocked(pid, STATE_EARLY_ANR); + if (result == RESULT_EARLY_ANR_KILL) return -1; + return 0; + } + } + + @Override + public int appNotResponding(String processName, int pid, String processStats) + throws RemoteException { + synchronized (this) { + System.out.println("** ERROR: PROCESS NOT RESPONDING"); + System.out.println("processName: " + processName); + System.out.println("processPid: " + pid); + System.out.println("processStats:"); + System.out.print(processStats); + System.out.println("#"); + int result = waitControllerLocked(pid, STATE_ANR); + if (result == RESULT_ANR_KILL) return -1; + if (result == RESULT_ANR_WAIT) return 1; + return 0; + } + } + + void killGdbLocked() { + mGotGdbPrint = false; + if (mGdbProcess != null) { + System.out.println("Stopping gdbserver"); + mGdbProcess.destroy(); + mGdbProcess = null; + } + if (mGdbThread != null) { + mGdbThread.interrupt(); + mGdbThread = null; + } + } + + int waitControllerLocked(int pid, int state) { + if (mGdbPort != null) { + killGdbLocked(); + + try { + System.out.println("Starting gdbserver on port " + mGdbPort); + System.out.println("Do the following:"); + System.out.println(" adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort); + System.out.println(" gdbclient app_process :" + mGdbPort); + + mGdbProcess = Runtime.getRuntime().exec(new String[] { + "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid) + }); + final InputStreamReader converter = new InputStreamReader( + mGdbProcess.getInputStream()); + mGdbThread = new Thread() { + @Override + public void run() { + BufferedReader in = new BufferedReader(converter); + String line; + int count = 0; + while (true) { + synchronized (MyActivityController.this) { + if (mGdbThread == null) { + return; + } + if (count == 2) { + mGotGdbPrint = true; + MyActivityController.this.notifyAll(); + } + } + try { + line = in.readLine(); + if (line == null) { + return; + } + System.out.println("GDB: " + line); + count++; + } catch (IOException e) { + return; + } + } + } + }; + mGdbThread.start(); + + // Stupid waiting for .5s. Doesn't matter if we end early. + try { + this.wait(500); + } catch (InterruptedException e) { + } + + } catch (IOException e) { + System.err.println("Failure starting gdbserver: " + e); + killGdbLocked(); + } + } + mState = state; + System.out.println(""); + printMessageForState(); + + while (mState != STATE_NORMAL) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + killGdbLocked(); + + return mResult; + } + + void resumeController(int result) { + synchronized (this) { + mState = STATE_NORMAL; + mResult = result; + notifyAll(); + } + } + + void printMessageForState() { + switch (mState) { + case STATE_NORMAL: + System.out.println("Monitoring activity manager... available commands:"); + break; + case STATE_CRASHED: + System.out.println("Waiting after crash... available commands:"); + System.out.println("(c)ontinue: show crash dialog"); + System.out.println("(k)ill: immediately kill app"); + break; + case STATE_EARLY_ANR: + System.out.println("Waiting after early ANR... available commands:"); + System.out.println("(c)ontinue: standard ANR processing"); + System.out.println("(k)ill: immediately kill app"); + break; + case STATE_ANR: + System.out.println("Waiting after ANR... available commands:"); + System.out.println("(c)ontinue: show ANR dialog"); + System.out.println("(k)ill: immediately kill app"); + System.out.println("(w)ait: wait some more"); + break; + } + System.out.println("(q)uit: finish monitoring"); + } + + void run() throws RemoteException { + try { + printMessageForState(); + + mAm.setActivityController(this); + mState = STATE_NORMAL; + + InputStreamReader converter = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(converter); + String line; + + while ((line = in.readLine()) != null) { + boolean addNewline = true; + if (line.length() <= 0) { + addNewline = false; + } else if ("q".equals(line) || "quit".equals(line)) { + resumeController(RESULT_DEFAULT); + break; + } else if (mState == STATE_CRASHED) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_CRASH_DIALOG); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_CRASH_KILL); + } else { + System.out.println("Invalid command: " + line); + } + } else if (mState == STATE_ANR) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_ANR_DIALOG); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_ANR_KILL); + } else if ("w".equals(line) || "wait".equals(line)) { + resumeController(RESULT_ANR_WAIT); + } else { + System.out.println("Invalid command: " + line); + } + } else if (mState == STATE_EARLY_ANR) { + if ("c".equals(line) || "continue".equals(line)) { + resumeController(RESULT_EARLY_ANR_CONTINUE); + } else if ("k".equals(line) || "kill".equals(line)) { + resumeController(RESULT_EARLY_ANR_KILL); + } else { + System.out.println("Invalid command: " + line); + } + } else { + System.out.println("Invalid command: " + line); + } + + synchronized (this) { + if (addNewline) { + System.out.println(""); + } + printMessageForState(); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + mAm.setActivityController(null); + } + } + } + + private void runMonitor() throws Exception { + String opt; + String gdbPort = null; + while ((opt=nextOption()) != null) { + if (opt.equals("--gdb")) { + gdbPort = nextArgRequired(); + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return; + } + } + + MyActivityController controller = new MyActivityController(gdbPort); + controller.run(); + } + private class IntentReceiver extends IIntentReceiver.Stub { private boolean mFinished = false; @@ -594,6 +897,9 @@ public class Am { " start profiling: am profile <PROCESS> start <FILE>\n" + " stop profiling: am profile <PROCESS> stop\n" + "\n" + + " start monitoring: am monitor [--gdb <port>]\n" + + " --gdb: start gdbserv on the given port at crash/ANR\n" + + "\n" + " <INTENT> specifications include these flags:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index 8263e75..37c8ad0 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -34,7 +34,6 @@ public final class Bmgr { private String[] mArgs; private int mNextArg; - private String mCurArgData; public static void main(String[] args) { try { @@ -175,6 +174,11 @@ public final class Bmgr { private void doTransport() { try { String which = nextArg(); + if (which == null) { + showUsage(); + return; + } + String old = mBmgr.selectBackupTransport(which); if (old == null) { System.out.println("Unknown transport '" + which @@ -269,6 +273,10 @@ public final class Bmgr { } private void printRestoreSets(RestoreSet[] sets) { + if (sets == null || sets.length == 0) { + System.out.println("No restore sets"); + return; + } for (RestoreSet s : sets) { System.out.println(" " + Long.toHexString(s.token) + " : " + s.name); } @@ -318,6 +326,11 @@ public final class Bmgr { private void doRestore() { String arg = nextArg(); + if (arg == null) { + showUsage(); + return; + } + if (arg.indexOf('.') >= 0) { // it's a package name doRestorePackage(arg); diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 12c9fe5..6650a71 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -38,7 +38,7 @@ #include <ui/EGLUtils.h> #include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/ISurfaceFlingerClient.h> +#include <surfaceflinger/ISurfaceComposerClient.h> #include <core/SkBitmap.h> #include <images/SkImageDecoder.h> diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 082e704..0723f67 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -122,11 +122,11 @@ static void dumpstate() { run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL); run_command("LIBRANK", 10, "librank", NULL); - dump_file("BINDER FAILED TRANSACTION LOG", "/proc/binder/failed_transaction_log"); - dump_file("BINDER TRANSACTION LOG", "/proc/binder/transaction_log"); - dump_file("BINDER TRANSACTIONS", "/proc/binder/transactions"); - dump_file("BINDER STATS", "/proc/binder/stats"); - run_command("BINDER PROCESS STATE", 10, "sh", "-c", "cat /proc/binder/proc/*"); + dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log"); + dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log"); + dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions"); + dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats"); + dump_file("BINDER STATE", "/sys/kernel/debug/binder/state"); run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL); @@ -216,10 +216,22 @@ int main(int argc, char *argv[]) { fclose(cmdline); } - /* switch to non-root user and group */ - gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT }; - setgroups(sizeof(groups)/sizeof(groups[0]), groups); - setuid(AID_SHELL); + if (getuid() == 0) { + /* switch to non-root user and group */ + gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT }; + if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { + LOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); + return -1; + } + if (setgid(AID_SHELL) != 0) { + LOGE("Unable to setgid, aborting: %s\n", strerror(errno)); + return -1; + } + if (setuid(AID_SHELL) != 0) { + LOGE("Unable to setuid, aborting: %s\n", strerror(errno)); + return -1; + } + } char path[PATH_MAX], tmp_path[PATH_MAX]; pid_t gzip_pid = -1; diff --git a/cmds/input/input b/cmds/input/input index fa9dced..fa9dced 100644..100755 --- a/cmds/input/input +++ b/cmds/input/input diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 41f070c..2f03c7a 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -16,7 +16,7 @@ #include "installd.h" -int install(const char *pkgname, uid_t uid, gid_t gid) +int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid) { char pkgdir[PKG_PATH_MAX]; char libdir[PKG_PATH_MAX]; @@ -24,14 +24,19 @@ int install(const char *pkgname, uid_t uid, gid_t gid) if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { LOGE("invalid uid/gid: %d %d\n", uid, gid); return -1; - } - if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) - return -1; - if (create_pkg_path(libdir, PKG_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX)) - return -1; - + if (encrypted_fs_flag == USE_UNENCRYPTED_FS) { + if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + if (create_pkg_path(libdir, PKG_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX)) + return -1; + } else { + if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + if (create_pkg_path(libdir, PKG_SEC_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX)) + return -1; + } if (mkdir(pkgdir, 0751) < 0) { LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); @@ -56,27 +61,38 @@ int install(const char *pkgname, uid_t uid, gid_t gid) return 0; } -int uninstall(const char *pkgname) +int uninstall(const char *pkgname, int encrypted_fs_flag) { char pkgdir[PKG_PATH_MAX]; - if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) - return -1; + if (encrypted_fs_flag == USE_UNENCRYPTED_FS) { + if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + } else { + if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + } /* delete contents AND directory, no exceptions */ return delete_dir_contents(pkgdir, 1, 0); } -int renamepkg(const char *oldpkgname, const char *newpkgname) +int renamepkg(const char *oldpkgname, const char *newpkgname, int encrypted_fs_flag) { char oldpkgdir[PKG_PATH_MAX]; char newpkgdir[PKG_PATH_MAX]; - if (create_pkg_path(oldpkgdir, PKG_DIR_PREFIX, oldpkgname, PKG_DIR_POSTFIX)) - return -1; - if (create_pkg_path(newpkgdir, PKG_DIR_PREFIX, newpkgname, PKG_DIR_POSTFIX)) - return -1; - + if (encrypted_fs_flag == USE_UNENCRYPTED_FS) { + if (create_pkg_path(oldpkgdir, PKG_DIR_PREFIX, oldpkgname, PKG_DIR_POSTFIX)) + return -1; + if (create_pkg_path(newpkgdir, PKG_DIR_PREFIX, newpkgname, PKG_DIR_POSTFIX)) + return -1; + } else { + if (create_pkg_path(oldpkgdir, PKG_SEC_DIR_PREFIX, oldpkgname, PKG_DIR_POSTFIX)) + return -1; + if (create_pkg_path(newpkgdir, PKG_SEC_DIR_PREFIX, newpkgname, PKG_DIR_POSTFIX)) + return -1; + } if (rename(oldpkgdir, newpkgdir) < 0) { LOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno)); @@ -85,35 +101,48 @@ int renamepkg(const char *oldpkgname, const char *newpkgname) return 0; } -int delete_user_data(const char *pkgname) +int delete_user_data(const char *pkgname, int encrypted_fs_flag) { char pkgdir[PKG_PATH_MAX]; - if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) - return -1; + if (encrypted_fs_flag == USE_UNENCRYPTED_FS) { + if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + } else { + if (create_pkg_path(pkgdir, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + } /* delete contents, excluding "lib", but not the directory itself */ return delete_dir_contents(pkgdir, 0, "lib"); } -int delete_cache(const char *pkgname) +int delete_cache(const char *pkgname, int encrypted_fs_flag) { char cachedir[PKG_PATH_MAX]; - if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX)) - return -1; - + if (encrypted_fs_flag == USE_UNENCRYPTED_FS) { + if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX)) + return -1; + } else { + if (create_pkg_path(cachedir, CACHE_SEC_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX)) + return -1; + } /* delete contents, not the directory, no exceptions */ return delete_dir_contents(cachedir, 0, 0); } -static int disk_free() +/* TODO(oam): depending on use case (ecryptfs or dmcrypt) + * change implementation + */ +static int64_t disk_free() { struct statfs sfs; if (statfs(PKG_DIR_PREFIX, &sfs) == 0) { return sfs.f_bavail * sfs.f_bsize; } else { + LOGE("Couldn't statfs " PKG_DIR_PREFIX ": %s\n", strerror(errno)); return -1; } } @@ -125,23 +154,56 @@ static int disk_free() * also require that apps constantly modify file metadata even * when just reading from the cache, which is pretty awful. */ -int free_cache(int free_size) +int free_cache(int64_t free_size) { const char *name; int dfd, subfd; DIR *d; struct dirent *de; - int avail; + int64_t avail; avail = disk_free(); if (avail < 0) return -1; - LOGI("free_cache(%d) avail %d\n", free_size, avail); + LOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail); if (avail >= free_size) return 0; + /* First try encrypted dir */ + d = opendir(PKG_SEC_DIR_PREFIX); + if (d == NULL) { + LOGE("cannot open %s: %s\n", PKG_SEC_DIR_PREFIX, strerror(errno)); + } else { + dfd = dirfd(d); + + while ((de = readdir(d))) { + if (de->d_type != DT_DIR) continue; + name = de->d_name; + + /* always skip "." and ".." */ + if (name[0] == '.') { + if (name[1] == 0) continue; + if ((name[1] == '.') && (name[2] == 0)) continue; + } + + subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); + if (subfd < 0) continue; + + delete_dir_contents_fd(subfd, "cache"); + close(subfd); + + avail = disk_free(); + if (avail >= free_size) { + closedir(d); + return 0; + } + } + closedir(d); + } + + /* Next try unencrypted dir... */ d = opendir(PKG_DIR_PREFIX); if (d == NULL) { - LOGE("cannot open %s\n", PKG_DIR_PREFIX); + LOGE("cannot open %s: %s\n", PKG_DIR_PREFIX, strerror(errno)); return -1; } dfd = dirfd(d); @@ -217,6 +279,7 @@ int move_dex(const char *src, const char *dst) LOGI("move %s -> %s\n", src_dex, dst_dex); if (rename(src_dex, dst_dex) < 0) { + LOGE("Couldn't move %s: %s\n", src_dex, strerror(errno)); return -1; } else { return 0; @@ -232,6 +295,7 @@ int rm_dex(const char *path) LOGI("unlink %s\n", dex_path); if (unlink(dex_path) < 0) { + LOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno)); return -1; } else { return 0; @@ -263,10 +327,10 @@ int protect(char *pkgname, gid_t gid) return 0; } -static int stat_size(struct stat *s) +static int64_t stat_size(struct stat *s) { - int blksize = s->st_blksize; - int size = s->st_size; + int64_t blksize = s->st_blksize; + int64_t size = s->st_size; if (blksize) { /* round up to filesystem block size */ @@ -276,9 +340,9 @@ static int stat_size(struct stat *s) return size; } -static int calculate_dir_size(int dfd) +static int64_t calculate_dir_size(int dfd) { - int size = 0; + int64_t size = 0; struct stat s; DIR *d; struct dirent *de; @@ -314,7 +378,7 @@ static int calculate_dir_size(int dfd) int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath, - int *_codesize, int *_datasize, int *_cachesize) + int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize, int encrypted_fs_flag) { DIR *d; int dfd; @@ -322,9 +386,9 @@ int get_size(const char *pkgname, const char *apkpath, struct stat s; char path[PKG_PATH_MAX]; - int codesize = 0; - int datasize = 0; - int cachesize = 0; + int64_t codesize = 0; + int64_t datasize = 0; + int64_t cachesize = 0; /* count the source apk as code -- but only if it's not * on the /system partition and its not on the sdcard. @@ -349,8 +413,14 @@ int get_size(const char *pkgname, const char *apkpath, } } - if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) { - goto done; + if (encrypted_fs_flag == 0) { + if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) { + goto done; + } + } else { + if (create_pkg_path(path, PKG_SEC_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) { + goto done; + } } d = opendir(path); @@ -375,7 +445,7 @@ int get_size(const char *pkgname, const char *apkpath, } subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); if (subfd >= 0) { - int size = calculate_dir_size(subfd); + int64_t size = calculate_dir_size(subfd); if (!strcmp(name,"lib")) { codesize += size; } else if(!strcmp(name,"cache")) { @@ -866,3 +936,155 @@ int movefiles() done: return 0; } + +int linklib(const char* dataDir, const char* asecLibDir) +{ + char libdir[PKG_PATH_MAX]; + struct stat s, libStat; + int rc = 0; + + const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX); + if (libdirLen >= PKG_PATH_MAX) { + LOGE("library dir len too large"); + return -1; + } + + if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) { + LOGE("library dir not written successfully: %s\n", strerror(errno)); + return -1; + } + + if (stat(dataDir, &s) < 0) return -1; + + if (chown(dataDir, 0, 0) < 0) { + LOGE("failed to chown '%s': %s\n", dataDir, strerror(errno)); + return -1; + } + + if (chmod(dataDir, 0700) < 0) { + LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno)); + rc = -1; + goto out; + } + + if (lstat(libdir, &libStat) < 0) { + LOGE("couldn't stat lib dir: %s\n", strerror(errno)); + rc = -1; + goto out; + } + + if (S_ISDIR(libStat.st_mode)) { + if (delete_dir_contents(libdir, 1, 0) < 0) { + rc = -1; + goto out; + } + } else if (S_ISLNK(libStat.st_mode)) { + if (unlink(libdir) < 0) { + rc = -1; + goto out; + } + } + + if (symlink(asecLibDir, libdir) < 0) { + LOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno)); + rc = -errno; + goto out; + } + + if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) { + LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno)); + unlink(libdir); + rc = -errno; + goto out; + } + +out: + if (chmod(dataDir, s.st_mode) < 0) { + LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno)); + return -errno; + } + + if (chown(dataDir, s.st_uid, s.st_gid) < 0) { + LOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno)); + return -errno; + } + + return rc; +} + +int unlinklib(const char* dataDir) +{ + char libdir[PKG_PATH_MAX]; + struct stat s, libStat; + int rc = 0; + + const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX); + if (libdirLen >= PKG_PATH_MAX) { + return -1; + } + + if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) { + LOGE("library dir not written successfully: %s\n", strerror(errno)); + return -1; + } + + if (stat(dataDir, &s) < 0) { + LOGE("couldn't state data dir"); + return -1; + } + + if (chown(dataDir, 0, 0) < 0) { + LOGE("failed to chown '%s': %s\n", dataDir, strerror(errno)); + return -1; + } + + if (chmod(dataDir, 0700) < 0) { + LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno)); + rc = -1; + goto out; + } + + if (lstat(libdir, &libStat) < 0) { + LOGE("couldn't stat lib dir: %s\n", strerror(errno)); + rc = -1; + goto out; + } + + if (S_ISDIR(libStat.st_mode)) { + if (delete_dir_contents(libdir, 1, 0) < 0) { + rc = -1; + goto out; + } + } else if (S_ISLNK(libStat.st_mode)) { + if (unlink(libdir) < 0) { + rc = -1; + goto out; + } + } + + if (mkdir(libdir, 0755) < 0) { + LOGE("cannot create dir '%s': %s\n", libdir, strerror(errno)); + rc = -errno; + goto out; + } + + if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) { + LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno)); + unlink(libdir); + rc = -errno; + goto out; + } + +out: + if (chmod(dataDir, s.st_mode) < 0) { + LOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno)); + return -1; + } + + if (chown(dataDir, s.st_uid, s.st_gid) < 0) { + LOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno)); + return -1; + } + + return rc; +} diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index f6ca998..9ba6402 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -29,7 +29,7 @@ static int do_ping(char **arg, char reply[REPLY_MAX]) static int do_install(char **arg, char reply[REPLY_MAX]) { - return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */ + return install(arg[0], atoi(arg[1]), atoi(arg[2]), atoi(arg[3])); /* pkgname, uid, gid */ } static int do_dexopt(char **arg, char reply[REPLY_MAX]) @@ -50,22 +50,22 @@ static int do_rm_dex(char **arg, char reply[REPLY_MAX]) static int do_remove(char **arg, char reply[REPLY_MAX]) { - return uninstall(arg[0]); /* pkgname */ + return uninstall(arg[0], atoi(arg[1])); /* pkgname */ } static int do_rename(char **arg, char reply[REPLY_MAX]) { - return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */ + return renamepkg(arg[0], arg[1], atoi(arg[2])); /* oldpkgname, newpkgname */ } static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */ { - return free_cache(atoi(arg[0])); /* free_size */ + return free_cache((int64_t)atoll(arg[0])); /* free_size */ } static int do_rm_cache(char **arg, char reply[REPLY_MAX]) { - return delete_cache(arg[0]); /* pkgname */ + return delete_cache(arg[0], atoi(arg[1])); /* pkgname */ } static int do_protect(char **arg, char reply[REPLY_MAX]) @@ -75,21 +75,25 @@ static int do_protect(char **arg, char reply[REPLY_MAX]) static int do_get_size(char **arg, char reply[REPLY_MAX]) { - int codesize = 0; - int datasize = 0; - int cachesize = 0; + int64_t codesize = 0; + int64_t datasize = 0; + int64_t cachesize = 0; int res = 0; /* pkgdir, apkpath */ - res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize); + res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize, atoi(arg[3])); - sprintf(reply,"%d %d %d", codesize, datasize, cachesize); + /* + * Each int64_t can take up 22 characters printed out. Make sure it + * doesn't go over REPLY_MAX in the future. + */ + snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64, codesize, datasize, cachesize); return res; } static int do_rm_user_data(char **arg, char reply[REPLY_MAX]) { - return delete_user_data(arg[0]); /* pkgname */ + return delete_user_data(arg[0], atoi(arg[1])); /* pkgname */ } static int do_movefiles(char **arg, char reply[REPLY_MAX]) @@ -97,6 +101,16 @@ static int do_movefiles(char **arg, char reply[REPLY_MAX]) return movefiles(); } +static int do_linklib(char **arg, char reply[REPLY_MAX]) +{ + return linklib(arg[0], arg[1]); +} + +static int do_unlinklib(char **arg, char reply[REPLY_MAX]) +{ + return unlinklib(arg[0]); +} + struct cmdinfo { const char *name; unsigned numargs; @@ -105,18 +119,20 @@ struct cmdinfo { struct cmdinfo cmds[] = { { "ping", 0, do_ping }, - { "install", 3, do_install }, + { "install", 4, do_install }, { "dexopt", 3, do_dexopt }, { "movedex", 2, do_move_dex }, { "rmdex", 1, do_rm_dex }, - { "remove", 1, do_remove }, - { "rename", 2, do_rename }, + { "remove", 2, do_remove }, + { "rename", 3, do_rename }, { "freecache", 1, do_free_cache }, - { "rmcache", 1, do_rm_cache }, + { "rmcache", 2, do_rm_cache }, { "protect", 2, do_protect }, - { "getsize", 3, do_get_size }, - { "rmuserdata", 1, do_rm_user_data }, + { "getsize", 4, do_get_size }, + { "rmuserdata", 2, do_rm_user_data }, { "movefiles", 0, do_movefiles }, + { "linklib", 2, do_linklib }, + { "unlinklib", 1, do_unlinklib }, }; static int readx(int s, void *_buf, int count) diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index cfcdb98..59475e9 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -19,6 +19,8 @@ #include <stdio.h> #include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> #include <sys/stat.h> #include <dirent.h> #include <unistd.h> @@ -48,16 +50,23 @@ /* elements combined with a valid package name to form paths */ #define PKG_DIR_PREFIX "/data/data/" +#define PKG_SEC_DIR_PREFIX "/data/secure/data/" #define PKG_DIR_POSTFIX "" #define PKG_LIB_PREFIX "/data/data/" +#define PKG_SEC_LIB_PREFIX "/data/secure/data/" #define PKG_LIB_POSTFIX "/lib" #define CACHE_DIR_PREFIX "/data/data/" +#define CACHE_SEC_DIR_PREFIX "/data/secure/data/" #define CACHE_DIR_POSTFIX "/cache" #define APK_DIR_PREFIX "/data/app/" +/* Encrypted File SYstems constants */ +#define USE_ENCRYPTED_FS 1 +#define USE_UNENCRYPTED_FS 0 + /* other handy constants */ #define PROTECTED_DIR_PREFIX "/data/app-private/" @@ -89,16 +98,18 @@ int delete_dir_contents_fd(int dfd, const char *name); /* commands.c */ -int install(const char *pkgname, uid_t uid, gid_t gid); -int uninstall(const char *pkgname); -int renamepkg(const char *oldpkgname, const char *newpkgname); -int delete_user_data(const char *pkgname); -int delete_cache(const char *pkgname); +int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid); +int uninstall(const char *pkgname, int encrypted_fs_flag); +int renamepkg(const char *oldpkgname, const char *newpkgname, int encrypted_fs_flag); +int delete_user_data(const char *pkgname, int encrypted_fs_flag); +int delete_cache(const char *pkgname, int encrypted_fs_flag); int move_dex(const char *src, const char *dst); int rm_dex(const char *path); int protect(char *pkgname, gid_t gid); int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath, - int *codesize, int *datasize, int *cachesize); -int free_cache(int free_size); + int64_t *codesize, int64_t *datasize, int64_t *cachesize, int encrypted_fs_flag); +int free_cache(int64_t free_size); int dexopt(const char *apk_path, uid_t uid, int is_public); int movefiles(); +int linklib(const char* target, const char* source); +int unlinklib(const char* libPath); diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c index 555c19e..a5e4b5a 100644 --- a/cmds/installd/utils.c +++ b/cmds/installd/utils.c @@ -98,11 +98,13 @@ static int _delete_dir_contents(DIR *d, const char *ignore) subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); if (subfd < 0) { + LOGE("Couldn't openat %s: %s\n", name, strerror(errno)); result = -1; continue; } subdir = fdopendir(subfd); if (subdir == NULL) { + LOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); close(subfd); result = -1; continue; @@ -112,10 +114,12 @@ static int _delete_dir_contents(DIR *d, const char *ignore) } closedir(subdir); if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { + LOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); result = -1; } } else { if (unlinkat(dfd, name, 0) < 0) { + LOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); result = -1; } } @@ -133,12 +137,14 @@ int delete_dir_contents(const char *pathname, d = opendir(pathname); if (d == NULL) { + LOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno)); return -errno; } res = _delete_dir_contents(d, ignore); closedir(d); if (also_delete_dir) { if (rmdir(pathname)) { + LOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno)); res = -1; } } @@ -152,10 +158,12 @@ int delete_dir_contents_fd(int dfd, const char *name) fd = openat(dfd, name, O_RDONLY | O_DIRECTORY); if (fd < 0) { + LOGE("Couldn't openat %s: %s\n", name, strerror(errno)); return -1; } d = fdopendir(fd); if (d == NULL) { + LOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); close(fd); return -1; } diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c index 60cc521..afa64f8 100644 --- a/cmds/keystore/keystore.c +++ b/cmds/keystore/keystore.c @@ -143,15 +143,20 @@ static void send_message(uint8_t *message, int length) send(the_socket, message, length, 0); } -/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to - * compute their checksums. To make the files portable, the length is stored in - * network order. Note that the first four bytes are reserved for future use and - * are always set to zero in this implementation. */ +/* Here is the file format. There are two parts in blob.value, the secret and + * the description. The secret is stored in ciphertext, and its original size + * can be found in blob.length. The description is stored after the secret in + * plaintext, and its size is specified in blob.info. The total size of the two + * parts must be no more than VALUE_SIZE bytes. The first three bytes of the + * file are reserved for future use and are always set to zero. Fields other + * than blob.info, blob.length, and blob.value are modified by encrypt_blob() + * and decrypt_blob(). Thus they should not be accessed from outside. */ static int the_entropy = -1; static struct __attribute__((packed)) { - uint32_t reserved; + uint8_t reserved[3]; + uint8_t info; uint8_t vector[AES_BLOCK_SIZE]; uint8_t encrypted[0]; uint8_t digest[MD5_DIGEST_LENGTH]; @@ -166,13 +171,17 @@ static int8_t encrypt_blob(char *name, AES_KEY *aes_key) int length; int fd; - if (read(the_entropy, vector, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) { + if (read(the_entropy, blob.vector, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) { return SYSTEM_ERROR; } - length = blob.length + blob.value - blob.encrypted; + length = blob.length + (blob.value - blob.encrypted); length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE; + if (blob.info != 0) { + memmove(&blob.encrypted[length], &blob.value[blob.length], blob.info); + } + blob.length = htonl(blob.length); MD5(blob.digested, length - (blob.digested - blob.encrypted), blob.digest); @@ -180,8 +189,8 @@ static int8_t encrypt_blob(char *name, AES_KEY *aes_key) AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector, AES_ENCRYPT); - blob.reserved = 0; - length += blob.encrypted - (uint8_t *)&blob; + memset(blob.reserved, 0, sizeof(blob.reserved)); + length += (blob.encrypted - (uint8_t *)&blob) + blob.info; fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); length -= write(fd, &blob, length); @@ -200,7 +209,7 @@ static int8_t decrypt_blob(char *name, AES_KEY *aes_key) length = read(fd, &blob, sizeof(blob)); close(fd); - length -= blob.encrypted - (uint8_t *)&blob; + length -= (blob.encrypted - (uint8_t *)&blob) + blob.info; if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) { return VALUE_CORRUPTED; } @@ -215,8 +224,13 @@ static int8_t decrypt_blob(char *name, AES_KEY *aes_key) length -= blob.value - blob.digested; blob.length = ntohl(blob.length); - return (blob.length < 0 || blob.length > length) ? VALUE_CORRUPTED : - NO_ERROR; + if (blob.length < 0 || blob.length > length) { + return VALUE_CORRUPTED; + } + if (blob.info != 0) { + memmove(&blob.value[blob.length], &blob.value[length], blob.info); + } + return NO_ERROR; } /* Here are the actions. Each of them is a function without arguments. All @@ -266,6 +280,7 @@ static int8_t insert() char name[NAME_MAX]; int n = sprintf(name, "%u_", uid); encode_key(&name[n], params[0].value, params[0].length); + blob.info = 0; blob.length = params[1].length; memcpy(blob.value, params[1].value, params[1].length); return encrypt_blob(name, &encryption_key); @@ -336,56 +351,88 @@ static int8_t reset() #define MASTER_KEY_FILE ".masterkey" #define MASTER_KEY_SIZE 16 +#define SALT_SIZE 16 -static void generate_key(uint8_t *key, uint8_t *password, int length) +static void set_key(uint8_t *key, uint8_t *password, int length, uint8_t *salt) { - PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore", - sizeof("keystore"), 1024, MASTER_KEY_SIZE, key); + if (salt) { + PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, salt, SALT_SIZE, + 8192, MASTER_KEY_SIZE, key); + } else { + PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore", + sizeof("keystore"), 1024, MASTER_KEY_SIZE, key); + } } +/* Here is the history. To improve the security, the parameters to generate the + * master key has been changed. To make a seamless transition, we update the + * file using the same password when the user unlock it for the first time. If + * any thing goes wrong during the transition, the new file will not overwrite + * the old one. This avoids permanent damages of the existing data. */ + static int8_t password() { uint8_t key[MASTER_KEY_SIZE]; AES_KEY aes_key; - int n; + int8_t response = SYSTEM_ERROR; if (state == UNINITIALIZED) { - blob.length = MASTER_KEY_SIZE; if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) { return SYSTEM_ERROR; } } else { - generate_key(key, params[0].value, params[0].length); + int fd = open(MASTER_KEY_FILE, O_RDONLY); + uint8_t *salt = NULL; + if (fd != -1) { + int length = read(fd, &blob, sizeof(blob)); + close(fd); + if (length > SALT_SIZE && blob.info == SALT_SIZE) { + salt = (uint8_t *)&blob + length - SALT_SIZE; + } + } + + set_key(key, params[0].value, params[0].length, salt); AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key); - n = decrypt_blob(MASTER_KEY_FILE, &aes_key); - if (n == SYSTEM_ERROR) { + response = decrypt_blob(MASTER_KEY_FILE, &aes_key); + if (response == SYSTEM_ERROR) { return SYSTEM_ERROR; } - if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) { + if (response != NO_ERROR || blob.length != MASTER_KEY_SIZE) { if (retry <= 0) { reset(); return UNINITIALIZED; } return WRONG_PASSWORD + --retry; } + + if (!salt && params[1].length == -1) { + params[1] = params[0]; + } } if (params[1].length == -1) { memcpy(key, blob.value, MASTER_KEY_SIZE); } else { - generate_key(key, params[1].value, params[1].length); + uint8_t *salt = &blob.value[MASTER_KEY_SIZE]; + if (read(the_entropy, salt, SALT_SIZE) != SALT_SIZE) { + return SYSTEM_ERROR; + } + + set_key(key, params[1].value, params[1].length, salt); AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key); memcpy(key, blob.value, MASTER_KEY_SIZE); - n = encrypt_blob(MASTER_KEY_FILE, &aes_key); + blob.info = SALT_SIZE; + blob.length = MASTER_KEY_SIZE; + response = encrypt_blob(MASTER_KEY_FILE, &aes_key); } - if (n == NO_ERROR) { + if (response == NO_ERROR) { AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key); AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key); state = NO_ERROR; retry = MAX_RETRY; } - return n; + return response; } static int8_t lock() diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h index 141f69b..4b4923e 100644 --- a/cmds/keystore/keystore_get.h +++ b/cmds/keystore/keystore_get.h @@ -32,7 +32,7 @@ extern "C" { #endif /* This function is provided for native components to get values from keystore. - * Users are required to link against libcutils. Keys are values are 8-bit safe. + * Users are required to link against libcutils. Keys and values are 8-bit safe. * The first two arguments are the key and its length. The third argument * specifies the buffer to store the retrieved value, which must be an array of * KEYSTORE_MESSAGE_SIZE bytes. This function returns the length of the value or @@ -65,7 +65,10 @@ static int keystore_get(const char *key, int length, char *value) } offset += n; } + } else { + length = -1; } + close(sock); return length; } diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk new file mode 100644 index 0000000..1a6e23e --- /dev/null +++ b/cmds/screencap/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + screencap.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libbinder \ + libui \ + libsurfaceflinger_client + +LOCAL_MODULE:= screencap + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_EXECUTABLE) diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp new file mode 100644 index 0000000..bc5e10d --- /dev/null +++ b/cmds/screencap/screencap.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <unistd.h> +#include <fcntl.h> + +#include <binder/IMemory.h> +#include <surfaceflinger/SurfaceComposerClient.h> + +using namespace android; + +int main(int argc, char** argv) +{ + ScreenshotClient screenshot; + if (screenshot.update() != NO_ERROR) + return 0; + + void const* base = screenshot.getPixels(); + uint32_t w = screenshot.getWidth(); + uint32_t h = screenshot.getHeight(); + uint32_t f = screenshot.getFormat(); + int fd = dup(STDOUT_FILENO); + write(fd, &w, 4); + write(fd, &h, 4); + write(fd, &f, 4); + write(fd, base, w*h*4); + close(fd); + return 0; +} diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c index 6dee816..ff5aced 100644 --- a/cmds/servicemanager/bctest.c +++ b/cmds/servicemanager/bctest.c @@ -14,6 +14,7 @@ void *svcmgr_lookup(struct binder_state *bs, void *target, const char *name) struct binder_io msg, reply; bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_uint32(&msg, 0); // strict mode header bio_put_string16_x(&msg, SVC_MGR_NAME); bio_put_string16_x(&msg, name); @@ -37,7 +38,7 @@ int svcmgr_publish(struct binder_state *bs, void *target, const char *name, void struct binder_io msg, reply; bio_init(&msg, iodata, sizeof(iodata), 4); - + bio_put_uint32(&msg, 0); // strict mode header bio_put_string16_x(&msg, SVC_MGR_NAME); bio_put_string16_x(&msg, name); bio_put_obj(&msg, ptr); diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index c46901b6..14536bd 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -36,12 +36,14 @@ static struct { { AID_MEDIA, "media.audio_policy" }, { AID_DRMIO, "drm.drmIOService" }, { AID_DRM, "drm.drmManager" }, + { AID_NFC, "nfc" }, { AID_RADIO, "radio.phone" }, { AID_RADIO, "radio.sms" }, { AID_RADIO, "radio.phonesubinfo" }, { AID_RADIO, "radio.simphonebook" }, /* TODO: remove after phone services are updated: */ { AID_RADIO, "phone" }, + { AID_RADIO, "sip" }, { AID_RADIO, "isms" }, { AID_RADIO, "iphonesubinfo" }, { AID_RADIO, "simphonebook" }, @@ -195,6 +197,7 @@ int svcmgr_handler(struct binder_state *bs, uint16_t *s; unsigned len; void *ptr; + uint32_t strict_policy; // LOGI("target=%p code=%d pid=%d uid=%d\n", // txn->target, txn->code, txn->sender_pid, txn->sender_euid); @@ -202,8 +205,12 @@ int svcmgr_handler(struct binder_state *bs, if (txn->target != svcmgr_handle) return -1; + // Equivalent to Parcel::enforceInterface(), reading the RPC + // header with the strict mode policy mask and the interface name. + // Note that we ignore the strict_policy and don't propagate it + // further (since we do no outbound RPCs anyway). + strict_policy = bio_get_uint32(msg); s = bio_get_string16(msg, &len); - if ((len != (sizeof(svcmgr_id) / 2)) || memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { fprintf(stderr,"invalid id %s\n", str8(s)); diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk index 34648b5..5b74007 100644 --- a/cmds/stagefright/Android.mk +++ b/cmds/stagefright/Android.mk @@ -1,5 +1,3 @@ -ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true) - LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) @@ -9,12 +7,13 @@ LOCAL_SRC_FILES:= \ SineSource.cpp LOCAL_SHARED_LIBRARIES := \ - libstagefright libmedia libutils libbinder + libstagefright libmedia libutils libbinder libstagefright_foundation LOCAL_C_INCLUDES:= \ $(JNI_H_INCLUDE) \ frameworks/base/media/libstagefright \ - $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include + frameworks/base/media/libstagefright/include \ + $(TOP)/frameworks/base/include/media/stagefright/openmax LOCAL_CFLAGS += -Wno-multichar @@ -38,7 +37,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ $(JNI_H_INCLUDE) \ frameworks/base/media/libstagefright \ - $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include + $(TOP)/frameworks/base/include/media/stagefright/openmax LOCAL_CFLAGS += -Wno-multichar @@ -62,7 +61,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ $(JNI_H_INCLUDE) \ frameworks/base/media/libstagefright \ - $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include + $(TOP)/frameworks/base/include/media/stagefright/openmax LOCAL_CFLAGS += -Wno-multichar @@ -71,5 +70,3 @@ LOCAL_MODULE_TAGS := debug LOCAL_MODULE:= audioloop include $(BUILD_EXECUTABLE) - -endif diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index 845c854..b718299 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -32,22 +32,34 @@ using namespace android; +static const int32_t kFramerate = 24; // fps +static const int32_t kIFramesIntervalSec = 1; +static const int32_t kVideoBitRate = 512 * 1024; +static const int32_t kAudioBitRate = 12200; +static const int64_t kDurationUs = 10000000LL; // 10 seconds + #if 1 class DummySource : public MediaSource { - static const int32_t kFramerate = 24; // fps public: - DummySource(int width, int height) + DummySource(int width, int height, int colorFormat) : mWidth(width), mHeight(height), + mColorFormat(colorFormat), mSize((width * height * 3) / 2) { mGroup.add_buffer(new MediaBuffer(mSize)); + + // Check the color format to make sure + // that the buffer size mSize it set correctly above. + CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar || + colorFormat == OMX_COLOR_FormatYUV420Planar); } virtual sp<MetaData> getFormat() { sp<MetaData> meta = new MetaData; meta->setInt32(kKeyWidth, mWidth); meta->setInt32(kKeyHeight, mHeight); + meta->setInt32(kKeyColorFormat, mColorFormat); meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); return meta; @@ -94,6 +106,7 @@ protected: private: MediaBufferGroup mGroup; int mWidth, mHeight; + int mColorFormat; size_t mSize; int64_t mNumFramesOutput;; @@ -133,21 +146,48 @@ sp<MediaSource> createSource(const char *filename) { return source; } +enum { + kYUV420SP = 0, + kYUV420P = 1, +}; + +// returns -1 if mapping of the given color is unsuccessful +// returns an omx color enum value otherwise +static int translateColorToOmxEnumValue(int color) { + switch (color) { + case kYUV420SP: + return OMX_COLOR_FormatYUV420SemiPlanar; + case kYUV420P: + return OMX_COLOR_FormatYUV420Planar; + default: + fprintf(stderr, "Unsupported color: %d\n", color); + return -1; + } +} + int main(int argc, char **argv) { android::ProcessState::self()->startThreadPool(); DataSource::RegisterDefaultSniffers(); #if 1 - if (argc != 2) { - fprintf(stderr, "usage: %s filename\n", argv[0]); + if (argc != 3) { + fprintf(stderr, "usage: %s <filename> <input_color_format>\n", argv[0]); + fprintf(stderr, " <input_color_format>: 0 (YUV420SP) or 1 (YUV420P)\n"); return 1; } + int colorFormat = translateColorToOmxEnumValue(atoi(argv[2])); + if (colorFormat == -1) { + fprintf(stderr, "input color format must be 0 (YUV420SP) or 1 (YUV420P)\n"); + return 1; + } OMXClient client; CHECK_EQ(client.connect(), OK); -#if 1 + status_t err = OK; + +#if 0 sp<MediaSource> source = createSource(argv[1]); if (source == NULL) { @@ -165,16 +205,23 @@ int main(int argc, char **argv) { success = success && meta->findInt32(kKeyHeight, &height); CHECK(success); #else - int width = 800; + int width = 720; int height = 480; - sp<MediaSource> decoder = new DummySource(width, height); + sp<MediaSource> decoder = new DummySource(width, height, colorFormat); #endif sp<MetaData> enc_meta = new MetaData; // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); enc_meta->setInt32(kKeyWidth, width); enc_meta->setInt32(kKeyHeight, height); + enc_meta->setInt32(kKeySampleRate, kFramerate); + enc_meta->setInt32(kKeyBitRate, kVideoBitRate); + enc_meta->setInt32(kKeyStride, width); + enc_meta->setInt32(kKeySliceHeight, height); + enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec); + enc_meta->setInt32(kKeyColorFormat, colorFormat); sp<MediaSource> encoder = OMXCodec::Create( @@ -183,16 +230,20 @@ int main(int argc, char **argv) { #if 1 sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4"); writer->addSource(encoder); - writer->start(); + writer->setMaxFileDuration(kDurationUs); + CHECK_EQ(OK, writer->start()); while (!writer->reachedEOS()) { + fprintf(stderr, "."); usleep(100000); } - writer->stop(); + err = writer->stop(); #else - encoder->start(); + CHECK_EQ(OK, encoder->start()); MediaBuffer *buffer; while (encoder->read(&buffer) == OK) { + printf("."); + fflush(stdout); int32_t isSync; if (!buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)) { isSync = false; @@ -205,14 +256,17 @@ int main(int argc, char **argv) { buffer = NULL; } - encoder->stop(); + err = encoder->stop(); #endif + printf("$\n"); client.disconnect(); #endif #if 0 CameraSource *source = CameraSource::Create(); + source->start(); + printf("source = %p\n", source); for (int i = 0; i < 100; ++i) { @@ -227,10 +281,16 @@ int main(int argc, char **argv) { buffer = NULL; } + err = source->stop(); + delete source; source = NULL; #endif + if (err != OK && err != ERROR_END_OF_STREAM) { + fprintf(stderr, "record failed: %d\n", err); + return 1; + } return 0; } #else @@ -262,6 +322,7 @@ int main(int argc, char **argv) { encMeta->setInt32(kKeySampleRate, kSampleRate); encMeta->setInt32(kKeyChannelCount, kNumChannels); encMeta->setInt32(kKeyMaxInputSize, 8192); + encMeta->setInt32(kKeyBitRate, kAudioBitRate); sp<MediaSource> encoder = OMXCodec::Create(client.interface(), encMeta, true, audioSource); diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index b838f32..f55b746 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "stagefright" +#include <media/stagefright/foundation/ADebug.h> + #include <sys/time.h> #include <stdlib.h> @@ -25,13 +29,15 @@ #include <binder/IServiceManager.h> #include <binder/ProcessState.h> #include <media/IMediaPlayerService.h> +#include <media/stagefright/foundation/ALooper.h> +#include "include/ARTSPController.h" +#include "include/LiveSource.h" +#include "include/NuCachedSource2.h" #include <media/stagefright/AudioPlayer.h> -#include <media/stagefright/CachingDataSource.h> -#include <media/stagefright/FileSource.h> -#include <media/stagefright/HTTPDataSource.h> +#include <media/stagefright/DataSource.h> #include <media/stagefright/JPEGSource.h> -#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> #include <media/stagefright/MediaExtractor.h> #include <media/stagefright/MediaSource.h> #include <media/stagefright/MetaData.h> @@ -39,6 +45,12 @@ #include <media/stagefright/OMXCodec.h> #include <media/mediametadataretriever.h> +#include <media/stagefright/foundation/hexdump.h> +#include <media/stagefright/MPEG2TSWriter.h> +#include <media/stagefright/MPEG4Writer.h> + +#include <fcntl.h> + using namespace android; static long gNumRepetitions; @@ -46,6 +58,8 @@ static long gMaxNumFrames; // 0 means decode all available. static long gReproduceBug; // if not -1. static bool gPreferSoftwareCodec; static bool gPlaybackAudio; +static bool gWriteMP4; +static String8 gWriteMP4Filename; static int64_t getNowUs() { struct timeval tv; @@ -54,7 +68,7 @@ static int64_t getNowUs() { return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll; } -static void playSource(OMXClient *client, const sp<MediaSource> &source) { +static void playSource(OMXClient *client, sp<MediaSource> &source) { sp<MetaData> meta = source->getFormat(); const char *mime; @@ -75,6 +89,8 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) { } } + source.clear(); + status_t err = rawSource->start(); if (err != OK) { @@ -85,6 +101,7 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) { if (gPlaybackAudio) { AudioPlayer *player = new AudioPlayer(NULL); player->setSource(rawSource); + rawSource.clear(); player->start(true /* sourceAlreadyStarted */); @@ -95,6 +112,8 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) { delete player; player = NULL; + + return; } else if (gReproduceBug >= 3 && gReproduceBug <= 5) { int64_t durationUs; CHECK(meta->findInt64(kKeyDuration, &durationUs)); @@ -109,7 +128,7 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) { bool shouldSeek = false; if (err == INFO_FORMAT_CHANGED) { - CHECK_EQ(buffer, NULL); + CHECK(buffer == NULL); printf("format changed.\n"); continue; @@ -195,7 +214,7 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) { options.clearSeekTo(); if (err != OK) { - CHECK_EQ(buffer, NULL); + CHECK(buffer == NULL); if (err == INFO_FORMAT_CHANGED) { printf("format changed.\n"); @@ -256,6 +275,183 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) { } } +//////////////////////////////////////////////////////////////////////////////// + +struct DetectSyncSource : public MediaSource { + DetectSyncSource(const sp<MediaSource> &source); + + virtual status_t start(MetaData *params = NULL); + virtual status_t stop(); + virtual sp<MetaData> getFormat(); + + virtual status_t read( + MediaBuffer **buffer, const ReadOptions *options); + +private: + enum StreamType { + AVC, + MPEG4, + H263, + OTHER, + }; + + sp<MediaSource> mSource; + StreamType mStreamType; + + DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource); +}; + +DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source) + : mSource(source), + mStreamType(OTHER) { + const char *mime; + CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + + if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + mStreamType = AVC; + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { + mStreamType = MPEG4; + CHECK(!"sync frame detection not implemented yet for MPEG4"); + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) { + mStreamType = H263; + CHECK(!"sync frame detection not implemented yet for H.263"); + } +} + +status_t DetectSyncSource::start(MetaData *params) { + return mSource->start(params); +} + +status_t DetectSyncSource::stop() { + return mSource->stop(); +} + +sp<MetaData> DetectSyncSource::getFormat() { + return mSource->getFormat(); +} + +static bool isIDRFrame(MediaBuffer *buffer) { + const uint8_t *data = + (const uint8_t *)buffer->data() + buffer->range_offset(); + size_t size = buffer->range_length(); + for (size_t i = 0; i + 3 < size; ++i) { + if (!memcmp("\x00\x00\x01", &data[i], 3)) { + uint8_t nalType = data[i + 3] & 0x1f; + if (nalType == 5) { + return true; + } + } + } + + return false; +} + +status_t DetectSyncSource::read( + MediaBuffer **buffer, const ReadOptions *options) { + status_t err = mSource->read(buffer, options); + + if (err != OK) { + return err; + } + + if (mStreamType == AVC && isIDRFrame(*buffer)) { + (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true); + } else { + (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true); + } + + return OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +static void writeSourcesToMP4( + Vector<sp<MediaSource> > &sources, bool syncInfoPresent) { +#if 0 + sp<MPEG4Writer> writer = + new MPEG4Writer(gWriteMP4Filename.string()); +#else + sp<MPEG2TSWriter> writer = + new MPEG2TSWriter(gWriteMP4Filename.string()); +#endif + + // at most one minute. + writer->setMaxFileDuration(60000000ll); + + for (size_t i = 0; i < sources.size(); ++i) { + sp<MediaSource> source = sources.editItemAt(i); + + CHECK_EQ(writer->addSource( + syncInfoPresent ? source : new DetectSyncSource(source)), + (status_t)OK); + } + + sp<MetaData> params = new MetaData; + params->setInt32(kKeyNotRealTime, true); + CHECK_EQ(writer->start(params.get()), (status_t)OK); + + while (!writer->reachedEOS()) { + usleep(100000); + } + writer->stop(); +} + +static void performSeekTest(const sp<MediaSource> &source) { + CHECK_EQ((status_t)OK, source->start()); + + int64_t durationUs; + CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs)); + + for (int64_t seekTimeUs = 0; seekTimeUs <= durationUs; + seekTimeUs += 60000ll) { + MediaSource::ReadOptions options; + options.setSeekTo( + seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); + + MediaBuffer *buffer; + status_t err; + for (;;) { + err = source->read(&buffer, &options); + + options.clearSeekTo(); + + if (err == INFO_FORMAT_CHANGED) { + CHECK(buffer == NULL); + continue; + } + + if (err != OK) { + CHECK(buffer == NULL); + break; + } + + if (buffer->range_length() > 0) { + break; + } + + CHECK(buffer != NULL); + + buffer->release(); + buffer = NULL; + } + + if (err == OK) { + int64_t timeUs; + CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); + + printf("%lld\t%lld\t%lld\n", seekTimeUs, timeUs, seekTimeUs - timeUs); + + buffer->release(); + buffer = NULL; + } else { + printf("ERROR\n"); + break; + } + } + + CHECK_EQ((status_t)OK, source->stop()); +} + static void usage(const char *me) { fprintf(stderr, "usage: %s\n", me); fprintf(stderr, " -h(elp)\n"); @@ -268,6 +464,8 @@ static void usage(const char *me) { fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n"); fprintf(stderr, " -s(oftware) prefer software codec\n"); fprintf(stderr, " -o playback audio\n"); + fprintf(stderr, " -w(rite) filename (write to .mp4 file)\n"); + fprintf(stderr, " -k seek test\n"); } int main(int argc, char **argv) { @@ -277,14 +475,19 @@ int main(int argc, char **argv) { bool listComponents = false; bool dumpProfiles = false; bool extractThumbnail = false; + bool seekTest = false; gNumRepetitions = 1; gMaxNumFrames = 0; gReproduceBug = -1; gPreferSoftwareCodec = false; gPlaybackAudio = false; + gWriteMP4 = false; + + sp<ALooper> looper; + sp<ARTSPController> rtspController; int res; - while ((res = getopt(argc, argv, "han:lm:b:ptso")) >= 0) { + while ((res = getopt(argc, argv, "han:lm:b:ptsow:k")) >= 0) { switch (res) { case 'a': { @@ -320,6 +523,13 @@ int main(int argc, char **argv) { break; } + case 'w': + { + gWriteMP4 = true; + gWriteMP4Filename.setTo(optarg); + break; + } + case 'p': { dumpProfiles = true; @@ -344,6 +554,12 @@ int main(int argc, char **argv) { break; } + case 'k': + { + seekTest = true; + break; + } + case '?': case 'h': default: @@ -379,10 +595,10 @@ int main(int argc, char **argv) { for (int k = 0; k < argc; ++k) { const char *filename = argv[k]; - CHECK_EQ(retriever->setDataSource(filename), OK); + CHECK_EQ(retriever->setDataSource(filename), (status_t)OK); CHECK_EQ(retriever->setMode( METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL), - OK); + (status_t)OK); sp<IMemory> mem = retriever->captureFrame(); @@ -428,7 +644,7 @@ int main(int argc, char **argv) { Vector<CodecCapabilities> results; CHECK_EQ(QueryCodecs(omx, kMimeTypes[k], true, // queryDecoders - &results), OK); + &results), (status_t)OK); for (size_t i = 0; i < results.size(); ++i) { printf(" decoder '%s' supports ", @@ -477,21 +693,16 @@ int main(int argc, char **argv) { status_t err = client.connect(); for (int k = 0; k < argc; ++k) { + bool syncInfoPresent = true; + const char *filename = argv[k]; - sp<DataSource> dataSource; - if (!strncasecmp("http://", filename, 7)) { - dataSource = new HTTPDataSource(filename); - if (((HTTPDataSource *)dataSource.get())->connect() != OK) { - fprintf(stderr, "failed to connect to HTTP server.\n"); - return -1; - } - dataSource = new CachingDataSource(dataSource, 32 * 1024, 20); - } else { - dataSource = new FileSource(filename); - } + sp<DataSource> dataSource = DataSource::CreateFromURI(filename); - if (dataSource == NULL) { + if (strncasecmp(filename, "sine:", 5) + && strncasecmp(filename, "rtsp://", 7) + && strncasecmp(filename, "httplive://", 11) + && dataSource == NULL) { fprintf(stderr, "Unable to create data source.\n"); return 1; } @@ -503,10 +714,14 @@ int main(int argc, char **argv) { isJPEG = true; } + Vector<sp<MediaSource> > mediaSources; sp<MediaSource> mediaSource; if (isJPEG) { mediaSource = new JPEGSource(dataSource); + if (gWriteMP4) { + mediaSources.push(mediaSource); + } } else if (!strncasecmp("sine:", filename, 5)) { char *end; long sampleRate = strtol(filename + 5, &end, 10); @@ -515,54 +730,131 @@ int main(int argc, char **argv) { sampleRate = 44100; } mediaSource = new SineSource(sampleRate, 1); + if (gWriteMP4) { + mediaSources.push(mediaSource); + } } else { - sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); - if (extractor == NULL) { - fprintf(stderr, "could not create extractor.\n"); - return -1; + sp<MediaExtractor> extractor; + + if (!strncasecmp("rtsp://", filename, 7)) { + if (looper == NULL) { + looper = new ALooper; + looper->start(); + } + + rtspController = new ARTSPController(looper); + status_t err = rtspController->connect(filename); + if (err != OK) { + fprintf(stderr, "could not connect to rtsp server.\n"); + return -1; + } + + extractor = rtspController.get(); + + syncInfoPresent = false; + } else if (!strncasecmp("httplive://", filename, 11)) { + String8 uri("http://"); + uri.append(filename + 11); + + dataSource = new LiveSource(uri.string()); + dataSource = new NuCachedSource2(dataSource); + + extractor = + MediaExtractor::Create( + dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); + + syncInfoPresent = false; + } else { + extractor = MediaExtractor::Create(dataSource); + if (extractor == NULL) { + fprintf(stderr, "could not create extractor.\n"); + return -1; + } } size_t numTracks = extractor->countTracks(); - sp<MetaData> meta; - size_t i; - for (i = 0; i < numTracks; ++i) { - meta = extractor->getTrackMetaData( - i, MediaExtractor::kIncludeExtensiveMetaData); + if (gWriteMP4) { + bool haveAudio = false; + bool haveVideo = false; + for (size_t i = 0; i < numTracks; ++i) { + sp<MediaSource> source = extractor->getTrack(i); + + const char *mime; + CHECK(source->getFormat()->findCString( + kKeyMIMEType, &mime)); + + bool useTrack = false; + if (!haveAudio && !strncasecmp("audio/", mime, 6)) { + haveAudio = true; + useTrack = true; + } else if (!haveVideo && !strncasecmp("video/", mime, 6)) { + haveVideo = true; + useTrack = true; + } - const char *mime; - meta->findCString(kKeyMIMEType, &mime); + if (useTrack) { + mediaSources.push(source); - if (audioOnly && !strncasecmp(mime, "audio/", 6)) { - break; + if (haveAudio && haveVideo) { + break; + } + } } + } else { + sp<MetaData> meta; + size_t i; + for (i = 0; i < numTracks; ++i) { + meta = extractor->getTrackMetaData( + i, MediaExtractor::kIncludeExtensiveMetaData); - if (!audioOnly && !strncasecmp(mime, "video/", 6)) { - break; + const char *mime; + meta->findCString(kKeyMIMEType, &mime); + + if (audioOnly && !strncasecmp(mime, "audio/", 6)) { + break; + } + + if (!audioOnly && !strncasecmp(mime, "video/", 6)) { + break; + } + + meta = NULL; } - meta = NULL; - } + if (meta == NULL) { + fprintf(stderr, + "No suitable %s track found. The '-a' option will " + "target audio tracks only, the default is to target " + "video tracks only.\n", + audioOnly ? "audio" : "video"); + return -1; + } - if (meta == NULL) { - fprintf(stderr, - "No suitable %s track found. The '-a' option will " - "target audio tracks only, the default is to target " - "video tracks only.\n", - audioOnly ? "audio" : "video"); - return -1; - } + int64_t thumbTimeUs; + if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) { + printf("thumbnailTime: %lld us (%.2f secs)\n", + thumbTimeUs, thumbTimeUs / 1E6); + } - int64_t thumbTimeUs; - if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) { - printf("thumbnailTime: %lld us (%.2f secs)\n", - thumbTimeUs, thumbTimeUs / 1E6); + mediaSource = extractor->getTrack(i); } + } - mediaSource = extractor->getTrack(i); + if (gWriteMP4) { + writeSourcesToMP4(mediaSources, syncInfoPresent); + } else if (seekTest) { + performSeekTest(mediaSource); + } else { + playSource(&client, mediaSource); } - playSource(&client, mediaSource); + if (rtspController != NULL) { + rtspController->disconnect(); + rtspController.clear(); + + sleep(3); + } } client.disconnect(); diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp index d650721..78b1007 100644 --- a/cmds/surfaceflinger/main_surfaceflinger.cpp +++ b/cmds/surfaceflinger/main_surfaceflinger.cpp @@ -1,18 +1,25 @@ -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> -#include <utils/Log.h> +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <binder/BinderService.h> #include <SurfaceFlinger.h> using namespace android; -int main(int argc, char** argv) -{ - sp<ProcessState> proc(ProcessState::self()); - sp<IServiceManager> sm = defaultServiceManager(); - LOGI("ServiceManager: %p", sm.get()); - SurfaceFlinger::instantiate(); - ProcessState::self()->startThreadPool(); - IPCThreadState::self()->joinThreadPool(); +int main(int argc, char** argv) { + SurfaceFlinger::publishAndJoinThreadPool(); + return 0; } diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java index d3ec3d9..e1d6619 100644 --- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java +++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java @@ -64,7 +64,7 @@ public class PowerCommand extends Svc.Command { = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE)); try { IBinder lock = new Binder(); - pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power"); + pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power", null); pm.setStayOnSetting(val); pm.releaseWakeLock(lock, 0); } diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk index a880a91..457cbd4 100644 --- a/cmds/system_server/library/Android.mk +++ b/cmds/system_server/library/Android.mk @@ -10,11 +10,13 @@ LOCAL_C_INCLUDES := \ $(base)/services/camera/libcameraservice \ $(base)/services/audioflinger \ $(base)/services/surfaceflinger \ + $(base)/services/sensorservice \ $(base)/media/libmediaplayerservice \ $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ + libsensorservice \ libsurfaceflinger \ libaudioflinger \ libcameraservice \ diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp index 1d57fdc..a29ba73 100644 --- a/cmds/system_server/library/system_init.cpp +++ b/cmds/system_server/library/system_init.cpp @@ -19,6 +19,7 @@ #include <CameraService.h> #include <AudioPolicyService.h> #include <MediaPlayerService.h> +#include <SensorService.h> #include <android_runtime/AndroidRuntime.h> @@ -69,6 +70,9 @@ extern "C" status_t system_init() SurfaceFlinger::instantiate(); } + // Start the sensor service + SensorService::instantiate(); + // On the simulator, audioflinger et al don't get started the // same way as on the device, and we need to start them here if (!proc->supportsProcesses()) { |