summaryrefslogtreecommitdiffstats
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/am/Android.mk17
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java143
-rw-r--r--cmds/app_process/app_main.cpp2
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java12
-rw-r--r--cmds/bootanimation/BootAnimation.cpp25
-rw-r--r--cmds/dumpstate/dumpstate.c82
-rw-r--r--cmds/dumpstate/dumpstate.h3
-rw-r--r--cmds/dumpstate/utils.c7
-rwxr-xr-xcmds/input/src/com/android/commands/input/Input.java2
-rw-r--r--cmds/installd/Android.mk17
-rw-r--r--cmds/installd/commands.c165
-rw-r--r--cmds/installd/installd.c24
-rw-r--r--cmds/installd/installd.h19
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java28
-rw-r--r--cmds/rawbu/backup.cpp1
-rw-r--r--cmds/screencap/Android.mk8
-rw-r--r--cmds/screencap/screencap.cpp166
-rw-r--r--cmds/screenshot/Android.mk16
-rw-r--r--cmds/screenshot/screenshot.c171
-rw-r--r--cmds/servicemanager/service_manager.c5
-rw-r--r--cmds/stagefright/Android.mk82
-rw-r--r--cmds/stagefright/recordvideo.cpp303
-rw-r--r--cmds/stagefright/sf2.cpp581
-rw-r--r--cmds/stagefright/stagefright.cpp177
-rw-r--r--cmds/stagefright/stream.cpp206
-rw-r--r--cmds/system_server/library/Android.mk1
26 files changed, 2029 insertions, 234 deletions
diff --git a/cmds/am/Android.mk b/cmds/am/Android.mk
index 170849d..8b321b3 100644
--- a/cmds/am/Android.mk
+++ b/cmds/am/Android.mk
@@ -12,3 +12,20 @@ ALL_PREBUILT += $(TARGET_OUT)/bin/am
$(TARGET_OUT)/bin/am : $(LOCAL_PATH)/am | $(ACP)
$(transform-prebuilt-to-target)
+NOTICE_FILE := NOTICE
+files_noticed := bin/am
+
+# Generate rules for a single file. The argument is the file path relative to
+# the installation root
+define make-notice-file
+
+$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE)
+ @echo Notice file: $$< -- $$@
+ @mkdir -p $$(dir $$@)
+ @cat $$< >> $$@
+
+$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt
+
+endef
+
+$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index f2aa91f..38cacdd 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -18,12 +18,14 @@
package com.android.commands.am;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
import android.content.ComponentName;
+import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.net.Uri;
@@ -102,8 +104,14 @@ public class Am {
sendBroadcast();
} else if (op.equals("profile")) {
runProfile();
+ } else if (op.equals("dumpheap")) {
+ runDumpHeap();
} else if (op.equals("monitor")) {
runMonitor();
+ } else if (op.equals("screen-compat")) {
+ runScreenCompat();
+ } else if (op.equals("display-size")) {
+ runDisplaySize();
} else {
throw new IllegalArgumentException("Unknown command: " + op);
}
@@ -146,6 +154,31 @@ public class Am {
String value = nextArgRequired();
intent.putExtra(key, Integer.valueOf(value));
hasIntentInfo = true;
+ } else if (opt.equals("--eia")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ String[] strings = value.split(",");
+ int[] list = new int[strings.length];
+ for (int i = 0; i < strings.length; i++) {
+ list[i] = Integer.valueOf(strings[i]);
+ }
+ intent.putExtra(key, list);
+ hasIntentInfo = true;
+ } else if (opt.equals("--el")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Long.valueOf(value));
+ hasIntentInfo = true;
+ } else if (opt.equals("--ela")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ String[] strings = value.split(",");
+ long[] list = new long[strings.length];
+ for (int i = 0; i < strings.length; i++) {
+ list[i] = Long.valueOf(strings[i]);
+ }
+ intent.putExtra(key, list);
+ hasIntentInfo = true;
} else if (opt.equals("--ez")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -430,6 +463,28 @@ public class Am {
}
}
+ private void runDumpHeap() throws Exception {
+ boolean managed = !"-n".equals(nextOption());
+ String process = nextArgRequired();
+ String heapFile = nextArgRequired();
+ ParcelFileDescriptor fd = null;
+
+ try {
+ fd = ParcelFileDescriptor.open(
+ new File(heapFile),
+ ParcelFileDescriptor.MODE_CREATE |
+ ParcelFileDescriptor.MODE_TRUNCATE |
+ ParcelFileDescriptor.MODE_READ_WRITE);
+ } catch (FileNotFoundException e) {
+ System.err.println("Error: Unable to open file: " + heapFile);
+ return;
+ }
+
+ if (!mAm.dumpHeap(process, managed, heapFile, fd)) {
+ throw new AndroidException("HEAP DUMP FAILED on process " + process);
+ }
+ }
+
class MyActivityController extends IActivityController.Stub {
final String mGdbPort;
@@ -727,6 +782,78 @@ public class Am {
controller.run();
}
+ private void runScreenCompat() throws Exception {
+ String mode = nextArgRequired();
+ boolean enabled;
+ if ("on".equals(mode)) {
+ enabled = true;
+ } else if ("off".equals(mode)) {
+ enabled = false;
+ } else {
+ System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode);
+ showUsage();
+ return;
+ }
+
+ String packageName = nextArgRequired();
+ do {
+ try {
+ mAm.setPackageScreenCompatMode(packageName, enabled
+ ? ActivityManager.COMPAT_MODE_ENABLED
+ : ActivityManager.COMPAT_MODE_DISABLED);
+ } catch (RemoteException e) {
+ }
+ packageName = nextArg();
+ } while (packageName != null);
+ }
+
+ private void runDisplaySize() throws Exception {
+ String size = nextArgRequired();
+ int m, n;
+ if ("reset".equals(size)) {
+ m = n = -1;
+ } else {
+ int div = size.indexOf('x');
+ if (div <= 0 || div >= (size.length()-1)) {
+ System.err.println("Error: bad size " + size);
+ showUsage();
+ return;
+ }
+ String mstr = size.substring(0, div);
+ String nstr = size.substring(div+1);
+ try {
+ m = Integer.parseInt(mstr);
+ n = Integer.parseInt(nstr);
+ } catch (NumberFormatException e) {
+ System.err.println("Error: bad number " + e);
+ showUsage();
+ return;
+ }
+ }
+
+ if (m < n) {
+ int tmp = m;
+ m = n;
+ n = tmp;
+ }
+
+ IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
+ Context.WINDOW_SERVICE));
+ if (wm == null) {
+ System.err.println(NO_SYSTEM_ERROR_CODE);
+ throw new AndroidException("Can't connect to window manager; is the system running?");
+ }
+
+ try {
+ if (m >= 0 && n >= 0) {
+ wm.setForcedDisplaySize(m, n);
+ } else {
+ wm.clearForcedDisplaySize();
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
private class IntentReceiver extends IIntentReceiver.Stub {
private boolean mFinished = false;
@@ -894,19 +1021,33 @@ public class Am {
" -p <FILE>: write profiling data to <FILE>\n" +
" -w: wait for instrumentation to finish before returning\n" +
"\n" +
+ " run a test package against an application: am instrument [flags] <TEST_PACKAGE>/<RUNNER_CLASS>\n" +
+ " -e <testrunner_flag> <testrunner_value> [,<testrunner_value>]\n" +
+ " -w wait for the test to finish (required)\n" +
+ " -r use with -e perf true to generate raw output for performance measurements\n" +
+ "\n" +
" start profiling: am profile <PROCESS> start <FILE>\n" +
" stop profiling: am profile <PROCESS> stop\n" +
+ " dump heap: am dumpheap [flags] <PROCESS> <FILE>\n" +
+ " -n: dump native heap instead of managed heap\n" +
"\n" +
" start monitoring: am monitor [--gdb <port>]\n" +
" --gdb: start gdbserv on the given port at crash/ANR\n" +
"\n" +
+ " control screen compatibility: am screen-compat [on|off] [package]\n" +
+ "\n" +
+ " override display size: am display-size [reset|MxN]\n" +
+ "\n" +
" <INTENT> specifications include these flags:\n" +
" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
" [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
" [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
" [--esn <EXTRA_KEY> ...]\n" +
" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
- " [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
+ " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
+ " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
+ " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
+ " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
" [-n <COMPONENT>] [-f <FLAGS>]\n" +
" [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
" [--debug-log-resolution]\n" +
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 7decf9a..0159edd 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -171,9 +171,9 @@ int main(int argc, const char* const argv[])
runtime.start();
}
} else {
- LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
+ LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index a1cc4ce..ac0e410 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -386,11 +386,13 @@ public final class Bmgr {
if (err == 0) {
observer.waitForCompletion();
sets = observer.sets;
- for (RestoreSet s : sets) {
- if (s.token == token) {
- System.out.println("Scheduling restore: " + s.name);
- didRestore = (mRestore.restoreAll(token, observer) == 0);
- break;
+ if (sets != null) {
+ for (RestoreSet s : sets) {
+ if (s.token == token) {
+ System.out.println("Scheduling restore: " + s.name);
+ didRestore = (mRestore.restoreAll(token, observer) == 0);
+ break;
+ }
}
}
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 6650a71..e07495d 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -23,6 +23,8 @@
#include <utils/misc.h>
#include <signal.h>
+#include <cutils/properties.h>
+
#include <binder/IPCThreadState.h>
#include <utils/threads.h>
#include <utils/Atomic.h>
@@ -51,6 +53,7 @@
#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
+#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
namespace android {
@@ -248,11 +251,25 @@ status_t BootAnimation::readyToRun() {
mFlingerSurface = s;
mAndroidAnimation = true;
- if ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR) ||
- (access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
- (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))
+
+ // If the device has encryption turned on or is in process
+ // of being encrypted we show the encrypted boot animation.
+ char decrypt[PROPERTY_VALUE_MAX];
+ property_get("vold.decrypt", decrypt, "");
+
+ bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);
+
+ if ((encryptedAnimation &&
+ (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
+ (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
+
+ ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
+ (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
+
+ ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
+ (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
mAndroidAnimation = false;
+ }
return NO_ERROR;
}
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 0723f67..ccc4fd7 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -39,6 +39,8 @@
static char cmdline_buf[16384] = "(unknown)";
static const char *dump_traces_path = NULL;
+static char screenshot_path[PATH_MAX] = "";
+
/* dumps the current system state to stdout */
static void dumpstate() {
time_t now = time(NULL);
@@ -76,7 +78,13 @@ static void dumpstate() {
dump_file("SLAB INFO", "/proc/slabinfo");
dump_file("ZONEINFO", "/proc/zoneinfo");
- run_command("SYSTEM LOG", 20, "logcat", "-v", "time", "-d", "*:v", NULL);
+ if (screenshot_path[0]) {
+ LOGI("taking screenshot\n");
+ run_command(NULL, 5, "su", "root", "screenshot", screenshot_path, NULL);
+ LOGI("wrote screenshot: %s\n", screenshot_path);
+ }
+
+ run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
/* show the traces we collected in main(), if that was done */
if (dump_traces_path != NULL) {
@@ -96,18 +104,33 @@ static void dumpstate() {
}
// dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
- run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "time", "-d", "*:v", NULL);
- run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "time", "-d", "*:v", NULL);
+ run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
+ run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
- run_command("NETWORK INTERFACES", 10, "netcfg", NULL);
+ run_command("NETWORK INTERFACES", 10, "su", "root", "netcfg", NULL);
dump_file("NETWORK ROUTES", "/proc/net/route");
+ dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route");
dump_file("ARP CACHE", "/proc/net/arp");
+ run_command("IPTABLES", 10, "su", "root", "iptables", "-L", NULL);
+ run_command("IPTABLE NAT", 10, "su", "root", "iptables", "-t", "nat", "-L", NULL);
+
+ run_command("WIFI NETWORKS", 20,
+ "su", "root", "wpa_cli", "list_networks", NULL);
#ifdef FWDUMP_bcm4329
- run_command("DUMP WIFI FIRMWARE LOG", 60,
- "su", "root", "dhdutil", "-i", "eth0", "upload", "/data/local/tmp/wlan_crash.dump", NULL);
+ run_command("DUMP WIFI STATUS", 20,
+ "su", "root", "dhdutil", "-i", "wlan0", "dump", NULL);
+ run_command("DUMP WIFI INTERNAL COUNTERS", 20,
+ "su", "root", "wlutil", "counters", NULL);
#endif
+ char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
+ property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
+ if (strlen(ril_dumpstate_timeout) > 0) {
+ run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
+ "su", "root", "vril-dump", NULL);
+ }
+
print_properties();
run_command("KERNEL LOG", 20, "dmesg", NULL);
@@ -128,7 +151,7 @@ static void dumpstate() {
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);
+ run_command("FILESYSTEMS & FREE SPACE", 10, "su", "root", "df", NULL);
dump_file("PACKAGE SETTINGS", "/data/system/packages.xml");
dump_file("PACKAGE UID ERRORS", "/data/system/uiderrors.txt");
@@ -161,21 +184,41 @@ static void dumpstate() {
to increase its timeout. we really need to do the timeouts in
dumpsys itself... */
run_command("DUMPSYS", 60, "dumpsys", NULL);
+
+ printf("========================================================\n");
+ printf("== Running Application Activities\n");
+ printf("========================================================\n");
+
+ run_command("APP ACTIVITIES", 30, "dumpsys", "activity", "all", NULL);
+
+ printf("========================================================\n");
+ printf("== Running Application Services\n");
+ printf("========================================================\n");
+
+ run_command("APP SERVICES", 30, "dumpsys", "activity", "service", "all", NULL);
+
}
static void usage() {
- fprintf(stderr, "usage: dumpstate [-d] [-o file] [-s] [-z]\n"
- " -d: append date to filename (requires -o)\n"
+ fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s]\n"
" -o: write to file (instead of stdout)\n"
+ " -d: append date to filename (requires -o)\n"
+ " -z: gzip output (requires -o)\n"
+ " -p: capture screenshot to filename.png (requires -o)\n"
" -s: write output to control socket (for init)\n"
- " -z: gzip output (requires -o)\n");
+ " -b: play sound file instead of vibrate, at beginning of job\n"
+ " -e: play sound file instead of vibrate, at end of job\n"
+ );
}
int main(int argc, char *argv[]) {
int do_add_date = 0;
int do_compress = 0;
char* use_outfile = 0;
+ char* begin_sound = 0;
+ char* end_sound = 0;
int use_socket = 0;
+ int do_fb = 0;
LOGI("begin\n");
@@ -191,13 +234,16 @@ int main(int argc, char *argv[]) {
dump_traces_path = dump_vm_traces();
int c;
- while ((c = getopt(argc, argv, "dho:svz")) != -1) {
+ while ((c = getopt(argc, argv, "b:de:ho:svzp")) != -1) {
switch (c) {
+ case 'b': begin_sound = optarg; break;
case 'd': do_add_date = 1; break;
+ case 'e': end_sound = optarg; break;
case 'o': use_outfile = optarg; break;
case 's': use_socket = 1; break;
case 'v': break; // compatibility no-op
case 'z': do_compress = 6; break;
+ case 'p': do_fb = 1; break;
case '?': printf("\n");
case 'h':
usage();
@@ -246,6 +292,10 @@ int main(int argc, char *argv[]) {
strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now));
strlcat(path, date, sizeof(path));
}
+ if (do_fb) {
+ strlcpy(screenshot_path, path, sizeof(screenshot_path));
+ strlcat(screenshot_path, ".png", sizeof(screenshot_path));
+ }
strlcat(path, ".txt", sizeof(path));
if (do_compress) strlcat(path, ".gz", sizeof(path));
strlcpy(tmp_path, path, sizeof(tmp_path));
@@ -253,16 +303,18 @@ int main(int argc, char *argv[]) {
gzip_pid = redirect_to_file(stdout, tmp_path, do_compress);
}
- /* bzzzzzz */
- if (vibrator) {
+ if (begin_sound) {
+ play_sound(begin_sound);
+ } else if (vibrator) {
fputs("150", vibrator);
fflush(vibrator);
}
dumpstate();
- /* bzzz bzzz bzzz */
- if (vibrator) {
+ if (end_sound) {
+ play_sound(end_sound);
+ } else if (vibrator) {
int i;
for (i = 0; i < 3; i++) {
fputs("75\n", vibrator);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 682eafd..83b1d11 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -44,4 +44,7 @@ void for_each_pid(void (*func)(int, const char *), const char *header);
/* Displays a blocked processes in-kernel wait channel */
void show_wchan(int pid, const char *name);
+/* Play a sound via Stagefright */
+void play_sound(const char* path);
+
#endif /* _DUMPSTATE_H_ */
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index c7a78cc..b2f9e80 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -167,6 +167,7 @@ int run_command(const char *title, int timeout_seconds, const char *command, ...
execvp(command, (char**) args);
printf("*** exec(%s): %s\n", command, strerror(errno));
+ fflush(stdout);
_exit(-1);
}
@@ -178,7 +179,7 @@ int run_command(const char *title, int timeout_seconds, const char *command, ...
if (p == pid) {
if (WIFSIGNALED(status)) {
printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
- } else if (WEXITSTATUS(status) > 0) {
+ } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
}
if (title) printf("[%s: %.1fs elapsed]\n\n", command, elapsed);
@@ -429,3 +430,7 @@ const char *dump_vm_traces() {
rename(anr_traces_path, traces_path);
return dump_traces_path;
}
+
+void play_sound(const char* path) {
+ run_command(NULL, 5, "/system/bin/stagefright", "-o", "-a", path, NULL);
+}
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 3a1accd..df1d0bf 100755
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -91,7 +91,7 @@ public class Input {
char[] chars = buff.toString().toCharArray();
KeyCharacterMap mKeyCharacterMap = KeyCharacterMap.
- load(KeyCharacterMap.BUILT_IN_KEYBOARD);
+ load(KeyCharacterMap.VIRTUAL_KEYBOARD);
KeyEvent[] events = mKeyCharacterMap.getEvents(chars);
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 6673862..8641c30 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -1,21 +1,24 @@
ifneq ($(TARGET_SIMULATOR),true)
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
+LOCAL_SRC_FILES := \
installd.c commands.c utils.c
-LOCAL_C_INCLUDES := \
- $(call include-path-for, system-core)/cutils
+#LOCAL_C_INCLUDES := \
+# $(call include-path-for, system-core)/cutils
LOCAL_SHARED_LIBRARIES := \
libcutils
-LOCAL_STATIC_LIBRARIES :=
+LOCAL_STATIC_LIBRARIES := \
+ libdiskusage
-LOCAL_MODULE:= installd
+LOCAL_MODULE := installd
+
+LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
-endif # !simulator))
+endif # !simulator
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 2f03c7a..4d49c30 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -15,8 +15,9 @@
*/
#include "installd.h"
+#include <diskusage/dirsize.h>
-int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid)
+int install(const char *pkgname, uid_t uid, gid_t gid)
{
char pkgdir[PKG_PATH_MAX];
char libdir[PKG_PATH_MAX];
@@ -26,17 +27,10 @@ int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid)
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 (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 (mkdir(pkgdir, 0751) < 0) {
LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
@@ -61,38 +55,26 @@ int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid)
return 0;
}
-int uninstall(const char *pkgname, int encrypted_fs_flag)
+int uninstall(const char *pkgname)
{
char pkgdir[PKG_PATH_MAX];
- 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;
- }
+ if (create_pkg_path(pkgdir, PKG_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 encrypted_fs_flag)
+int renamepkg(const char *oldpkgname, const char *newpkgname)
{
char oldpkgdir[PKG_PATH_MAX];
char newpkgdir[PKG_PATH_MAX];
- 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 (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 (rename(oldpkgdir, newpkgdir) < 0) {
LOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
@@ -101,41 +83,28 @@ int renamepkg(const char *oldpkgname, const char *newpkgname, int encrypted_fs_f
return 0;
}
-int delete_user_data(const char *pkgname, int encrypted_fs_flag)
+int delete_user_data(const char *pkgname)
{
char pkgdir[PKG_PATH_MAX];
- 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;
- }
+ if (create_pkg_path(pkgdir, PKG_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 encrypted_fs_flag)
+int delete_cache(const char *pkgname)
{
char cachedir[PKG_PATH_MAX];
- 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;
- }
+ if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX))
+ return -1;
/* delete contents, not the directory, no exceptions */
return delete_dir_contents(cachedir, 0, 0);
}
-/* TODO(oam): depending on use case (ecryptfs or dmcrypt)
- * change implementation
- */
static int64_t disk_free()
{
struct statfs sfs;
@@ -168,39 +137,6 @@ int free_cache(int64_t free_size)
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: %s\n", PKG_DIR_PREFIX, strerror(errno));
@@ -327,58 +263,9 @@ int protect(char *pkgname, gid_t gid)
return 0;
}
-static int64_t stat_size(struct stat *s)
-{
- int64_t blksize = s->st_blksize;
- int64_t size = s->st_size;
-
- if (blksize) {
- /* round up to filesystem block size */
- size = (size + blksize - 1) & (~(blksize - 1));
- }
-
- return size;
-}
-
-static int64_t calculate_dir_size(int dfd)
-{
- int64_t size = 0;
- struct stat s;
- DIR *d;
- struct dirent *de;
-
- d = fdopendir(dfd);
- if (d == NULL) {
- close(dfd);
- return 0;
- }
-
- while ((de = readdir(d))) {
- const char *name = de->d_name;
- if (de->d_type == DT_DIR) {
- int subfd;
- /* 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) {
- size += calculate_dir_size(subfd);
- }
- } else {
- if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
- size += stat_size(&s);
- }
- }
- }
- closedir(d);
- return size;
-}
-
int get_size(const char *pkgname, const char *apkpath,
const char *fwdlock_apkpath,
- int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize, int encrypted_fs_flag)
+ int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize)
{
DIR *d;
int dfd;
@@ -413,14 +300,8 @@ int get_size(const char *pkgname, const char *apkpath,
}
}
- 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;
- }
+ if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) {
+ goto done;
}
d = opendir(path);
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 9ba6402..d2b2f7f 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]), atoi(arg[3])); /* pkgname, uid, gid */
+ return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */
}
static int do_dexopt(char **arg, char reply[REPLY_MAX])
@@ -50,12 +50,12 @@ 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], atoi(arg[1])); /* pkgname */
+ return uninstall(arg[0]); /* pkgname */
}
static int do_rename(char **arg, char reply[REPLY_MAX])
{
- return renamepkg(arg[0], arg[1], atoi(arg[2])); /* oldpkgname, newpkgname */
+ return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */
}
static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */
@@ -65,7 +65,7 @@ static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_siz
static int do_rm_cache(char **arg, char reply[REPLY_MAX])
{
- return delete_cache(arg[0], atoi(arg[1])); /* pkgname */
+ return delete_cache(arg[0]); /* pkgname */
}
static int do_protect(char **arg, char reply[REPLY_MAX])
@@ -81,7 +81,7 @@ static int do_get_size(char **arg, char reply[REPLY_MAX])
int res = 0;
/* pkgdir, apkpath */
- res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize, atoi(arg[3]));
+ res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize);
/*
* Each int64_t can take up 22 characters printed out. Make sure it
@@ -93,7 +93,7 @@ static int do_get_size(char **arg, char reply[REPLY_MAX])
static int do_rm_user_data(char **arg, char reply[REPLY_MAX])
{
- return delete_user_data(arg[0], atoi(arg[1])); /* pkgname */
+ return delete_user_data(arg[0]); /* pkgname */
}
static int do_movefiles(char **arg, char reply[REPLY_MAX])
@@ -119,17 +119,17 @@ struct cmdinfo {
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
- { "install", 4, do_install },
+ { "install", 3, do_install },
{ "dexopt", 3, do_dexopt },
{ "movedex", 2, do_move_dex },
{ "rmdex", 1, do_rm_dex },
- { "remove", 2, do_remove },
- { "rename", 3, do_rename },
+ { "remove", 1, do_remove },
+ { "rename", 2, do_rename },
{ "freecache", 1, do_free_cache },
- { "rmcache", 2, do_rm_cache },
+ { "rmcache", 1, do_rm_cache },
{ "protect", 2, do_protect },
- { "getsize", 4, do_get_size },
- { "rmuserdata", 2, do_rm_user_data },
+ { "getsize", 3, do_get_size },
+ { "rmuserdata", 1, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
{ "linklib", 2, do_linklib },
{ "unlinklib", 1, do_unlinklib },
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 59475e9..77b58ec 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -50,23 +50,16 @@
/* 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/"
@@ -98,16 +91,16 @@ int delete_dir_contents_fd(int dfd, const char *name);
/* commands.c */
-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 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 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,
- int64_t *codesize, int64_t *datasize, int64_t *cachesize, int encrypted_fs_flag);
+ int64_t *codesize, int64_t *datasize, int64_t *cachesize);
int free_cache(int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, int is_public);
int movefiles();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index f2b6fce..1b2326a 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -194,6 +194,7 @@ public final class Pm {
private void runListPackages(boolean showApplicationPackage) {
int getFlags = 0;
boolean listDisabled = false, listEnabled = false;
+ boolean listSystem = false, listThirdParty = false;
try {
String opt;
while ((opt=nextOption()) != null) {
@@ -207,6 +208,10 @@ public final class Pm {
listDisabled = true;
} else if (opt.equals("-e")) {
listEnabled = true;
+ } else if (opt.equals("-s")) {
+ listSystem = true;
+ } else if (opt.equals("-3")) {
+ listThirdParty = true;
} else if (opt.equals("-u")) {
getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
} else {
@@ -232,8 +237,12 @@ public final class Pm {
if (filter != null && !info.packageName.contains(filter)) {
continue;
}
+ final boolean isSystem =
+ (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0;
if ((!listDisabled || !info.applicationInfo.enabled) &&
- (!listEnabled || info.applicationInfo.enabled)) {
+ (!listEnabled || info.applicationInfo.enabled) &&
+ (!listSystem || isSystem) &&
+ (!listThirdParty || !isSystem)) {
System.out.print("package:");
if (showApplicationPackage) {
System.out.print(info.applicationInfo.sourceDir);
@@ -276,7 +285,7 @@ public final class Pm {
for (int i=0; i<rawList.length; i++) {
list.add(rawList[i]);
}
-
+
// Sort by name
Collections.sort(list, new Comparator<FeatureInfo>() {
@@ -784,10 +793,10 @@ public final class Pm {
boolean finished;
boolean result;
- public void packageDeleted(boolean succeeded) {
+ public void packageDeleted(String packageName, int returnCode) {
synchronized (this) {
finished = true;
- result = succeeded;
+ result = returnCode == PackageManager.DELETE_SUCCEEDED;
notifyAll();
}
}
@@ -1010,7 +1019,7 @@ public final class Pm {
private static void showUsage() {
System.err.println("usage: pm [list|path|install|uninstall]");
- System.err.println(" pm list packages [-f] [-d] [-e] [-u] [FILTER]");
+ System.err.println(" pm list packages [-f] [-d] [-e] [-s] [-e] [-u] [FILTER]");
System.err.println(" pm list permission-groups");
System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
@@ -1027,8 +1036,10 @@ public final class Pm {
System.err.println("The list packages command prints all packages, optionally only");
System.err.println("those whose package name contains the text in FILTER. Options:");
System.err.println(" -f: see their associated file.");
- System.err.println(" -d: filter to include disbled packages.");
- System.err.println(" -e: filter to include enabled packages.");
+ System.err.println(" -d: filter to only show disbled packages.");
+ System.err.println(" -e: filter to only show enabled packages.");
+ System.err.println(" -s: filter to only show system packages.");
+ System.err.println(" -3: filter to only show third party packages.");
System.err.println(" -u: also include uninstalled packages.");
System.err.println("");
System.err.println("The list permission-groups command prints all known");
@@ -1045,6 +1056,9 @@ public final class Pm {
System.err.println("The list instrumentation command prints all instrumentations,");
System.err.println("or only those that target a specified package. Options:");
System.err.println(" -f: see their associated file.");
+ System.err.println("(Use this command to list all test packages, or use <TARGET-PACKAGE> ");
+ System.err.println(" to list the test packages for a particular application. The -f ");
+ System.err.println(" option lists the .apk file for the test package.)");
System.err.println("");
System.err.println("The list features command prints all features of the system.");
System.err.println("");
diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp
index c4fa765..9ea046d 100644
--- a/cmds/rawbu/backup.cpp
+++ b/cmds/rawbu/backup.cpp
@@ -14,6 +14,7 @@
#include <utime.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <stdint.h>
#include <cutils/properties.h>
diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk
index 1a6e23e..400a36b 100644
--- a/cmds/screencap/Android.mk
+++ b/cmds/screencap/Android.mk
@@ -8,6 +8,7 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
+ libskia \
libui \
libsurfaceflinger_client
@@ -15,4 +16,11 @@ LOCAL_MODULE:= screencap
LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES += \
+ external/skia/include/core \
+ external/skia/include/effects \
+ external/skia/include/images \
+ external/skia/src/ports \
+ external/skia/include/utils
+
include $(BUILD_EXECUTABLE)
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index bc5e10d..7a599e9 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -14,29 +14,171 @@
* limitations under the License.
*/
+#include <errno.h>
#include <unistd.h>
+#include <stdio.h>
#include <fcntl.h>
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
#include <binder/IMemory.h>
#include <surfaceflinger/SurfaceComposerClient.h>
+#include <SkImageEncoder.h>
+#include <SkBitmap.h>
+#include <SkStream.h>
+
using namespace android;
+static void usage(const char* pname)
+{
+ fprintf(stderr,
+ "usage: %s [-hp] [FILENAME]\n"
+ " -h: this message\n"
+ " -p: save the file as a png.\n"
+ "If FILENAME ends with .png it will be saved as a png.\n"
+ "If FILENAME is not given, the results will be printed to stdout.\n",
+ pname
+ );
+}
+
+static SkBitmap::Config flinger2skia(PixelFormat f)
+{
+ switch (f) {
+ case PIXEL_FORMAT_A_8:
+ case PIXEL_FORMAT_L_8:
+ return SkBitmap::kA8_Config;
+ case PIXEL_FORMAT_RGB_565:
+ return SkBitmap::kRGB_565_Config;
+ case PIXEL_FORMAT_RGBA_4444:
+ return SkBitmap::kARGB_4444_Config;
+ default:
+ return SkBitmap::kARGB_8888_Config;
+ }
+}
+
+static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,
+ uint32_t* bytespp, uint32_t* f)
+{
+
+ switch (vinfo.bits_per_pixel) {
+ case 16:
+ *f = PIXEL_FORMAT_RGB_565;
+ *bytespp = 2;
+ break;
+ case 24:
+ *f = PIXEL_FORMAT_RGB_888;
+ *bytespp = 3;
+ break;
+ case 32:
+ // TODO: do better decoding of vinfo here
+ *f = PIXEL_FORMAT_RGBX_8888;
+ *bytespp = 4;
+ break;
+ default:
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
int main(int argc, char** argv)
{
+ const char* pname = argv[0];
+ bool png = false;
+ int c;
+ while ((c = getopt(argc, argv, "ph")) != -1) {
+ switch (c) {
+ case 'p':
+ png = true;
+ break;
+ case '?':
+ case 'h':
+ usage(pname);
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ int fd = -1;
+ if (argc == 0) {
+ fd = dup(STDOUT_FILENO);
+ } else if (argc == 1) {
+ const char* fn = argv[0];
+ fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+ if (fd == -1) {
+ fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
+ return 1;
+ }
+ const int len = strlen(fn);
+ if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {
+ png = true;
+ }
+ }
+
+ if (fd == -1) {
+ usage(pname);
+ return 1;
+ }
+
+ void const* mapbase = MAP_FAILED;
+ ssize_t mapsize = -1;
+
+ void const* base = 0;
+ uint32_t w, h, f;
+ size_t size = 0;
+
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);
+ if (screenshot.update() == NO_ERROR) {
+ base = screenshot.getPixels();
+ w = screenshot.getWidth();
+ h = screenshot.getHeight();
+ f = screenshot.getFormat();
+ size = screenshot.getSize();
+ } else {
+ const char* fbpath = "/dev/graphics/fb0";
+ int fb = open(fbpath, O_RDONLY);
+ if (fb >= 0) {
+ struct fb_var_screeninfo vinfo;
+ if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {
+ uint32_t bytespp;
+ if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {
+ size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp;
+ w = vinfo.xres;
+ h = vinfo.yres;
+ size = w*h*bytespp;
+ mapsize = offset + size;
+ mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);
+ if (mapbase != MAP_FAILED) {
+ base = (void const *)((char const *)mapbase + offset);
+ }
+ }
+ }
+ close(fb);
+ }
+ }
+
+ if (base) {
+ if (png) {
+ SkBitmap b;
+ b.setConfig(flinger2skia(f), w, h);
+ b.setPixels((void*)base);
+ SkDynamicMemoryWStream stream;
+ SkImageEncoder::EncodeStream(&stream, b,
+ SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
+ write(fd, stream.getStream(), stream.getOffset());
+ } else {
+ write(fd, &w, 4);
+ write(fd, &h, 4);
+ write(fd, &f, 4);
+ write(fd, base, size);
+ }
+ }
close(fd);
+ if (mapbase != MAP_FAILED) {
+ munmap((void *)mapbase, mapsize);
+ }
return 0;
}
diff --git a/cmds/screenshot/Android.mk b/cmds/screenshot/Android.mk
new file mode 100644
index 0000000..99c7aeb
--- /dev/null
+++ b/cmds/screenshot/Android.mk
@@ -0,0 +1,16 @@
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := screenshot.c
+
+LOCAL_MODULE := screenshot
+
+LOCAL_SHARED_LIBRARIES := libcutils libz
+LOCAL_STATIC_LIBRARIES := libpng
+LOCAL_C_INCLUDES += external/zlib
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/cmds/screenshot/screenshot.c b/cmds/screenshot/screenshot.c
new file mode 100644
index 0000000..048636c
--- /dev/null
+++ b/cmds/screenshot/screenshot.c
@@ -0,0 +1,171 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <linux/fb.h>
+
+#include <zlib.h>
+#include <libpng/png.h>
+
+#include "private/android_filesystem_config.h"
+
+#define LOG_TAG "screenshot"
+#include <utils/Log.h>
+
+void take_screenshot(FILE *fb_in, FILE *fb_out) {
+ int fb;
+ char imgbuf[0x10000];
+ struct fb_var_screeninfo vinfo;
+ png_structp png;
+ png_infop info;
+ unsigned int r,c,rowlen;
+ unsigned int bytespp,offset;
+
+ fb = fileno(fb_in);
+ if(fb < 0) {
+ LOGE("failed to open framebuffer\n");
+ return;
+ }
+ fb_in = fdopen(fb, "r");
+
+ if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) {
+ LOGE("failed to get framebuffer info\n");
+ return;
+ }
+ fcntl(fb, F_SETFD, FD_CLOEXEC);
+
+ png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png == NULL) {
+ LOGE("failed png_create_write_struct\n");
+ fclose(fb_in);
+ return;
+ }
+
+ png_init_io(png, fb_out);
+ info = png_create_info_struct(png);
+ if (info == NULL) {
+ LOGE("failed png_create_info_struct\n");
+ png_destroy_write_struct(&png, NULL);
+ fclose(fb_in);
+ return;
+ }
+ if (setjmp(png_jmpbuf(png))) {
+ LOGE("failed png setjmp\n");
+ png_destroy_write_struct(&png, NULL);
+ fclose(fb_in);
+ return;
+ }
+
+ bytespp = vinfo.bits_per_pixel / 8;
+ png_set_IHDR(png, info,
+ vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4,
+ PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+ png_write_info(png, info);
+
+ rowlen=vinfo.xres * bytespp;
+ if (rowlen > sizeof(imgbuf)) {
+ LOGE("crazy rowlen: %d\n", rowlen);
+ png_destroy_write_struct(&png, NULL);
+ fclose(fb_in);
+ return;
+ }
+
+ offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp;
+ fseek(fb_in, offset, SEEK_SET);
+
+ for(r=0; r<vinfo.yres; r++) {
+ int len = fread(imgbuf, 1, rowlen, fb_in);
+ if (len <= 0) break;
+ png_write_row(png, (png_bytep)imgbuf);
+ }
+
+ png_write_end(png, info);
+ fclose(fb_in);
+ png_destroy_write_struct(&png, NULL);
+}
+
+void fork_sound(const char* path) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL);
+ }
+}
+
+void usage() {
+ fprintf(stderr,
+ "usage: screenshot [-s soundfile] filename.png\n"
+ " -s: play a sound effect to signal success\n"
+ " -i: autoincrement to avoid overwriting filename.png\n"
+ );
+}
+
+int main(int argc, char**argv) {
+ FILE *png = NULL;
+ FILE *fb_in = NULL;
+ char outfile[PATH_MAX] = "";
+
+ char * soundfile = NULL;
+ int do_increment = 0;
+
+ int c;
+ while ((c = getopt(argc, argv, "s:i")) != -1) {
+ switch (c) {
+ case 's': soundfile = optarg; break;
+ case 'i': do_increment = 1; break;
+ case '?':
+ case 'h':
+ usage(); exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage(); exit(1);
+ }
+
+ strlcpy(outfile, argv[0], PATH_MAX);
+ if (do_increment) {
+ struct stat st;
+ char base[PATH_MAX] = "";
+ int i = 0;
+ while (stat(outfile, &st) == 0) {
+ if (!base[0]) {
+ char *p = strrchr(outfile, '.');
+ if (p) *p = '\0';
+ strcpy(base, outfile);
+ }
+ snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i);
+ }
+ }
+
+ fb_in = fopen("/dev/graphics/fb0", "r");
+ if (!fb_in) {
+ fprintf(stderr, "error: could not read framebuffer\n");
+ exit(1);
+ }
+
+ /* switch to non-root user and group */
+ gid_t groups[] = { AID_LOG, AID_SDCARD_RW };
+ setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+ setuid(AID_SHELL);
+
+ png = fopen(outfile, "w");
+ if (!png) {
+ fprintf(stderr, "error: writing file %s: %s\n",
+ outfile, strerror(errno));
+ exit(1);
+ }
+
+ take_screenshot(fb_in, png);
+
+ if (soundfile) {
+ fork_sound(soundfile);
+ }
+
+ exit(0);
+}
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 14536bd..2df450f 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -34,7 +34,6 @@ static struct {
{ AID_MEDIA, "media.player" },
{ AID_MEDIA, "media.camera" },
{ AID_MEDIA, "media.audio_policy" },
- { AID_DRMIO, "drm.drmIOService" },
{ AID_DRM, "drm.drmManager" },
{ AID_NFC, "nfc" },
{ AID_RADIO, "radio.phone" },
@@ -161,9 +160,9 @@ int do_add_service(struct binder_state *bs,
si = find_svc(s, len);
if (si) {
if (si->ptr) {
- LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",
+ LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
str8(s), ptr, uid);
- return -1;
+ svcinfo_death(bs, si);
}
si->ptr = ptr;
} else {
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 5b74007..1b13dd9 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -7,13 +7,16 @@ LOCAL_SRC_FILES:= \
SineSource.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libutils libbinder libstagefright_foundation
+ libstagefright libmedia libutils libbinder libstagefright_foundation \
+ libskia libsurfaceflinger_client libgui
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
frameworks/base/media/libstagefright/include \
- $(TOP)/frameworks/base/include/media/stagefright/openmax
+ $(TOP)/frameworks/base/include/media/stagefright/openmax \
+ external/skia/include/core \
+ external/skia/include/images \
LOCAL_CFLAGS += -Wno-multichar
@@ -53,6 +56,31 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
SineSource.cpp \
+ recordvideo.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright liblog libutils libbinder
+
+LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
+ frameworks/base/media/libstagefright \
+ $(TOP)/frameworks/base/include/media/stagefright/openmax
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE:= recordvideo
+
+include $(BUILD_EXECUTABLE)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ SineSource.cpp \
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
@@ -70,3 +98,53 @@ LOCAL_MODULE_TAGS := debug
LOCAL_MODULE:= audioloop
include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ stream.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright liblog libutils libbinder libsurfaceflinger_client \
+ libstagefright_foundation libmedia
+
+LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
+ frameworks/base/media/libstagefright \
+ $(TOP)/frameworks/base/include/media/stagefright/openmax
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE:= stream
+
+include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ sf2.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright liblog libutils libbinder libstagefright_foundation \
+ libmedia libsurfaceflinger_client libcutils libui
+
+LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
+ frameworks/base/media/libstagefright \
+ $(TOP)/frameworks/base/include/media/stagefright/openmax
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_MODULE:= sf2
+
+include $(BUILD_EXECUTABLE)
+
+
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
new file mode 100644
index 0000000..1264215
--- /dev/null
+++ b/cmds/stagefright/recordvideo.cpp
@@ -0,0 +1,303 @@
+/*
+ * 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 "SineSource.h"
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/MediaPlayerInterface.h>
+
+using namespace android;
+
+// Print usage showing how to use this utility to record videos
+static void usage(const char *me) {
+ fprintf(stderr, "usage: %s\n", me);
+ fprintf(stderr, " -h(elp)\n");
+ fprintf(stderr, " -b bit rate in bits per second (default: 300000)\n");
+ fprintf(stderr, " -c YUV420 color format: [0] semi planar or [1] planar (default: 1)\n");
+ fprintf(stderr, " -f frame rate in frames per second (default: 30)\n");
+ fprintf(stderr, " -i I frame interval in seconds (default: 1)\n");
+ fprintf(stderr, " -n number of frames to be recorded (default: 300)\n");
+ fprintf(stderr, " -w width in pixels (default: 176)\n");
+ fprintf(stderr, " -t height in pixels (default: 144)\n");
+ fprintf(stderr, " -l encoder level. see omx il header (default: encoder specific)\n");
+ fprintf(stderr, " -p encoder profile. see omx il header (default: encoder specific)\n");
+ fprintf(stderr, " -v video codec: [0] AVC [1] M4V [2] H263 (default: 0)\n");
+ fprintf(stderr, "The output file is /sdcard/output.mp4\n");
+ exit(1);
+}
+
+class DummySource : public MediaSource {
+
+public:
+ DummySource(int width, int height, int nFrames, int fps, int colorFormat)
+ : mWidth(width),
+ mHeight(height),
+ mMaxNumFrames(nFrames),
+ mFrameRate(fps),
+ 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;
+ }
+
+ virtual status_t start(MetaData *params) {
+ mNumFramesOutput = 0;
+ return OK;
+ }
+
+ virtual status_t stop() {
+ return OK;
+ }
+
+ virtual status_t read(
+ MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+
+ if (mNumFramesOutput % 10 == 0) {
+ fprintf(stderr, ".");
+ }
+ if (mNumFramesOutput == mMaxNumFrames) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ status_t err = mGroup.acquire_buffer(buffer);
+ if (err != OK) {
+ return err;
+ }
+
+ // We don't care about the contents. we just test video encoder
+ // Also, by skipping the content generation, we can return from
+ // read() much faster.
+ //char x = (char)((double)rand() / RAND_MAX * 255);
+ //memset((*buffer)->data(), x, mSize);
+ (*buffer)->set_range(0, mSize);
+ (*buffer)->meta_data()->clear();
+ (*buffer)->meta_data()->setInt64(
+ kKeyTime, (mNumFramesOutput * 1000000) / mFrameRate);
+ ++mNumFramesOutput;
+
+ return OK;
+ }
+
+protected:
+ virtual ~DummySource() {}
+
+private:
+ MediaBufferGroup mGroup;
+ int mWidth, mHeight;
+ int mMaxNumFrames;
+ int mFrameRate;
+ int mColorFormat;
+ size_t mSize;
+ int64_t mNumFramesOutput;;
+
+ DummySource(const DummySource &);
+ DummySource &operator=(const DummySource &);
+};
+
+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) {
+
+ // Default values for the program if not overwritten
+ int frameRateFps = 30;
+ int width = 176;
+ int height = 144;
+ int bitRateBps = 300000;
+ int iFramesIntervalSeconds = 1;
+ int colorFormat = OMX_COLOR_FormatYUV420Planar;
+ int nFrames = 300;
+ int level = -1; // Encoder specific default
+ int profile = -1; // Encoder specific default
+ int codec = 0;
+ const char *fileName = "/sdcard/output.mp4";
+
+ android::ProcessState::self()->startThreadPool();
+ int res;
+ while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:h")) >= 0) {
+ switch (res) {
+ case 'b':
+ {
+ bitRateBps = atoi(optarg);
+ break;
+ }
+
+ case 'c':
+ {
+ colorFormat = translateColorToOmxEnumValue(atoi(optarg));
+ if (colorFormat == -1) {
+ usage(argv[0]);
+ }
+ break;
+ }
+
+ case 'f':
+ {
+ frameRateFps = atoi(optarg);
+ break;
+ }
+
+ case 'i':
+ {
+ iFramesIntervalSeconds = atoi(optarg);
+ break;
+ }
+
+ case 'n':
+ {
+ nFrames = atoi(optarg);
+ break;
+ }
+
+ case 'w':
+ {
+ width = atoi(optarg);
+ break;
+ }
+
+ case 't':
+ {
+ height = atoi(optarg);
+ break;
+ }
+
+ case 'l':
+ {
+ level = atoi(optarg);
+ break;
+ }
+
+ case 'p':
+ {
+ profile = atoi(optarg);
+ break;
+ }
+
+ case 'v':
+ {
+ codec = atoi(optarg);
+ if (codec < 0 || codec > 2) {
+ usage(argv[0]);
+ }
+ break;
+ }
+
+ case 'h':
+ default:
+ {
+ usage(argv[0]);
+ break;
+ }
+ }
+ }
+
+ OMXClient client;
+ CHECK_EQ(client.connect(), OK);
+
+ status_t err = OK;
+ sp<MediaSource> source =
+ new DummySource(width, height, nFrames, frameRateFps, colorFormat);
+
+ sp<MetaData> enc_meta = new MetaData;
+ switch (codec) {
+ case 1:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+ break;
+ case 2:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+ break;
+ default:
+ enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ break;
+ }
+ enc_meta->setInt32(kKeyWidth, width);
+ enc_meta->setInt32(kKeyHeight, height);
+ enc_meta->setInt32(kKeyFrameRate, frameRateFps);
+ enc_meta->setInt32(kKeyBitRate, bitRateBps);
+ enc_meta->setInt32(kKeyStride, width);
+ enc_meta->setInt32(kKeySliceHeight, height);
+ enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds);
+ enc_meta->setInt32(kKeyColorFormat, colorFormat);
+ if (level != -1) {
+ enc_meta->setInt32(kKeyVideoLevel, level);
+ }
+ if (profile != -1) {
+ enc_meta->setInt32(kKeyVideoProfile, profile);
+ }
+
+ sp<MediaSource> encoder =
+ OMXCodec::Create(
+ client.interface(), enc_meta, true /* createEncoder */, source);
+
+ sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
+ writer->addSource(encoder);
+ int64_t start = systemTime();
+ CHECK_EQ(OK, writer->start());
+ while (!writer->reachedEOS()) {
+ }
+ err = writer->stop();
+ int64_t end = systemTime();
+
+ fprintf(stderr, "$\n");
+ client.disconnect();
+
+ if (err != OK && err != ERROR_END_OF_STREAM) {
+ fprintf(stderr, "record failed: %d\n", err);
+ return 1;
+ }
+ fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000);
+ fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start));
+ return 0;
+}
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
new file mode 100644
index 0000000..c1d0803
--- /dev/null
+++ b/cmds/stagefright/sf2.cpp
@@ -0,0 +1,581 @@
+/*
+ * 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/ProcessState.h>
+
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/stagefright/ACodec.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include "include/ESDS.h"
+
+using namespace android;
+
+struct Controller : public AHandler {
+ Controller(const char *uri, bool decodeAudio, const sp<Surface> &surface)
+ : mURI(uri),
+ mDecodeAudio(decodeAudio),
+ mSurface(surface),
+ mCodec(new ACodec) {
+ CHECK(!mDecodeAudio || mSurface == NULL);
+ }
+
+ void startAsync() {
+ (new AMessage(kWhatStart, id()))->post();
+ }
+
+protected:
+ virtual ~Controller() {
+ }
+
+ virtual void onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatStart:
+ {
+#if 1
+ mDecodeLooper = looper();
+#else
+ mDecodeLooper = new ALooper;
+ mDecodeLooper->setName("sf2 decode looper");
+ mDecodeLooper->start();
+#endif
+
+ sp<DataSource> dataSource =
+ DataSource::CreateFromURI(mURI.c_str());
+
+ sp<MediaExtractor> extractor =
+ MediaExtractor::Create(dataSource);
+
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!strncasecmp(mDecodeAudio ? "audio/" : "video/",
+ mime, 6)) {
+ mSource = extractor->getTrack(i);
+ break;
+ }
+ }
+ CHECK(mSource != NULL);
+
+ CHECK_EQ(mSource->start(), (status_t)OK);
+
+ mDecodeLooper->registerHandler(mCodec);
+
+ mCodec->setNotificationMessage(
+ new AMessage(kWhatCodecNotify, id()));
+
+ sp<AMessage> format = makeFormat(mSource->getFormat());
+
+ if (mSurface != NULL) {
+ format->setObject("surface", mSurface);
+ }
+
+ mCodec->initiateSetup(format);
+
+ mCSDIndex = 0;
+ mStartTimeUs = ALooper::GetNowUs();
+ mNumOutputBuffersReceived = 0;
+ mTotalBytesReceived = 0;
+ mLeftOverBuffer = NULL;
+ mFinalResult = OK;
+ mSeekState = SEEK_NONE;
+
+ // (new AMessage(kWhatSeek, id()))->post(5000000ll);
+ break;
+ }
+
+ case kWhatSeek:
+ {
+ printf("+");
+ fflush(stdout);
+
+ CHECK(mSeekState == SEEK_NONE
+ || mSeekState == SEEK_FLUSH_COMPLETED);
+
+ if (mLeftOverBuffer != NULL) {
+ mLeftOverBuffer->release();
+ mLeftOverBuffer = NULL;
+ }
+
+ mSeekState = SEEK_FLUSHING;
+ mSeekTimeUs = 30000000ll;
+
+ mCodec->signalFlush();
+ break;
+ }
+
+ case kWhatStop:
+ {
+ if (mLeftOverBuffer != NULL) {
+ mLeftOverBuffer->release();
+ mLeftOverBuffer = NULL;
+ }
+
+ CHECK_EQ(mSource->stop(), (status_t)OK);
+ mSource.clear();
+
+ mCodec->initiateShutdown();
+ break;
+ }
+
+ case kWhatCodecNotify:
+ {
+ int32_t what;
+ CHECK(msg->findInt32("what", &what));
+
+ if (what == ACodec::kWhatFillThisBuffer) {
+ onFillThisBuffer(msg);
+ } else if (what == ACodec::kWhatDrainThisBuffer) {
+ if ((mNumOutputBuffersReceived++ % 16) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+
+ onDrainThisBuffer(msg);
+ } else if (what == ACodec::kWhatEOS) {
+ printf("$\n");
+
+ int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
+
+ if (mDecodeAudio) {
+ printf("%lld bytes received. %.2f KB/sec\n",
+ mTotalBytesReceived,
+ mTotalBytesReceived * 1E6 / 1024 / delayUs);
+ } else {
+ printf("%d frames decoded, %.2f fps. %lld bytes "
+ "received. %.2f KB/sec\n",
+ mNumOutputBuffersReceived,
+ mNumOutputBuffersReceived * 1E6 / delayUs,
+ mTotalBytesReceived,
+ mTotalBytesReceived * 1E6 / 1024 / delayUs);
+ }
+
+ (new AMessage(kWhatStop, id()))->post();
+ } else if (what == ACodec::kWhatFlushCompleted) {
+ mSeekState = SEEK_FLUSH_COMPLETED;
+ mCodec->signalResume();
+
+ (new AMessage(kWhatSeek, id()))->post(5000000ll);
+ } else if (what == ACodec::kWhatOutputFormatChanged) {
+ } else {
+ CHECK_EQ(what, (int32_t)ACodec::kWhatShutdownCompleted);
+
+ mDecodeLooper->unregisterHandler(mCodec->id());
+
+ if (mDecodeLooper != looper()) {
+ mDecodeLooper->stop();
+ }
+
+ looper()->stop();
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ break;
+ }
+ }
+
+private:
+ enum {
+ kWhatStart = 'strt',
+ kWhatStop = 'stop',
+ kWhatCodecNotify = 'noti',
+ kWhatSeek = 'seek',
+ };
+
+ sp<ALooper> mDecodeLooper;
+
+ AString mURI;
+ bool mDecodeAudio;
+ sp<Surface> mSurface;
+ sp<ACodec> mCodec;
+ sp<MediaSource> mSource;
+
+ Vector<sp<ABuffer> > mCSD;
+ size_t mCSDIndex;
+
+ MediaBuffer *mLeftOverBuffer;
+ status_t mFinalResult;
+
+ int64_t mStartTimeUs;
+ int32_t mNumOutputBuffersReceived;
+ int64_t mTotalBytesReceived;
+
+ enum SeekState {
+ SEEK_NONE,
+ SEEK_FLUSHING,
+ SEEK_FLUSH_COMPLETED,
+ };
+ SeekState mSeekState;
+ int64_t mSeekTimeUs;
+
+ sp<AMessage> makeFormat(const sp<MetaData> &meta) {
+ CHECK(mCSD.isEmpty());
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ sp<AMessage> msg = new AMessage;
+ msg->setString("mime", mime);
+
+ if (!strncasecmp("video/", mime, 6)) {
+ int32_t width, height;
+ CHECK(meta->findInt32(kKeyWidth, &width));
+ CHECK(meta->findInt32(kKeyHeight, &height));
+
+ msg->setInt32("width", width);
+ msg->setInt32("height", height);
+ } else {
+ CHECK(!strncasecmp("audio/", mime, 6));
+
+ int32_t numChannels, sampleRate;
+ CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+ CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+
+ msg->setInt32("channel-count", numChannels);
+ msg->setInt32("sample-rate", sampleRate);
+ }
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+ // Parse the AVCDecoderConfigurationRecord
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ CHECK(size >= 7);
+ CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
+ uint8_t profile = ptr[1];
+ uint8_t level = ptr[3];
+
+ // There is decodable content out there that fails the following
+ // assertion, let's be lenient for now...
+ // CHECK((ptr[4] >> 2) == 0x3f); // reserved
+
+ size_t lengthSize = 1 + (ptr[4] & 3);
+
+ // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
+ // violates it...
+ // CHECK((ptr[5] >> 5) == 7); // reserved
+
+ size_t numSeqParameterSets = ptr[5] & 31;
+
+ ptr += 6;
+ size -= 6;
+
+ sp<ABuffer> buffer = new ABuffer(1024);
+ buffer->setRange(0, 0);
+
+ for (size_t i = 0; i < numSeqParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
+ memcpy(buffer->data() + buffer->size() + 4, ptr, length);
+ buffer->setRange(0, buffer->size() + 4 + length);
+
+ ptr += length;
+ size -= length;
+ }
+
+ buffer->meta()->setInt32("csd", true);
+ mCSD.push(buffer);
+
+ buffer = new ABuffer(1024);
+ buffer->setRange(0, 0);
+
+ CHECK(size >= 1);
+ size_t numPictureParameterSets = *ptr;
+ ++ptr;
+ --size;
+
+ for (size_t i = 0; i < numPictureParameterSets; ++i) {
+ CHECK(size >= 2);
+ size_t length = U16_AT(ptr);
+
+ ptr += 2;
+ size -= 2;
+
+ CHECK(size >= length);
+
+ memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
+ memcpy(buffer->data() + buffer->size() + 4, ptr, length);
+ buffer->setRange(0, buffer->size() + 4 + length);
+
+ ptr += length;
+ size -= length;
+ }
+
+ buffer->meta()->setInt32("csd", true);
+ mCSD.push(buffer);
+
+ msg->setObject("csd", buffer);
+ } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
+ ESDS esds((const char *)data, size);
+ CHECK_EQ(esds.InitCheck(), (status_t)OK);
+
+ const void *codec_specific_data;
+ size_t codec_specific_data_size;
+ esds.getCodecSpecificInfo(
+ &codec_specific_data, &codec_specific_data_size);
+
+ sp<ABuffer> buffer = new ABuffer(codec_specific_data_size);
+
+ memcpy(buffer->data(), codec_specific_data,
+ codec_specific_data_size);
+
+ buffer->meta()->setInt32("csd", true);
+ mCSD.push(buffer);
+ }
+
+ int32_t maxInputSize;
+ if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
+ msg->setInt32("max-input-size", maxInputSize);
+ }
+
+ return msg;
+ }
+
+ void onFillThisBuffer(const sp<AMessage> &msg) {
+ sp<AMessage> reply;
+ CHECK(msg->findMessage("reply", &reply));
+
+ if (mSeekState == SEEK_FLUSHING) {
+ reply->post();
+ return;
+ }
+
+ sp<RefBase> obj;
+ CHECK(msg->findObject("buffer", &obj));
+ sp<ABuffer> outBuffer = static_cast<ABuffer *>(obj.get());
+
+ if (mCSDIndex < mCSD.size()) {
+ outBuffer = mCSD.editItemAt(mCSDIndex++);
+ outBuffer->meta()->setInt64("timeUs", 0);
+ } else {
+ size_t sizeLeft = outBuffer->capacity();
+ outBuffer->setRange(0, 0);
+
+ int32_t n = 0;
+
+ for (;;) {
+ MediaBuffer *inBuffer;
+
+ if (mLeftOverBuffer != NULL) {
+ inBuffer = mLeftOverBuffer;
+ mLeftOverBuffer = NULL;
+ } else if (mFinalResult != OK) {
+ break;
+ } else {
+ MediaSource::ReadOptions options;
+ if (mSeekState == SEEK_FLUSH_COMPLETED) {
+ options.setSeekTo(mSeekTimeUs);
+ mSeekState = SEEK_NONE;
+ }
+ status_t err = mSource->read(&inBuffer, &options);
+
+ if (err != OK) {
+ mFinalResult = err;
+ break;
+ }
+ }
+
+ if (inBuffer->range_length() > sizeLeft) {
+ if (outBuffer->size() == 0) {
+ LOGE("Unable to fit even a single input buffer of size %d.",
+ inBuffer->range_length());
+ }
+ CHECK_GT(outBuffer->size(), 0u);
+
+ mLeftOverBuffer = inBuffer;
+ break;
+ }
+
+ ++n;
+
+ if (outBuffer->size() == 0) {
+ int64_t timeUs;
+ CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+
+ outBuffer->meta()->setInt64("timeUs", timeUs);
+ }
+
+ memcpy(outBuffer->data() + outBuffer->size(),
+ (const uint8_t *)inBuffer->data()
+ + inBuffer->range_offset(),
+ inBuffer->range_length());
+
+ outBuffer->setRange(
+ 0, outBuffer->size() + inBuffer->range_length());
+
+ sizeLeft -= inBuffer->range_length();
+
+ inBuffer->release();
+ inBuffer = NULL;
+
+ // break; // Don't coalesce
+ }
+
+ LOGV("coalesced %d input buffers", n);
+
+ if (outBuffer->size() == 0) {
+ CHECK_NE(mFinalResult, (status_t)OK);
+
+ reply->setInt32("err", mFinalResult);
+ reply->post();
+ return;
+ }
+ }
+
+ reply->setObject("buffer", outBuffer);
+ reply->post();
+ }
+
+ void onDrainThisBuffer(const sp<AMessage> &msg) {
+ sp<RefBase> obj;
+ CHECK(msg->findObject("buffer", &obj));
+
+ sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
+ mTotalBytesReceived += buffer->size();
+
+ sp<AMessage> reply;
+ CHECK(msg->findMessage("reply", &reply));
+
+ reply->post();
+ }
+
+ DISALLOW_EVIL_CONSTRUCTORS(Controller);
+};
+
+static void usage(const char *me) {
+ fprintf(stderr, "usage: %s\n", me);
+ fprintf(stderr, " -h(elp)\n");
+ fprintf(stderr, " -a(udio)\n");
+
+ fprintf(stderr,
+ " -s(surface) Allocate output buffers on a surface.\n");
+}
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+ bool decodeAudio = false;
+ bool useSurface = false;
+
+ int res;
+ while ((res = getopt(argc, argv, "has")) >= 0) {
+ switch (res) {
+ case 'a':
+ decodeAudio = true;
+ break;
+
+ case 's':
+ useSurface = true;
+ break;
+
+ case '?':
+ case 'h':
+ default:
+ {
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1) {
+ usage(argv[-optind]);
+ return 1;
+ }
+
+ DataSource::RegisterDefaultSniffers();
+
+ sp<ALooper> looper = new ALooper;
+ looper->setName("sf2");
+
+ sp<SurfaceComposerClient> composerClient;
+ sp<SurfaceControl> control;
+ sp<Surface> surface;
+
+ if (!decodeAudio && useSurface) {
+ composerClient = new SurfaceComposerClient;
+ CHECK_EQ(composerClient->initCheck(), (status_t)OK);
+
+ control = composerClient->createSurface(
+ getpid(),
+ String8("A Surface"),
+ 0,
+ 1280,
+ 800,
+ PIXEL_FORMAT_RGB_565,
+ 0);
+
+ CHECK(control != NULL);
+ CHECK(control->isValid());
+
+ CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ CHECK_EQ(control->setLayer(30000), (status_t)OK);
+ CHECK_EQ(control->show(), (status_t)OK);
+ CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+
+ surface = control->getSurface();
+ CHECK(surface != NULL);
+ }
+
+ sp<Controller> controller = new Controller(argv[0], decodeAudio, surface);
+ looper->registerHandler(controller);
+
+ controller->startAsync();
+
+ CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK);
+
+ looper->unregisterHandler(controller->id());
+
+ if (!decodeAudio && useSurface) {
+ composerClient->dispose();
+ }
+
+ return 0;
+}
+
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index ff92431..a875c3a 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,7 +31,7 @@
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ALooper.h>
#include "include/ARTSPController.h"
-#include "include/LiveSource.h"
+#include "include/LiveSession.h"
#include "include/NuCachedSource2.h"
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/DataSource.h>
@@ -49,8 +49,17 @@
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
+#include <private/media/VideoFrame.h>
+#include <SkBitmap.h>
+#include <SkImageEncoder.h>
+
#include <fcntl.h>
+#include <gui/SurfaceTextureClient.h>
+
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
using namespace android;
static long gNumRepetitions;
@@ -59,8 +68,13 @@ static long gReproduceBug; // if not -1.
static bool gPreferSoftwareCodec;
static bool gPlaybackAudio;
static bool gWriteMP4;
+static bool gDisplayHistogram;
static String8 gWriteMP4Filename;
+static sp<ANativeWindow> gSurface;
+
+#define USE_SURFACE_COMPOSER 0
+
static int64_t getNowUs() {
struct timeval tv;
gettimeofday(&tv, NULL);
@@ -68,6 +82,58 @@ static int64_t getNowUs() {
return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
}
+static int CompareIncreasing(const int64_t *a, const int64_t *b) {
+ return (*a) < (*b) ? -1 : (*a) > (*b) ? 1 : 0;
+}
+
+static void displayDecodeHistogram(Vector<int64_t> *decodeTimesUs) {
+ printf("decode times:\n");
+
+ decodeTimesUs->sort(CompareIncreasing);
+
+ size_t n = decodeTimesUs->size();
+ int64_t minUs = decodeTimesUs->itemAt(0);
+ int64_t maxUs = decodeTimesUs->itemAt(n - 1);
+
+ printf("min decode time %lld us (%.2f secs)\n", minUs, minUs / 1E6);
+ printf("max decode time %lld us (%.2f secs)\n", maxUs, maxUs / 1E6);
+
+ size_t counts[100];
+ for (size_t i = 0; i < 100; ++i) {
+ counts[i] = 0;
+ }
+
+ for (size_t i = 0; i < n; ++i) {
+ int64_t x = decodeTimesUs->itemAt(i);
+
+ size_t slot = ((x - minUs) * 100) / (maxUs - minUs);
+ if (slot == 100) { slot = 99; }
+
+ ++counts[slot];
+ }
+
+ for (size_t i = 0; i < 100; ++i) {
+ int64_t slotUs = minUs + (i * (maxUs - minUs) / 100);
+
+ double fps = 1E6 / slotUs;
+ printf("[%.2f fps]: %d\n", fps, counts[i]);
+ }
+}
+
+static void displayAVCProfileLevelIfPossible(const sp<MetaData>& meta) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyAVCC, &type, &data, &size)) {
+ const uint8_t *ptr = (const uint8_t *)data;
+ CHECK(size >= 7);
+ CHECK(ptr[0] == 1); // configurationVersion == 1
+ uint8_t profile = ptr[1];
+ uint8_t level = ptr[3];
+ fprintf(stderr, "AVC video profile %d and level %d\n", profile, level);
+ }
+}
+
static void playSource(OMXClient *client, sp<MediaSource> &source) {
sp<MetaData> meta = source->getFormat();
@@ -81,12 +147,14 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) {
rawSource = OMXCodec::Create(
client->interface(), meta, false /* createEncoder */, source,
NULL /* matchComponentName */,
- gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
+ gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0,
+ gSurface);
if (rawSource == NULL) {
fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
return;
}
+ displayAVCProfileLevelIfPossible(meta);
}
source.clear();
@@ -201,6 +269,8 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) {
int64_t sumDecodeUs = 0;
int64_t totalBytes = 0;
+ Vector<int64_t> decodeTimesUs;
+
while (numIterationsLeft-- > 0) {
long numFrames = 0;
@@ -224,9 +294,17 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) {
break;
}
- if (buffer->range_length() > 0 && (n++ % 16) == 0) {
- printf(".");
- fflush(stdout);
+ if (buffer->range_length() > 0) {
+ if (gDisplayHistogram && n > 0) {
+ // Ignore the first time since it includes some setup
+ // cost.
+ decodeTimesUs.push(delayDecodeUs);
+ }
+
+ if ((n++ % 16) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
}
sumDecodeUs += delayDecodeUs;
@@ -266,6 +344,10 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) {
(double)sumDecodeUs / n);
printf("decoded a total of %d frame(s).\n", n);
+
+ if (gDisplayHistogram) {
+ displayDecodeHistogram(&decodeTimesUs);
+ }
} else if (!strncasecmp("audio/", mime, 6)) {
// Frame count makes less sense for audio, as the output buffer
// sizes may be different across decoders.
@@ -466,6 +548,9 @@ static void usage(const char *me) {
fprintf(stderr, " -o playback audio\n");
fprintf(stderr, " -w(rite) filename (write to .mp4 file)\n");
fprintf(stderr, " -k seek test\n");
+ fprintf(stderr, " -x display a histogram of decoding times/fps "
+ "(video only)\n");
+ fprintf(stderr, " -S allocate buffers from a surface\n");
}
int main(int argc, char **argv) {
@@ -476,18 +561,21 @@ int main(int argc, char **argv) {
bool dumpProfiles = false;
bool extractThumbnail = false;
bool seekTest = false;
+ bool useSurfaceAlloc = false;
gNumRepetitions = 1;
gMaxNumFrames = 0;
gReproduceBug = -1;
gPreferSoftwareCodec = false;
gPlaybackAudio = false;
gWriteMP4 = false;
+ gDisplayHistogram = false;
sp<ALooper> looper;
sp<ARTSPController> rtspController;
+ sp<LiveSession> liveSession;
int res;
- while ((res = getopt(argc, argv, "han:lm:b:ptsow:k")) >= 0) {
+ while ((res = getopt(argc, argv, "han:lm:b:ptsow:kxS")) >= 0) {
switch (res) {
case 'a':
{
@@ -560,6 +648,18 @@ int main(int argc, char **argv) {
break;
}
+ case 'x':
+ {
+ gDisplayHistogram = true;
+ break;
+ }
+
+ case 'S':
+ {
+ useSurfaceAlloc = true;
+ break;
+ }
+
case '?':
case 'h':
default:
@@ -602,6 +702,19 @@ int main(int argc, char **argv) {
if (mem != NULL) {
printf("getFrameAtTime(%s) => OK\n", filename);
+
+ VideoFrame *frame = (VideoFrame *)mem->pointer();
+
+ SkBitmap bitmap;
+ bitmap.setConfig(
+ SkBitmap::kRGB_565_Config, frame->mWidth, frame->mHeight);
+
+ bitmap.setPixels((uint8_t *)frame + sizeof(VideoFrame));
+
+ CHECK(SkImageEncoder::EncodeFile(
+ "/sdcard/out.jpg", bitmap,
+ SkImageEncoder::kJPEG_Type,
+ SkImageEncoder::kDefaultQuality));
} else {
mem = retriever->extractAlbumArt();
@@ -685,6 +798,39 @@ int main(int argc, char **argv) {
}
}
+ sp<SurfaceComposerClient> composerClient;
+ sp<SurfaceControl> control;
+
+ if (useSurfaceAlloc && !audioOnly) {
+#if USE_SURFACE_COMPOSER
+ composerClient = new SurfaceComposerClient;
+ CHECK_EQ(composerClient->initCheck(), (status_t)OK);
+
+ control = composerClient->createSurface(
+ getpid(),
+ String8("A Surface"),
+ 0,
+ 1280,
+ 800,
+ PIXEL_FORMAT_RGB_565,
+ 0);
+
+ CHECK(control != NULL);
+ CHECK(control->isValid());
+
+ CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ CHECK_EQ(control->setLayer(30000), (status_t)OK);
+ CHECK_EQ(control->show(), (status_t)OK);
+ CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+
+ gSurface = control->getSurface();
+ CHECK(gSurface != NULL);
+#else
+ sp<SurfaceTexture> texture = new SurfaceTexture(0 /* tex */);
+ gSurface = new SurfaceTextureClient(texture);
+#endif
+ }
+
DataSource::RegisterDefaultSniffers();
OMXClient client;
@@ -754,8 +900,15 @@ int main(int argc, char **argv) {
String8 uri("http://");
uri.append(filename + 11);
- dataSource = new LiveSource(uri.string());
- dataSource = new NuCachedSource2(dataSource);
+ if (looper == NULL) {
+ looper = new ALooper;
+ looper->start();
+ }
+ liveSession = new LiveSession;
+ looper->registerHandler(liveSession);
+
+ liveSession->connect(uri.string());
+ dataSource = liveSession->getDataSource();
extractor =
MediaExtractor::Create(
@@ -855,6 +1008,14 @@ int main(int argc, char **argv) {
}
}
+ if (useSurfaceAlloc && !audioOnly) {
+ gSurface.clear();
+
+#if USE_SURFACE_COMPOSER
+ composerClient->dispose();
+#endif
+ }
+
client.disconnect();
return 0;
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
new file mode 100644
index 0000000..bb84bd1
--- /dev/null
+++ b/cmds/stagefright/stream.cpp
@@ -0,0 +1,206 @@
+/*
+ * 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/ProcessState.h>
+
+#include <media/IStreamSource.h>
+#include <media/mediaplayer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <fcntl.h>
+
+using namespace android;
+
+struct MyStreamSource : public BnStreamSource {
+ // Caller retains ownership of fd.
+ MyStreamSource(int fd);
+
+ virtual void setListener(const sp<IStreamListener> &listener);
+ virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
+
+ virtual void onBufferAvailable(size_t index);
+
+protected:
+ virtual ~MyStreamSource();
+
+private:
+ int mFd;
+ off64_t mFileSize;
+ int64_t mNextSeekTimeUs;
+
+ sp<IStreamListener> mListener;
+ Vector<sp<IMemory> > mBuffers;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MyStreamSource);
+};
+
+MyStreamSource::MyStreamSource(int fd)
+ : mFd(fd),
+ mFileSize(0),
+ mNextSeekTimeUs(-1) { // ALooper::GetNowUs() + 5000000ll) {
+ CHECK_GE(fd, 0);
+
+ mFileSize = lseek64(fd, 0, SEEK_END);
+ lseek64(fd, 0, SEEK_SET);
+}
+
+MyStreamSource::~MyStreamSource() {
+}
+
+void MyStreamSource::setListener(const sp<IStreamListener> &listener) {
+ mListener = listener;
+}
+
+void MyStreamSource::setBuffers(const Vector<sp<IMemory> > &buffers) {
+ mBuffers = buffers;
+}
+
+void MyStreamSource::onBufferAvailable(size_t index) {
+ CHECK_LT(index, mBuffers.size());
+
+ if (mNextSeekTimeUs >= 0 && mNextSeekTimeUs <= ALooper::GetNowUs()) {
+ off64_t offset = (off64_t)(((float)rand() / RAND_MAX) * mFileSize * 0.8);
+ offset = (offset / 188) * 188;
+
+ lseek(mFd, offset, SEEK_SET);
+
+ mListener->issueCommand(
+ IStreamListener::DISCONTINUITY, false /* synchronous */);
+
+ mNextSeekTimeUs = -1;
+ mNextSeekTimeUs = ALooper::GetNowUs() + 5000000ll;
+ }
+
+ sp<IMemory> mem = mBuffers.itemAt(index);
+
+ ssize_t n = read(mFd, mem->pointer(), mem->size());
+ if (n <= 0) {
+ mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
+ } else {
+ mListener->queueBuffer(index, n);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct MyClient : public BnMediaPlayerClient {
+ MyClient()
+ : mEOS(false) {
+ }
+
+ virtual void notify(int msg, int ext1, int ext2) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
+ mEOS = true;
+ mCondition.signal();
+ }
+ }
+
+ void waitForEOS() {
+ Mutex::Autolock autoLock(mLock);
+ while (!mEOS) {
+ mCondition.wait(mLock);
+ }
+ }
+
+protected:
+ virtual ~MyClient() {
+ }
+
+private:
+ Mutex mLock;
+ Condition mCondition;
+
+ bool mEOS;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MyClient);
+};
+
+int main(int argc, char **argv) {
+ android::ProcessState::self()->startThreadPool();
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s filename\n", argv[0]);
+ return 1;
+ }
+
+ sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
+ CHECK_EQ(composerClient->initCheck(), (status_t)OK);
+
+ sp<SurfaceControl> control =
+ composerClient->createSurface(
+ getpid(),
+ String8("A Surface"),
+ 0,
+ 1280,
+ 800,
+ PIXEL_FORMAT_RGB_565,
+ 0);
+
+ CHECK(control != NULL);
+ CHECK(control->isValid());
+
+ CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ CHECK_EQ(control->setLayer(30000), (status_t)OK);
+ CHECK_EQ(control->show(), (status_t)OK);
+ CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+
+ sp<Surface> surface = control->getSurface();
+ CHECK(surface != NULL);
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.player"));
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+
+ CHECK(service.get() != NULL);
+
+ int fd = open(argv[1], O_RDONLY);
+
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open file '%s'.", argv[1]);
+ return 1;
+ }
+
+ sp<MyClient> client = new MyClient;
+
+ sp<IMediaPlayer> player =
+ service->create(getpid(), client, new MyStreamSource(fd), 0);
+
+ if (player != NULL) {
+ player->setVideoSurface(surface);
+ player->start();
+
+ client->waitForEOS();
+
+ player->stop();
+ } else {
+ fprintf(stderr, "failed to instantiate player.\n");
+ }
+
+ close(fd);
+ fd = -1;
+
+ composerClient->dispose();
+
+ return 0;
+}
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
index 457cbd4..e8afce3 100644
--- a/cmds/system_server/library/Android.mk
+++ b/cmds/system_server/library/Android.mk
@@ -21,6 +21,7 @@ LOCAL_SHARED_LIBRARIES := \
libaudioflinger \
libcameraservice \
libmediaplayerservice \
+ libinput \
libutils \
libbinder \
libcutils