summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.xml47
-rw-r--r--cmds/dumpstate/dumpstate.c11
-rw-r--r--core/java/android/app/ActivityThread.java85
-rw-r--r--core/java/android/app/ApplicationThreadNative.java4
-rw-r--r--core/java/android/content/res/Configuration.java127
-rw-r--r--core/java/android/os/Binder.java33
-rw-r--r--core/java/android/os/Environment.java45
-rw-r--r--core/java/android/os/IBinder.java10
-rw-r--r--core/java/android/os/Parcel.java2
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java11
-rw-r--r--core/java/android/os/storage/IMountService.java14
-rw-r--r--core/java/android/os/storage/StorageManager.java27
-rw-r--r--core/java/android/os/storage/StorageVolume.aidl19
-rw-r--r--core/java/android/os/storage/StorageVolume.java147
-rw-r--r--core/jni/android_util_Binder.cpp35
-rwxr-xr-xcore/res/res/values/attrs.xml17
-rwxr-xr-xcore/res/res/values/config.xml50
-rwxr-xr-xcore/res/res/values/strings.xml8
-rw-r--r--core/res/res/xml/storage_list.xml40
-rw-r--r--docs/html/guide/topics/usb/adk.jd61
-rw-r--r--docs/html/sdk/android-3.1.jd4
-rw-r--r--docs/html/sdk/oem-usb.jd5
-rw-r--r--docs/html/videos/index.jd14
-rw-r--r--media/java/android/media/MediaScanner.java3
-rw-r--r--services/java/com/android/server/MountService.java109
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java674
-rw-r--r--services/java/com/android/server/am/ActivityRecord.java2
-rw-r--r--services/java/com/android/server/am/ContentProviderRecord.java2
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java2
-rw-r--r--services/java/com/android/server/am/TransferPipe.java242
30 files changed, 1401 insertions, 449 deletions
diff --git a/api/current.xml b/api/current.xml
index b85ace5366e4..ba4fa7be4b95 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -143329,6 +143329,21 @@
<parameter name="args" type="java.lang.String[]">
</parameter>
</method>
+<method name="dumpAsync"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<parameter name="args" type="java.lang.String[]">
+</parameter>
+</method>
<method name="flushPendingCommands"
return="void"
abstract="false"
@@ -147801,6 +147816,23 @@
<exception name="RemoteException" type="android.os.RemoteException">
</exception>
</method>
+<method name="dumpAsync"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<parameter name="args" type="java.lang.String[]">
+</parameter>
+<exception name="RemoteException" type="android.os.RemoteException">
+</exception>
+</method>
<method name="getInterfaceDescriptor"
return="java.lang.String"
abstract="true"
@@ -150155,6 +150187,21 @@
visibility="public"
>
</method>
+<method name="dup"
+ return="android.os.ParcelFileDescriptor"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="orig" type="java.io.FileDescriptor">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
<method name="fromSocket"
return="android.os.ParcelFileDescriptor"
abstract="false"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 77386489abf7..ccc4fd78c1dd 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -186,11 +186,16 @@ static void dumpstate() {
run_command("DUMPSYS", 60, "dumpsys", NULL);
printf("========================================================\n");
- printf("== Application Services\n");
+ printf("== Running Application Activities\n");
printf("========================================================\n");
- /* Instead of a 60s timeout, we should give each service a 5 second timeout */
- run_command("APP SERVICES", 60, "dumpsys", "activity", "service", NULL);
+ 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);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 67e88396a883..6c8f85f2cb32 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -367,11 +367,10 @@ public final class ActivityThread {
}
static final class DumpComponentInfo {
- FileDescriptor fd;
+ ParcelFileDescriptor fd;
IBinder token;
String prefix;
String[] args;
- boolean dumped;
}
static final class ResultData {
@@ -639,20 +638,13 @@ public final class ActivityThread {
public void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args) {
DumpComponentInfo data = new DumpComponentInfo();
- data.fd = fd;
- data.token = servicetoken;
- data.args = args;
- data.dumped = false;
- queueOrSendMessage(H.DUMP_SERVICE, data);
- synchronized (data) {
- while (!data.dumped) {
- try {
- data.wait();
- } catch (InterruptedException e) {
- // no need to do anything here, we will keep waiting until
- // dumped is set
- }
- }
+ try {
+ data.fd = ParcelFileDescriptor.dup(fd);
+ data.token = servicetoken;
+ data.args = args;
+ queueOrSendMessage(H.DUMP_SERVICE, data);
+ } catch (IOException e) {
+ Slog.w(TAG, "dumpService failed", e);
}
}
@@ -714,21 +706,14 @@ public final class ActivityThread {
public void dumpActivity(FileDescriptor fd, IBinder activitytoken,
String prefix, String[] args) {
DumpComponentInfo data = new DumpComponentInfo();
- data.fd = fd;
- data.token = activitytoken;
- data.prefix = prefix;
- data.args = args;
- data.dumped = false;
- queueOrSendMessage(H.DUMP_ACTIVITY, data);
- synchronized (data) {
- while (!data.dumped) {
- try {
- data.wait();
- } catch (InterruptedException e) {
- // no need to do anything here, we will keep waiting until
- // dumped is set
- }
- }
+ try {
+ data.fd = ParcelFileDescriptor.dup(fd);
+ data.token = activitytoken;
+ data.prefix = prefix;
+ data.args = args;
+ queueOrSendMessage(H.DUMP_ACTIVITY, data);
+ } catch (IOException e) {
+ Slog.w(TAG, "dumpActivity failed", e);
}
}
@@ -2154,33 +2139,27 @@ public final class ActivityThread {
}
private void handleDumpService(DumpComponentInfo info) {
- try {
- Service s = mServices.get(info.token);
- if (s != null) {
- PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd));
- s.dump(info.fd, pw, info.args);
- pw.close();
- }
- } finally {
- synchronized (info) {
- info.dumped = true;
- info.notifyAll();
+ Service s = mServices.get(info.token);
+ if (s != null) {
+ PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor()));
+ s.dump(info.fd.getFileDescriptor(), pw, info.args);
+ pw.flush();
+ try {
+ info.fd.close();
+ } catch (IOException e) {
}
}
}
private void handleDumpActivity(DumpComponentInfo info) {
- try {
- ActivityClientRecord r = mActivities.get(info.token);
- if (r != null && r.activity != null) {
- PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd));
- r.activity.dump(info.prefix, info.fd, pw, info.args);
- pw.close();
- }
- } finally {
- synchronized (info) {
- info.dumped = true;
- info.notifyAll();
+ ActivityClientRecord r = mActivities.get(info.token);
+ if (r != null && r.activity != null) {
+ PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor()));
+ r.activity.dump(info.prefix, info.fd.getFileDescriptor(), pw, info.args);
+ pw.flush();
+ try {
+ info.fd.close();
+ } catch (IOException e) {
}
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index e1d76a44e477..850ad2bfa581 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -845,7 +845,7 @@ class ApplicationThreadProxy implements IApplicationThread {
data.writeFileDescriptor(fd);
data.writeStrongBinder(token);
data.writeStringArray(args);
- mRemote.transact(DUMP_SERVICE_TRANSACTION, data, null, 0);
+ mRemote.transact(DUMP_SERVICE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
@@ -967,7 +967,7 @@ class ApplicationThreadProxy implements IApplicationThread {
data.writeStrongBinder(token);
data.writeString(prefix);
data.writeStringArray(args);
- mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, 0);
+ mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index de2b1dada893..4ac72fdc1c15 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -303,45 +303,106 @@ public final class Configuration implements Parcelable, Comparable<Configuration
public String toString() {
StringBuilder sb = new StringBuilder(128);
- sb.append("{ scale=");
+ sb.append("{ fnt=");
sb.append(fontScale);
sb.append(" imsi=");
sb.append(mcc);
sb.append("/");
sb.append(mnc);
- sb.append(" loc=");
- sb.append(locale);
- sb.append(" touch=");
- sb.append(touchscreen);
- sb.append(" keys=");
- sb.append(keyboard);
- sb.append("/");
- sb.append(keyboardHidden);
- sb.append("/");
- sb.append(hardKeyboardHidden);
- sb.append(" nav=");
- sb.append(navigation);
- sb.append("/");
- sb.append(navigationHidden);
- sb.append(" orien=");
- switch(orientation) {
- case ORIENTATION_LANDSCAPE:
- sb.append("L"); break;
- case ORIENTATION_PORTRAIT:
- sb.append("P"); break;
- default:
- sb.append(orientation);
- }
- sb.append(" layout=0x");
- sb.append(java.lang.Integer.toHexString(screenLayout));
- sb.append(" uiMode=0x");
- sb.append(java.lang.Integer.toHexString(uiMode));
- sb.append(" wdp=");
- sb.append(screenWidthDp);
- sb.append(" hdp=");
- sb.append(screenHeightDp);
+ if (locale != null) {
+ sb.append(" ");
+ sb.append(locale);
+ } else {
+ sb.append(" (no locale)");
+ }
+ switch (touchscreen) {
+ case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break;
+ case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break;
+ case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break;
+ case TOUCHSCREEN_FINGER: sb.append(" finger"); break;
+ default: sb.append(" touch="); sb.append(touchscreen); break;
+ }
+ switch (keyboard) {
+ case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break;
+ case KEYBOARD_NOKEYS: sb.append(" -keyb"); break;
+ case KEYBOARD_QWERTY: sb.append(" qwerty"); break;
+ case KEYBOARD_12KEY: sb.append(" 12key"); break;
+ default: sb.append(" keys="); sb.append(keyboard); break;
+ }
+ switch (keyboardHidden) {
+ case KEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
+ case KEYBOARDHIDDEN_NO: sb.append("/v"); break;
+ case KEYBOARDHIDDEN_YES: sb.append("/h"); break;
+ case KEYBOARDHIDDEN_SOFT: sb.append("/s"); break;
+ default: sb.append("/"); sb.append(keyboardHidden); break;
+ }
+ switch (hardKeyboardHidden) {
+ case HARDKEYBOARDHIDDEN_UNDEFINED: sb.append("/?"); break;
+ case HARDKEYBOARDHIDDEN_NO: sb.append("/v"); break;
+ case HARDKEYBOARDHIDDEN_YES: sb.append("/h"); break;
+ default: sb.append("/"); sb.append(hardKeyboardHidden); break;
+ }
+ switch (navigation) {
+ case NAVIGATION_UNDEFINED: sb.append(" ?nav"); break;
+ case NAVIGATION_NONAV: sb.append(" -nav"); break;
+ case NAVIGATION_DPAD: sb.append(" dpad"); break;
+ case NAVIGATION_TRACKBALL: sb.append(" tball"); break;
+ case NAVIGATION_WHEEL: sb.append(" wheel"); break;
+ default: sb.append(" nav="); sb.append(navigation); break;
+ }
+ switch (navigationHidden) {
+ case NAVIGATIONHIDDEN_UNDEFINED: sb.append("/?"); break;
+ case NAVIGATIONHIDDEN_NO: sb.append("/v"); break;
+ case NAVIGATIONHIDDEN_YES: sb.append("/h"); break;
+ default: sb.append("/"); sb.append(navigationHidden); break;
+ }
+ switch (orientation) {
+ case ORIENTATION_UNDEFINED: sb.append(" ?orien"); break;
+ case ORIENTATION_LANDSCAPE: sb.append(" land"); break;
+ case ORIENTATION_PORTRAIT: sb.append(" port"); break;
+ default: sb.append(" orien="); sb.append(orientation); break;
+ }
+ switch ((screenLayout&SCREENLAYOUT_SIZE_MASK)) {
+ case SCREENLAYOUT_SIZE_UNDEFINED: sb.append(" ?lsize"); break;
+ case SCREENLAYOUT_SIZE_SMALL: sb.append(" smll"); break;
+ case SCREENLAYOUT_SIZE_NORMAL: sb.append(" nrml"); break;
+ case SCREENLAYOUT_SIZE_LARGE: sb.append(" lrg"); break;
+ case SCREENLAYOUT_SIZE_XLARGE: sb.append(" xlrg"); break;
+ default: sb.append(" layoutSize=");
+ sb.append(screenLayout&SCREENLAYOUT_SIZE_MASK); break;
+ }
+ switch ((screenLayout&SCREENLAYOUT_LONG_MASK)) {
+ case SCREENLAYOUT_LONG_UNDEFINED: sb.append(" ?long"); break;
+ case SCREENLAYOUT_LONG_NO: /* not-long is not interesting to print */ break;
+ case SCREENLAYOUT_LONG_YES: sb.append(" long"); break;
+ default: sb.append(" layoutLong=");
+ sb.append(screenLayout&SCREENLAYOUT_LONG_MASK); break;
+ }
+ switch ((uiMode&UI_MODE_TYPE_MASK)) {
+ case UI_MODE_TYPE_UNDEFINED: sb.append(" ?uimode"); break;
+ case UI_MODE_TYPE_NORMAL: /* normal is not interesting to print */ break;
+ case UI_MODE_TYPE_DESK: sb.append(" desk"); break;
+ case UI_MODE_TYPE_CAR: sb.append(" car"); break;
+ default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
+ }
+ switch ((uiMode&UI_MODE_NIGHT_MASK)) {
+ case UI_MODE_NIGHT_UNDEFINED: sb.append(" ?night"); break;
+ case UI_MODE_NIGHT_NO: /* not-night is not interesting to print */ break;
+ case UI_MODE_NIGHT_YES: sb.append(" night"); break;
+ default: sb.append(" night="); sb.append(uiMode&UI_MODE_NIGHT_MASK); break;
+ }
+ if (screenWidthDp != SCREEN_WIDTH_DP_UNDEFINED) {
+ sb.append(" w"); sb.append(screenWidthDp); sb.append("dp");
+ } else {
+ sb.append("?wdp");
+ }
+ if (screenHeightDp != SCREEN_HEIGHT_DP_UNDEFINED) {
+ sb.append(" h"); sb.append(screenHeightDp); sb.append("dp");
+ } else {
+ sb.append("?hdp");
+ }
if (seq != 0) {
- sb.append(" seq=");
+ sb.append(" s.");
sb.append(seq);
}
sb.append('}');
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 7dc36f99ca65..ae1e1c2615fd 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -256,6 +256,25 @@ public class Binder implements IBinder {
}
/**
+ * Like {@link #dump(FileDescriptor, String[])}, but ensures the target
+ * executes asynchronously.
+ */
+ public void dumpAsync(final FileDescriptor fd, final String[] args) {
+ final FileOutputStream fout = new FileOutputStream(fd);
+ final PrintWriter pw = new PrintWriter(fout);
+ Thread thr = new Thread("Binder.dumpAsync") {
+ public void run() {
+ try {
+ dump(fd, pw, args);
+ } finally {
+ pw.flush();
+ }
+ }
+ };
+ thr.start();
+ }
+
+ /**
* Print the object's state into the given stream.
*
* @param fd The raw file descriptor that the dump is being sent to.
@@ -364,6 +383,20 @@ final class BinderProxy implements IBinder {
}
}
+ public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ try {
+ transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
+ reply.readException();
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
BinderProxy() {
mSelf = new WeakReference(this);
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e308c2c48a8d..1f3f6d9565b6 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -20,6 +20,7 @@ import java.io.File;
import android.content.res.Resources;
import android.os.storage.IMountService;
+import android.os.storage.StorageVolume;
import android.util.Log;
/**
@@ -35,7 +36,25 @@ public class Environment {
private static final Object mLock = new Object();
- private volatile static Boolean mIsExternalStorageEmulated = null;
+ private volatile static StorageVolume mPrimaryVolume = null;
+
+ private static StorageVolume getPrimaryVolume() {
+ if (mPrimaryVolume == null) {
+ synchronized (mLock) {
+ if (mPrimaryVolume == null) {
+ try {
+ IMountService mountService = IMountService.Stub.asInterface(ServiceManager
+ .getService("mount"));
+ Parcelable[] volumes = mountService.getVolumeList();
+ mPrimaryVolume = (StorageVolume)volumes[0];
+ } catch (Exception e) {
+ Log.e(TAG, "couldn't talk to MountService", e);
+ }
+ }
+ }
+ }
+ return mPrimaryVolume;
+ }
/**
* Gets the Android root directory.
@@ -416,9 +435,8 @@ public class Environment {
* <p>See {@link #getExternalStorageDirectory()} for more information.
*/
public static boolean isExternalStorageRemovable() {
- if (isExternalStorageEmulated()) return false;
- return Resources.getSystem().getBoolean(
- com.android.internal.R.bool.config_externalStorageRemovable);
+ StorageVolume volume = getPrimaryVolume();
+ return (volume != null && volume.isRemovable());
}
/**
@@ -435,23 +453,8 @@ public class Environment {
* android.content.ComponentName, boolean)} for additional details.
*/
public static boolean isExternalStorageEmulated() {
- if (mIsExternalStorageEmulated == null) {
- synchronized (mLock) {
- if (mIsExternalStorageEmulated == null) {
- boolean externalStorageEmulated;
- try {
- IMountService mountService = IMountService.Stub.asInterface(ServiceManager
- .getService("mount"));
- externalStorageEmulated = mountService.isExternalStorageEmulated();
- mIsExternalStorageEmulated = Boolean.valueOf(externalStorageEmulated);
- } catch (Exception e) {
- Log.e(TAG, "couldn't talk to MountService", e);
- return false;
- }
- }
- }
- }
- return mIsExternalStorageEmulated;
+ StorageVolume volume = getPrimaryVolume();
+ return (volume != null && volume.isEmulated());
}
static File getDirectory(String variableName, String defaultPath) {
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 8ae800854027..887635458622 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -157,6 +157,16 @@ public interface IBinder {
public void dump(FileDescriptor fd, String[] args) throws RemoteException;
/**
+ * Like {@link #dump(FileDescriptor, String[])} but always executes
+ * asynchronously. If the object is local, a new thread is created
+ * to perform the dump.
+ *
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param args additional arguments to the dump request.
+ */
+ public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;
+
+ /**
* Perform a generic operation with the object.
*
* @param code The action to perform. This should
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index eca348485bba..6b352158120c 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1383,6 +1383,8 @@ public final class Parcel {
private native FileDescriptor internalReadFileDescriptor();
/*package*/ static native FileDescriptor openFileDescriptor(String file,
int mode) throws FileNotFoundException;
+ /*package*/ static native FileDescriptor dupFileDescriptor(FileDescriptor orig)
+ throws IOException;
/*package*/ static native void closeFileDescriptor(FileDescriptor desc)
throws IOException;
/*package*/ static native void clearFileDescriptor(FileDescriptor desc);
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 5bd129f19166..aa959b4ded1a 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -117,6 +117,17 @@ public class ParcelFileDescriptor implements Parcelable {
}
/**
+ * Create a new ParcelFileDescriptor that is a dup of an existing
+ * FileDescriptor. This obeys standard POSIX semantics, where the
+ * new file descriptor shared state such as file position with the
+ * original file descriptor.
+ */
+ public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
+ FileDescriptor fd = Parcel.dupFileDescriptor(orig);
+ return fd != null ? new ParcelFileDescriptor(fd) : null;
+ }
+
+ /**
* Create a new ParcelFileDescriptor from the specified Socket.
*
* @param socket The Socket whose FileDescriptor is used to create
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 27da3c344880..c2dc8aeefc43 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -20,7 +20,9 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
+import android.os.Parcelable;
import android.os.RemoteException;
+import android.os.storage.StorageVolume;
/**
* WARNING! Update IMountService.h and IMountService.cpp if you change this
@@ -638,15 +640,15 @@ public interface IMountService extends IInterface {
return _result;
}
- public String[] getVolumeList() throws RemoteException {
+ public Parcelable[] getVolumeList() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
- String[] _result;
+ Parcelable[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0);
_reply.readException();
- _result = _reply.readStringArray();
+ _result = _reply.readParcelableArray(StorageVolume.class.getClassLoader());
} finally {
_reply.recycle();
_data.recycle();
@@ -1024,9 +1026,9 @@ public interface IMountService extends IInterface {
}
case TRANSACTION_getVolumeList: {
data.enforceInterface(DESCRIPTOR);
- String[] result = getVolumeList();
+ Parcelable[] result = getVolumeList();
reply.writeNoException();
- reply.writeStringArray(result);
+ reply.writeParcelableArray(result, 0);
return true;
}
}
@@ -1207,5 +1209,5 @@ public interface IMountService extends IInterface {
/**
* Returns list of all mountable volumes.
*/
- public String[] getVolumeList() throws RemoteException;
+ public Parcelable[] getVolumeList() throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 234057b8632e..6fd1d002fa84 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -19,6 +19,7 @@ package android.os.storage;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -545,12 +546,34 @@ public class StorageManager
* Returns list of all mountable volumes.
* @hide
*/
- public String[] getVolumeList() {
+ public StorageVolume[] getVolumeList() {
try {
- return mMountService.getVolumeList();
+ Parcelable[] list = mMountService.getVolumeList();
+ if (list == null) return new StorageVolume[0];
+ int length = list.length;
+ StorageVolume[] result = new StorageVolume[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = (StorageVolume)list[i];
+ }
+ return result;
} catch (RemoteException e) {
Log.e(TAG, "Failed to get volume list", e);
return null;
}
}
+
+ /**
+ * Returns list of paths for all mountable volumes.
+ * @hide
+ */
+ public String[] getVolumePaths() {
+ StorageVolume[] volumes = getVolumeList();
+ if (volumes == null) return null;
+ int count = volumes.length;
+ String[] paths = new String[count];
+ for (int i = 0; i < count; i++) {
+ paths[i] = volumes[i].getPath();
+ }
+ return paths;
+ }
}
diff --git a/core/java/android/os/storage/StorageVolume.aidl b/core/java/android/os/storage/StorageVolume.aidl
new file mode 100644
index 000000000000..d68991790519
--- /dev/null
+++ b/core/java/android/os/storage/StorageVolume.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011, 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.
+ */
+
+package android.os.storage;
+
+parcelable StorageVolume;
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
new file mode 100644
index 000000000000..d79f6c8f1792
--- /dev/null
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package android.os.storage;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class representing a storage volume
+ * @hide
+ */
+public class StorageVolume implements Parcelable {
+
+ private static final String TAG = "StorageVolume";
+
+ private final String mPath;
+ private final String mDescription;
+ private final boolean mRemovable;
+ private final boolean mEmulated;
+ private final int mMtpReserveSpace;
+
+ public StorageVolume(String path, String description,
+ boolean removable, boolean emulated,
+ int mtpReserveSpace) {
+ mPath = path;
+ mDescription = description;
+ mRemovable = removable;
+ mEmulated = emulated;
+ mMtpReserveSpace = mtpReserveSpace;
+ }
+
+ /**
+ * Returns the mount path for the volume.
+ *
+ * @return the mount path
+ */
+ public String getPath() {
+ return mPath;
+ }
+
+ /**
+ * Returns a user visible description of the volume.
+ *
+ * @return the volume description
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * Returns true if the volume is removable.
+ *
+ * @return is removable
+ */
+ public boolean isRemovable() {
+ return mRemovable;
+ }
+
+ /**
+ * Returns true if the volume is emulated.
+ *
+ * @return is removable
+ */
+ public boolean isEmulated() {
+ return mEmulated;
+ }
+
+ /**
+ * Number of megabytes of space to leave unallocated by MTP.
+ * MTP will subtract this value from the free space it reports back
+ * to the host via GetStorageInfo, and will not allow new files to
+ * be added via MTP if there is less than this amount left free in the storage.
+ * If MTP has dedicated storage this value should be zero, but if MTP is
+ * sharing storage with the rest of the system, set this to a positive value
+ * to ensure that MTP activity does not result in the storage being
+ * too close to full.
+ *
+ * @return MTP reserve space
+ */
+ public int getMtpReserveSpace() {
+ return mMtpReserveSpace;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof StorageVolume && mPath != null) {
+ StorageVolume volume = (StorageVolume)obj;
+ return (mPath.equals(volume.mPath));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mPath.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return mPath;
+ }
+
+ public static final Parcelable.Creator<StorageVolume> CREATOR =
+ new Parcelable.Creator<StorageVolume>() {
+ public StorageVolume createFromParcel(Parcel in) {
+ String path = in.readString();
+ String description = in.readString();
+ int removable = in.readInt();
+ int emulated = in.readInt();
+ int mtpReserveSpace = in.readInt();
+ return new StorageVolume(path, description,
+ removable == 1, emulated == 1, mtpReserveSpace);
+ }
+
+ public StorageVolume[] newArray(int size) {
+ return new StorageVolume[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mPath);
+ parcel.writeString(mDescription);
+ parcel.writeInt(mRemovable ? 1 : 0);
+ parcel.writeInt(mEmulated ? 1 : 0);
+ parcel.writeInt(mMtpReserveSpace);
+ }
+}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 09a5fd4159dd..eb1c43735a51 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1509,7 +1509,31 @@ static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz,
int fd = open(name8.string(), flags, realMode);
if (fd < 0) {
- jniThrowException(env, "java/io/FileNotFoundException", NULL);
+ jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
+ return NULL;
+ }
+ jobject object = newFileDescriptor(env, fd);
+ if (object == NULL) {
+ close(fd);
+ }
+ return object;
+}
+
+static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jobject clazz, jobject orig)
+{
+ if (orig == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return NULL;
+ }
+ int origfd = env->GetIntField(orig, gFileDescriptorOffsets.mDescriptor);
+ if (origfd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
+ return NULL;
+ }
+
+ int fd = dup(origfd);
+ if (fd < 0) {
+ jniThrowException(env, "java/io/IOException", strerror(errno));
return NULL;
}
jobject object = newFileDescriptor(env, fd);
@@ -1521,6 +1545,10 @@ static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz,
static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
{
+ if (object == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
if (fd >= 0) {
env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
@@ -1531,6 +1559,10 @@ static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jo
static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jobject clazz, jobject object)
{
+ if (object == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+ return;
+ }
int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
if (fd >= 0) {
env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
@@ -1735,6 +1767,7 @@ static const JNINativeMethod gParcelMethods[] = {
{"readStrongBinder", "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
{"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
{"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
+ {"dupFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
{"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
{"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
{"freeBuffer", "()V", (void*)android_os_Parcel_freeBuffer},
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 71a8b2a82dc1..004b7555f53f 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4878,4 +4878,21 @@
<!-- Y coordinate of the icon hot spot. -->
<attr name="hotSpotY" format="float" />
</declare-styleable>
+
+ <declare-styleable name="Storage">
+ <!-- path to mount point for the storage -->
+ <attr name="mountPoint" format="string" />
+ <!-- user visible description of the storage -->
+ <attr name="storageDescription" format="string" />
+ <!-- true if the storage is the primary external storage -->
+ <attr name="primary" format="boolean" />
+ <!-- true if the storage is removable -->
+ <attr name="removable" format="boolean" />
+ <!-- true if the storage is emulated via the FUSE sdcard daemon -->
+ <attr name="emulated" format="boolean" />
+ <!-- number of megabytes of storage MTP should reserve for free storage
+ (used for emulated storage that is shared with system's data partition) -->
+ <attr name="mtpReserve" format="integer" />
+ </declare-styleable>
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 32249730a60c..4a239e2af1bb 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -94,52 +94,10 @@
when there's no network connection. If the scan doesn't timeout, use zero -->
<integer name="config_radioScanningTimeout">0</integer>
- <!-- Set to true if the location returned Environment.getExternalStorageDirectory()
- is actually a subdirectory of the internal storage.
- If this is set then Environment.getExternalStorageState() will always return
- MEDIA_MOUNTED and Intent.ACTION_MEDIA_MOUNTED will be broadcast at boot time
- for backward compatibility with apps that require external storage. -->
- <bool name="config_emulateExternalStorage">false</bool>
-
- <!-- Set to true if external storage is case sensitive.
- Typically external storage is FAT, which is case insensitive. -->
- <bool name="config_caseSensitiveExternalStorage">false</bool>
-
- <!-- A product with no SD card == not removable. -->
- <bool name="config_externalStorageRemovable" product="nosdcard">false</bool>
- <!-- Configures whether the primary external storage device is
- removable. For example, if external storage is on an SD card,
- it is removable; if it is built in to the device, it is not removable.
- The default product has external storage on an SD card, which is
- removable. -->
- <bool name="config_externalStorageRemovable" product="default">true</bool>
-
- <!-- List of mount points for external storage devices.
- The first item on the list should be the primary external storage and should match the
- value returned by Environment.getExternalStorageDirectory (/mnt/sdcard).
- MTP storage IDs will be generated based on the position of the mountpoint in this list:
- 0x00010001 - ID for primary external storage (/mnt/sdcard)
- 0x00020001 - ID for first secondary external storage
- 0x00030001 - ID for second secondary external storage
- etc. -->
- <string-array translatable="false" name="config_externalStoragePaths">
- <item>"/mnt/sdcard"</item>
- </string-array>
-
- <!-- User visible descriptions of the volumes in the config_externalStoragePaths array. -->
- <string-array translatable="true" name="config_externalStorageDescriptions">
- <item>"SD card"</item>
- </string-array>
-
- <!-- Number of megabytes of space to leave unallocated by MTP.
- MTP will subtract this value from the free space it reports back
- to the host via GetStorageInfo, and will not allow new files to
- be added via MTP if there is less than this amount left free in the storage.
- If MTP has dedicated storage this value should be zero, but if MTP is
- sharing storage with the rest of the system, set this to a positive value
- to ensure that MTP activity does not result in the storage being
- too close to full. -->
- <integer name="config_mtpReserveSpaceMegabytes">0</integer>
+ <!-- Storage lists for default and nosdcard products.
+ Both have a single SD card storage, but the storage is not removable in the nosdcard case -->
+ <integer name="config_storageListId" product="nosdcard">@xml/storage_list_nosdcard</integer>
+ <integer name="config_storageListId" product="default">@xml/storage_list</integer>
<!-- XXXXX NOTE THE FOLLOWING RESOURCES USE THE WRONG NAMING CONVENTION.
Please don't copy them, copy anything else. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8ef9a3b247b4..b713b518e739 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2808,4 +2808,12 @@
<!-- Description of the button to decrement the NumberPicker value. [CHAR LIMIT=NONE] -->
<string name="number_picker_decrement_button">Decrement</string>
+ <!-- Storage description for internal storage. [CHAR LIMIT=NONE] -->
+ <string name="storage_internal">Internal Storage</string>
+
+ <!-- Storage description for the SD card. [CHAR LIMIT=NONE] -->
+ <string name="storage_sd_card">SD Card</string>
+
+ <!-- Storage description for USB storage. [CHAR LIMIT=NONE] -->
+ <string name="storage_usb">USB storage</string>
</resources>
diff --git a/core/res/res/xml/storage_list.xml b/core/res/res/xml/storage_list.xml
new file mode 100644
index 000000000000..944bb3a94209
--- /dev/null
+++ b/core/res/res/xml/storage_list.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011, 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.
+*/
+-->
+
+<!-- The <device> element should contain one or more <storage> elements.
+ Exactly one of these should have the attribute primary="true".
+ This storage will be the primary external storage and should have mountPoint="/mnt/sdcard".
+ Each storage should have both a mountPoint and storageDescription attribute.
+ The following attributes are optional:
+
+ primary: (boolean) this storage is the primary external storage
+ removable: (boolean) this is removable storage (for example, a real SD card)
+ emulated: (boolean) the storage is emulated via the FUSE sdcard daemon
+ mtpReserve: (integer) number of megabytes of storage MTP should reserve for free storage
+ (used for emulated storage that is shared with system's data partition)
+
+ A storage should not have both emulated and removable set to true
+-->
+
+<StorageList xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- removable is not set in nosdcard product -->
+ <storage android:mountPoint="/mnt/sdcard"
+ android:storageDescription="@string/storage_usb"
+ android:primary="true" />
+</StorageList>
diff --git a/docs/html/guide/topics/usb/adk.jd b/docs/html/guide/topics/usb/adk.jd
index 44d7fc22edab..8aaa65c9fd0b 100644
--- a/docs/html/guide/topics/usb/adk.jd
+++ b/docs/html/guide/topics/usb/adk.jd
@@ -6,7 +6,9 @@ page.title=Android Open Accessory Development Kit
<h2>In this document</h2>
<ol>
+ <li><a href="#components">ADK Components</a></li>
<li>
+
<a href="#getting-started">Getting Started with the ADK</a>
<ol>
@@ -54,16 +56,28 @@ page.title=Android Open Accessory Development Kit
</li>
</ol>
- <h2>Where to Buy</h2>
+
+
+ <h2>See also</h2>
+
+ <ol>
+ <li><a href="http://www.youtube.com/watch?v=s7szcpXf2rE">Google I/O Session Video</a></li>
+ <li><a href="{@docRoot}guide/topics/usb/accessory.html">USB Accessory Dev Guide</a></li>
+ </ol>
+
+ <h2>Where to buy</h2>
<ol>
<li><a href=
- "http://www.rt-shop.sakura.ne.jp/rt-shop/index.php?main_page=product_info&amp;products_id=2731&language=en">
+ "http://www.rt-net.jp/shop/index.php?main_page=product_info&cPath=3_4&products_id=1">
RT Corp</a></li>
<li><a href=
"http://www.microchip.com/android">
Microchip</a></li>
+
+ <li><a href="https://store.diydrones.com/ProductDetails.asp?ProductCode=BR-PhoneDrone">
+ DIY Drones</a></li>
</ol>
</div>
</div>
@@ -79,7 +93,7 @@ page.title=Android Open Accessory Development Kit
released Android-powered devices are only capable of acting as a USB device and cannot initiate
connections with external USB devices. Android Open Accessory support overcomes this limitation
and allows you to build accessories that can interact with an assortment of Android-powered
- devices by allowing the accessory initiate the connection.</p>
+ devices by allowing the accessory to initiate the connection.</p>
<p class="note"><strong>Note:</strong> Accessory mode is ultimately dependent on the device's
hardware and not all devices will support accessory mode. Devices that support accessory mode can
@@ -87,20 +101,29 @@ page.title=Android Open Accessory Development Kit
Android manifest. For more information, see the <a href=
"{@docRoot}guide/topics/usb/accessory.html#manifest">USB Accessory</a> Developer Guide.</p>
+ <p>The following list of distributers are currently producing Android Open Accessory compatible
+ development boards:</p>
+
+ <ul>
+ <li><a href="http://www.rt-net.jp/shop/index.php?main_page=product_info&cPath=3_4&products_id=1">
+ RT Corp</a> provides an Arduino-compatible board based on the Android ADK board design.</li>
+ <li><a href="http://www.microchip.com/android">Microchip</a> provides a A PIC based USB
+ microcontroller board.</li>
+ <li><a href="https://store.diydrones.com/ProductDetails.asp?ProductCode=BR-PhoneDrone">DIY
+ Drones</a> provides an Arduino-compatible board geared towards RC (radio controlled) and UAV
+ (unmanned aerial vehicle) enthusiasts.</li>
+ </ul>
+
+ <p>We expect more hardware distributers to create a variety of kits, so please stay tuned for
+ further developments.</p>
+
+ <h2 id="components">ADK Components</h2>
<p>The Android Open Accessory Development Kit (ADK) provides an implementation of an Android USB
accessory that is based on the <a href="http://www.arduino.cc/">Arduino open source electronics
prototyping platform</a>, the accessory's hardware design files, code that implements the
accessory's firmware, and the Android application that interacts with the accessory. The hardware
- design files and code are contained in the <a href=
- "https://dl-ssl.google.com/android/adk/adk_release_0506.zip">ADK package download</a>. You can
- <a href=
- "http://www.rt-shop.sakura.ne.jp/rt-shop/index.php?main_page=product_info&amp;products_id=2731&language=en">buy
- the hardware components</a> of the ADK if you do not already have them. There is also a <a href=
- "http://www.microchip.com/android">
- PIC based USB microcontroller</a> that is not based on the ADK design, but that you can still use
- to create your own Android open accessories. We expect more hardware distributers to create a
- variety of kits, so please stay tuned for further developments.</p>
-
+ design files and firmware code are contained in the <a href=
+ "https://dl-ssl.google.com/android/adk/adk_release_0512.zip">ADK package download</a>.</p>
<p>The main hardware and software components of the ADK include:</p>
<ul>
@@ -138,7 +161,6 @@ page.title=Android Open Accessory Development Kit
how to setup communication with the device.</li>
<li>Other third party libraries to support the ADK board's functionality:
-
<ul>
<li><a href="http://www.arduino.cc/playground/Main/CapSense">CapSense library</a></li>
@@ -150,11 +172,12 @@ page.title=Android Open Accessory Development Kit
<li><a href="http://www.arduino.cc/playground/Code/Spi">Spi library</a></li>
<li><a href="http://www.arduino.cc/en/Reference/Wire">Wire library</a></li>
+
+ <li>An Android application, DemoKit, that communicates with the ADK board and shield. The
+ source for this project is in the <code>app/</code> directory.</li>
</ul>
</li>
- <li>An Android application, DemoKit, that communicates with the ADK board and shield. The
- source for this project is in the <code>app/</code> directory.</li>
</ul>
<h2 id="getting-started">Getting Started with the ADK</h2>
@@ -172,7 +195,7 @@ page.title=Android Open Accessory Development Kit
libraries to sense human capacitance. This is needed for the capacative button that is located
on the ADK shield.</li>
- <li><a href="">The ADK package</a>: contains the firmware for the ADK board and hardware design
+ <li><a href="https://dl-ssl.google.com/android/adk/adk_release_0512.zip">The ADK package</a>: contains the firmware for the ADK board and hardware design
files for the ADK board and shield.</li>
</ul>
@@ -190,7 +213,7 @@ page.title=Android Open Accessory Development Kit
otherwise.</p>
</li>
- <li><a href="https://dl-ssl.google.com/android/adk/adk_release_0506.zip">Download</a> and
+ <li><a href="https://dl-ssl.google.com/android/adk/adk_release_0512.zip">Download</a> and
extract the ADK package to a directory of your choice. You should have an <code>app</code>,
<code>firmware</code>, and <code>hardware</code> directories.</li>
@@ -419,7 +442,7 @@ page.title=Android Open Accessory Development Kit
mode, the accessory cannot discern whether the device supports accessory mode and is not in that
state, or if the device does not support accessory mode at all. This is because devices that
support accessory mode but aren't in it initially report the device's manufacturer vendor ID and
- product ID, and not the special Google ones. In either case, the accessory should try to start
+ product ID, and not the special Android Open Accessory ones. In either case, the accessory should try to start
the device into accessory mode to figure out if the device supports it. The following steps
explain how to do this:</p>
diff --git a/docs/html/sdk/android-3.1.jd b/docs/html/sdk/android-3.1.jd
index 57fe1ebc35c9..992b7d16e1c8 100644
--- a/docs/html/sdk/android-3.1.jd
+++ b/docs/html/sdk/android-3.1.jd
@@ -107,8 +107,8 @@ discover, communicate with, and manage a variety of device types connected over
USB. </p>
<p>The stack and APIs distinguish two basic types of USB hardware, based on
-whether the platform iself is acting as host or the external hardware is acting
-as host: </p>
+whether the Android-powered device is acting as host or the external hardware
+is acting as host: </p>
<ul>
<li>A <em>USB device</em> is a piece of connected hardware that depends on the
diff --git a/docs/html/sdk/oem-usb.jd b/docs/html/sdk/oem-usb.jd
index c94668f5b04f..27e742a0bec1 100644
--- a/docs/html/sdk/oem-usb.jd
+++ b/docs/html/sdk/oem-usb.jd
@@ -36,6 +36,11 @@ use the <a href="{@docRoot}sdk/win-usb.html">Google USB Driver</a>, instead of a
href="http://www.acer.com/worldwide/support/mobile.html">http://www.acer.com/worldwide/support/mobile.html</a>
</td></tr>
<tr>
+ <td style="font-variant:small-caps">alcatel one touch</td>
+ <td><a
+href="http://www.alcatel-mobilephones.com/global/Android-Downloads">http://www.alcatel-mobilephones.com/global/Android-Downloads</a></td>
+ </tr>
+ <tr>
<td>Asus</td>
<td><a href="http://support.asus.com/download/">http://support.asus.com/download/</a></td>
</tr>
diff --git a/docs/html/videos/index.jd b/docs/html/videos/index.jd
index 50bdb46a1ca2..7f5df784a6a9 100644
--- a/docs/html/videos/index.jd
+++ b/docs/html/videos/index.jd
@@ -37,12 +37,12 @@ var playlistsWithTitleInDescription = "734A052F802C96B9";
* Each playlist ID is paired with a custom video description.
*/
var featured = {
-// Android UI design patterns
- 'M1ZBjlCRfz0' : "The Android user experience team provides suggestions for how to make your applications more useable and engaging.",
-// The world of ListView
- 'wDBM6wVEO70' : "ListView is a common widget that's customizable, but can be tricky to polish, so this talk shows how you can provide the best performance.",
-// Debugging Arts of the Ninja Masters
- 'Dgnx0E7m1GQ' : "The Android SDK includes tools to debug your apps like a ninja. Enter the dojo and become a master at debugging your apps."
+// Android Development Tools
+ 'Oq05KqjXTvs' : "The team behind the Android Development Tools demonstrate several powerful features for app development, including new capabilities in the Eclipse layout editor.",
+// Android UIs for phones and tablets
+ 'WGIU2JX1U5Y' : "This talk from the Android UI team explains several design patterns that the team recommends you use when designing your application for screens of all sizes.",
+// Android Protips
+ 'twmuBbC_oB8' : "In this talk, you'll learn how to create a well polished app that abides by several key virtues, using advanced development techniques and some lesser known APIs."
};
/* When an event on the browser history occurs (back, forward, load),
@@ -177,7 +177,7 @@ function showPlaylists() {
for (var i in ids) {
var script = "<script type='text/javascript' src='http://gdata.youtube.com/feeds/api/playlists/"
+ ids[i] +
- "?v=2&alt=json-in-script&callback=renderPlaylist'><\/script>";
+ "?v=2&alt=json-in-script&max-results=50&callback=renderPlaylist'><\/script>";
$("body").append(script);
}
}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index d1eb3884968e..55b004517958 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1147,8 +1147,7 @@ public class MediaScanner
mGenresUri = Genres.getContentUri(volumeName);
mPlaylistsUri = Playlists.getContentUri(volumeName);
- mCaseInsensitivePaths = !mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_caseSensitiveExternalStorage);
+ mCaseInsensitivePaths = true;
if (!Process.supportsProcesses()) {
// Simulator uses host file system, so it should be case sensitive.
mCaseInsensitivePaths = false;
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index a100f1f34dd8..376d42f74c15 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -17,6 +17,7 @@
package com.android.server;
import com.android.internal.app.IMediaContainerService;
+import com.android.internal.util.XmlUtils;
import com.android.server.am.ActivityManagerService;
import android.Manifest;
@@ -28,6 +29,9 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.ObbInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -36,6 +40,7 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -46,8 +51,14 @@ import android.os.storage.IMountShutdownObserver;
import android.os.storage.IObbActionListener;
import android.os.storage.OnObbStateChangeListener;
import android.os.storage.StorageResultCode;
+import android.os.storage.StorageVolume;
import android.text.TextUtils;
+import android.util.AttributeSet;
import android.util.Slog;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -145,6 +156,8 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
private Context mContext;
private NativeDaemonConnector mConnector;
+ private final ArrayList<StorageVolume> mVolumes = new ArrayList<StorageVolume>();
+ private StorageVolume mPrimaryVolume;
private final HashMap<String, String> mVolumeStates = new HashMap<String, String>();
private String mExternalStoragePath;
private PackageManagerService mPms;
@@ -1068,6 +1081,74 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
}
}
+ // Storage list XML tags
+ private static final String TAG_STORAGE_LIST = "StorageList";
+ private static final String TAG_STORAGE = "storage";
+
+ private void readStorageList(Resources resources) {
+ int id = com.android.internal.R.xml.storage_list;
+ XmlResourceParser parser = resources.getXml(id);
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+
+ try {
+ XmlUtils.beginDocument(parser, TAG_STORAGE_LIST);
+ while (true) {
+ XmlUtils.nextElement(parser);
+
+ String element = parser.getName();
+ if (element == null) break;
+
+ if (TAG_STORAGE.equals(element)) {
+ TypedArray a = resources.obtainAttributes(attrs,
+ com.android.internal.R.styleable.Storage);
+
+ CharSequence path = a.getText(
+ com.android.internal.R.styleable.Storage_mountPoint);
+ CharSequence description = a.getText(
+ com.android.internal.R.styleable.Storage_storageDescription);
+ boolean primary = a.getBoolean(
+ com.android.internal.R.styleable.Storage_primary, false);
+ boolean removable = a.getBoolean(
+ com.android.internal.R.styleable.Storage_removable, false);
+ boolean emulated = a.getBoolean(
+ com.android.internal.R.styleable.Storage_emulated, false);
+ int mtpReserve = a.getInt(
+ com.android.internal.R.styleable.Storage_mtpReserve, 0);
+
+ Slog.d(TAG, "got storage path: " + path + " description: " + description +
+ " primary: " + primary + " removable: " + removable +
+ " emulated: " + emulated + " mtpReserve: " + mtpReserve);
+ if (path == null || description == null) {
+ Slog.e(TAG, "path or description is null in readStorageList");
+ } else {
+ StorageVolume volume = new StorageVolume(path.toString(),
+ description.toString(), removable, emulated, mtpReserve);
+ if (primary) {
+ if (mPrimaryVolume == null) {
+ mPrimaryVolume = volume;
+ } else {
+ Slog.e(TAG, "multiple primary volumes in storage list");
+ }
+ }
+ if (mPrimaryVolume == volume) {
+ // primay volume must be first
+ mVolumes.add(0, volume);
+ } else {
+ mVolumes.add(volume);
+ }
+ }
+ a.recycle();
+ }
+ }
+ } catch (XmlPullParserException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ parser.close();
+ }
+ }
+
/**
* Constructs a new MountService instance
*
@@ -1075,13 +1156,16 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
*/
public MountService(Context context) {
mContext = context;
+ Resources resources = context.getResources();
+ readStorageList(resources);
- mExternalStoragePath = Environment.getExternalStorageDirectory().getPath();
- mEmulateExternalStorage = context.getResources().getBoolean(
- com.android.internal.R.bool.config_emulateExternalStorage);
- if (mEmulateExternalStorage) {
- Slog.d(TAG, "using emulated external storage");
- mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
+ if (mPrimaryVolume != null) {
+ mExternalStoragePath = mPrimaryVolume.getPath();
+ mEmulateExternalStorage = mPrimaryVolume.isEmulated();
+ if (mEmulateExternalStorage) {
+ Slog.d(TAG, "using emulated external storage");
+ mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
+ }
}
// XXX: This will go away soon in favor of IMountServiceObserver
@@ -1753,13 +1837,12 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
}
}
- public String[] getVolumeList() {
- synchronized(mVolumeStates) {
- Set<String> volumes = mVolumeStates.keySet();
- String[] result = new String[volumes.size()];
- int i = 0;
- for (String volume : volumes) {
- result[i++] = volume;
+ public Parcelable[] getVolumeList() {
+ synchronized(mVolumes) {
+ int size = mVolumes.size();
+ Parcelable[] result = new Parcelable[size];
+ for (int i = 0; i < size; i++) {
+ result[i] = mVolumes.get(i);
}
return result;
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6a5ca1f7ecf5..6619caf5455d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -90,6 +90,7 @@ import android.os.FileObserver;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IInterface;
import android.os.IPermissionController;
import android.os.Looper;
import android.os.Message;
@@ -1404,35 +1405,7 @@ public final class ActivityManagerService extends ActivityManagerNative
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- ActivityManagerService service = mActivityManagerService;
- ArrayList<ProcessRecord> procs;
- synchronized (mActivityManagerService) {
- if (args != null && args.length > 0
- && args[0].charAt(0) != '-') {
- procs = new ArrayList<ProcessRecord>();
- int pid = -1;
- try {
- pid = Integer.parseInt(args[0]);
- } catch (NumberFormatException e) {
-
- }
- for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord proc = service.mLruProcesses.get(i);
- if (proc.pid == pid) {
- procs.add(proc);
- } else if (proc.processName.equals(args[0])) {
- procs.add(proc);
- }
- }
- if (procs.size() <= 0) {
- pw.println("No process found for: " + args[0]);
- return;
- }
- } else {
- procs = new ArrayList<ProcessRecord>(service.mLruProcesses);
- }
- }
- dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
+ mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args);
}
}
@@ -7494,6 +7467,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
boolean dumpAll = false;
+ boolean dumpClient = false;
int opti = 0;
while (opti < args.length) {
@@ -7504,9 +7478,11 @@ public final class ActivityManagerService extends ActivityManagerNative
opti++;
if ("-a".equals(opt)) {
dumpAll = true;
+ } else if ("-c".equals(opt)) {
+ dumpClient = true;
} else if ("-h".equals(opt)) {
pw.println("Activity manager dump options:");
- pw.println(" [-a] [-h] [cmd] ...");
+ pw.println(" [-a] [-c] [-h] [cmd] ...");
pw.println(" cmd may be one of:");
pw.println(" a[ctivities]: activity stack state");
pw.println(" b[roadcasts]: broadcast state");
@@ -7515,10 +7491,14 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println(" o[om]: out of memory management");
pw.println(" prov[iders]: content provider state");
pw.println(" s[ervices]: service state");
- pw.println(" service [name]: service client-side state");
- pw.println(" cmd may also be a component name (com.foo/.myApp),");
- pw.println(" a partial substring in a component name, or an");
- pw.println(" ActivityRecord hex object identifier.");
+ pw.println(" service [COMP_SPEC]: service client-side state");
+ pw.println(" cmd may also be a COMP_SPEC to dump activities.");
+ pw.println(" COMP_SPEC may also be a component name (com.foo/.myApp),");
+ pw.println(" a partial substring in a component name, an");
+ pw.println(" ActivityRecord hex object identifier, or");
+ pw.println(" \"all\" for all objects");
+ pw.println(" -a: include all available server state.");
+ pw.println(" -c: include client state.");
return;
} else {
pw.println("Unknown argument: " + opt + "; use -h for help");
@@ -7531,7 +7511,7 @@ public final class ActivityManagerService extends ActivityManagerNative
opti++;
if ("activities".equals(cmd) || "a".equals(cmd)) {
synchronized (this) {
- dumpActivitiesLocked(fd, pw, args, opti, true, true);
+ dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient);
}
return;
} else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
@@ -7560,20 +7540,33 @@ public final class ActivityManagerService extends ActivityManagerNative
}
return;
} else if ("service".equals(cmd)) {
- dumpService(fd, pw, args, opti);
+ String[] newArgs;
+ String name;
+ if (opti >= args.length) {
+ name = null;
+ newArgs = EMPTY_STRING_ARRAY;
+ } else {
+ name = args[opti];
+ opti++;
+ newArgs = new String[args.length - opti];
+ if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
+ }
+ if (!dumpService(fd, pw, name, newArgs, 0, dumpAll)) {
+ pw.println("No services match: " + name);
+ pw.println("Use -h for help.");
+ }
return;
} else if ("services".equals(cmd) || "s".equals(cmd)) {
synchronized (this) {
- dumpServicesLocked(fd, pw, args, opti, true);
+ dumpServicesLocked(fd, pw, args, opti, true, dumpClient);
}
return;
} else {
// Dumping a single activity?
- if (dumpActivity(fd, pw, cmd, args, opti, dumpAll)) {
- return;
+ if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) {
+ pw.println("Bad activity command, or no activities match: " + cmd);
+ pw.println("Use -h for help.");
}
- pw.println("Bad activity command, or no activities match: " + cmd);
- pw.println("Use -h for help.");
return;
}
}
@@ -7581,16 +7574,12 @@ public final class ActivityManagerService extends ActivityManagerNative
// No piece of data specified, dump everything.
synchronized (this) {
boolean needSep;
- if (dumpAll) {
- pw.println("Providers in Current Activity Manager State:");
- }
- needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
+ needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
if (needSep) {
pw.println(" ");
}
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
- pw.println("Broadcasts in Current Activity Manager State:");
}
needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
if (needSep) {
@@ -7598,88 +7587,95 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
- pw.println("Services in Current Activity Manager State:");
}
- needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
+ needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
if (needSep) {
pw.println(" ");
}
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
- pw.println("PendingIntents in Current Activity Manager State:");
}
- needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
+ needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll, dumpClient);
if (needSep) {
pw.println(" ");
}
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
- pw.println("Activities in Current Activity Manager State:");
}
- needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
+ needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient);
if (needSep) {
pw.println(" ");
}
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
- pw.println("Processes in Current Activity Manager State:");
}
dumpProcessesLocked(fd, pw, args, opti, dumpAll);
}
}
boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, boolean needHeader) {
- if (needHeader) {
- pw.println(" Activity stack:");
- }
- dumpHistoryList(pw, mMainStack.mHistory, " ", "Hist", true);
+ int opti, boolean dumpAll, boolean dumpClient) {
+ pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
+ pw.println(" Main stack:");
+ dumpHistoryList(fd, pw, mMainStack.mHistory, " ", "Hist", true, !dumpAll, dumpClient);
pw.println(" ");
pw.println(" Running activities (most recent first):");
- dumpHistoryList(pw, mMainStack.mLRUActivities, " ", "Run", false);
+ dumpHistoryList(fd, pw, mMainStack.mLRUActivities, " ", "Run", false, !dumpAll, false);
if (mMainStack.mWaitingVisibleActivities.size() > 0) {
pw.println(" ");
pw.println(" Activities waiting for another to become visible:");
- dumpHistoryList(pw, mMainStack.mWaitingVisibleActivities, " ", "Wait", false);
+ dumpHistoryList(fd, pw, mMainStack.mWaitingVisibleActivities, " ", "Wait", false,
+ !dumpAll, false);
}
if (mMainStack.mStoppingActivities.size() > 0) {
pw.println(" ");
pw.println(" Activities waiting to stop:");
- dumpHistoryList(pw, mMainStack.mStoppingActivities, " ", "Stop", false);
+ dumpHistoryList(fd, pw, mMainStack.mStoppingActivities, " ", "Stop", false,
+ !dumpAll, false);
}
if (mMainStack.mGoingToSleepActivities.size() > 0) {
pw.println(" ");
pw.println(" Activities waiting to sleep:");
- dumpHistoryList(pw, mMainStack.mGoingToSleepActivities, " ", "Sleep", false);
+ dumpHistoryList(fd, pw, mMainStack.mGoingToSleepActivities, " ", "Sleep", false,
+ !dumpAll, false);
}
if (mMainStack.mFinishingActivities.size() > 0) {
pw.println(" ");
pw.println(" Activities waiting to finish:");
- dumpHistoryList(pw, mMainStack.mFinishingActivities, " ", "Fin", false);
+ dumpHistoryList(fd, pw, mMainStack.mFinishingActivities, " ", "Fin", false,
+ !dumpAll, false);
}
pw.println(" ");
- pw.println(" mPausingActivity: " + mMainStack.mPausingActivity);
+ if (mMainStack.mPausingActivity != null) {
+ pw.println(" mPausingActivity: " + mMainStack.mPausingActivity);
+ }
pw.println(" mResumedActivity: " + mMainStack.mResumedActivity);
pw.println(" mFocusedActivity: " + mFocusedActivity);
- pw.println(" mLastPausedActivity: " + mMainStack.mLastPausedActivity);
- pw.println(" mSleepTimeout: " + mMainStack.mSleepTimeout);
+ if (dumpAll) {
+ pw.println(" mLastPausedActivity: " + mMainStack.mLastPausedActivity);
+ pw.println(" mSleepTimeout: " + mMainStack.mSleepTimeout);
+ }
- if (dumpAll && mRecentTasks.size() > 0) {
- pw.println(" ");
- pw.println("Recent tasks in Current Activity Manager State:");
+ if (mRecentTasks.size() > 0) {
+ pw.println();
+ pw.println(" Recent tasks:");
final int N = mRecentTasks.size();
for (int i=0; i<N; i++) {
TaskRecord tr = mRecentTasks.get(i);
pw.print(" * Recent #"); pw.print(i); pw.print(": ");
pw.println(tr);
- mRecentTasks.get(i).dump(pw, " ");
+ if (dumpAll) {
+ mRecentTasks.get(i).dump(pw, " ");
+ }
}
}
- pw.println(" ");
- pw.println(" mCurTask: " + mCurTask);
+ if (dumpAll) {
+ pw.println(" ");
+ pw.println(" mCurTask: " + mCurTask);
+ }
return true;
}
@@ -7689,6 +7685,8 @@ public final class ActivityManagerService extends ActivityManagerNative
boolean needSep = false;
int numPers = 0;
+ pw.println("ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)");
+
if (dumpAll) {
for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
final int NA = procs.size();
@@ -7712,20 +7710,22 @@ public final class ActivityManagerService extends ActivityManagerNative
if (mLruProcesses.size() > 0) {
if (needSep) pw.println(" ");
needSep = true;
- pw.println(" Running processes (most recent first):");
+ pw.println(" Process LRU list (most recent first):");
dumpProcessOomList(pw, this, mLruProcesses, " ",
"Proc", "PERS", false);
needSep = true;
}
- synchronized (mPidsSelfLocked) {
- if (mPidsSelfLocked.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" PID mappings:");
- for (int i=0; i<mPidsSelfLocked.size(); i++) {
- pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
- pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
+ if (dumpAll) {
+ synchronized (mPidsSelfLocked) {
+ if (mPidsSelfLocked.size() > 0) {
+ if (needSep) pw.println(" ");
+ needSep = true;
+ pw.println(" PID mappings:");
+ for (int i=0; i<mPidsSelfLocked.size(); i++) {
+ pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
+ pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
+ }
}
}
}
@@ -7810,16 +7810,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- pw.println(" ");
+ pw.println();
pw.println(" mHomeProcess: " + mHomeProcess);
if (mHeavyWeightProcess != null) {
pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
}
pw.println(" mConfiguration: " + mConfiguration);
- pw.println(" mConfigWillChange: " + mMainStack.mConfigWillChange);
- if (mCompatModePackages.getPackages().size() > 0) {
- pw.print(" mScreenCompatPackages=");
- pw.println(mCompatModePackages.getPackages());
+ if (dumpAll) {
+ pw.println(" mConfigWillChange: " + mMainStack.mConfigWillChange);
+ if (mCompatModePackages.getPackages().size() > 0) {
+ pw.print(" mScreenCompatPackages=");
+ pw.println(mCompatModePackages.getPackages());
+ }
}
pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
@@ -7914,7 +7916,7 @@ public final class ActivityManagerService extends ActivityManagerNative
needSep = dumpProcessesToGc(fd, pw, args, opti, needSep, dumpAll);
- pw.println(" ");
+ pw.println();
pw.println(" mHomeProcess: " + mHomeProcess);
if (mHeavyWeightProcess != null) {
pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
@@ -7931,61 +7933,96 @@ public final class ActivityManagerService extends ActivityManagerNative
* - the first arg isn't the flattened component name of an existing service:
* dump all services whose component contains the first arg as a substring
*/
- protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args, int opti) {
- String[] newArgs;
- String componentNameString;
- ServiceRecord r;
- if (opti >= args.length) {
- componentNameString = null;
- newArgs = EMPTY_STRING_ARRAY;
- r = null;
- } else {
- componentNameString = args[opti];
- opti++;
- ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
+ protected boolean dumpService(FileDescriptor fd, PrintWriter pw, String name, String[] args,
+ int opti, boolean dumpAll) {
+ ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
+
+ if ("all".equals(name)) {
synchronized (this) {
- r = componentName != null ? mServices.get(componentName) : null;
+ for (ServiceRecord r1 : mServices.values()) {
+ services.add(r1);
+ }
}
- newArgs = new String[args.length - opti];
- if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
- }
-
- if (r != null) {
- dumpService(fd, pw, r, newArgs);
} else {
- ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
+ ComponentName componentName = name != null
+ ? ComponentName.unflattenFromString(name) : null;
+ int objectId = 0;
+ if (componentName == null) {
+ // Not a '/' separated full component name; maybe an object ID?
+ try {
+ objectId = Integer.parseInt(name, 16);
+ name = null;
+ componentName = null;
+ } catch (RuntimeException e) {
+ }
+ }
+
synchronized (this) {
for (ServiceRecord r1 : mServices.values()) {
- if (componentNameString == null
- || r1.name.flattenToString().contains(componentNameString)) {
+ if (componentName != null) {
+ if (r1.name.equals(componentName)) {
+ services.add(r1);
+ }
+ } else if (name != null) {
+ if (r1.name.flattenToString().contains(name)) {
+ services.add(r1);
+ }
+ } else if (System.identityHashCode(r1) == objectId) {
services.add(r1);
}
}
}
- for (int i=0; i<services.size(); i++) {
- dumpService(fd, pw, services.get(i), newArgs);
+ }
+
+ if (services.size() <= 0) {
+ return false;
+ }
+
+ boolean needSep = false;
+ for (int i=0; i<services.size(); i++) {
+ if (needSep) {
+ pw.println();
}
+ needSep = true;
+ dumpService("", fd, pw, services.get(i), args, dumpAll);
}
+ return true;
}
/**
* Invokes IApplicationThread.dumpService() on the thread of the specified service if
* there is a thread associated with the service.
*/
- private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
- pw.println("------------------------------------------------------------"
- + "-------------------");
- pw.println("APP SERVICE: " + r.name.flattenToString());
+ private void dumpService(String prefix, FileDescriptor fd, PrintWriter pw,
+ final ServiceRecord r, String[] args, boolean dumpAll) {
+ String innerPrefix = prefix + " ";
+ synchronized (this) {
+ pw.print(prefix); pw.print("SERVICE ");
+ pw.print(r.shortName); pw.print(" ");
+ pw.print(Integer.toHexString(System.identityHashCode(r)));
+ pw.print(" pid=");
+ if (r.app != null) pw.println(r.app.pid);
+ else pw.println("(not running)");
+ if (dumpAll) {
+ r.dump(pw, innerPrefix);
+ }
+ }
if (r.app != null && r.app.thread != null) {
+ pw.print(prefix); pw.println(" Client:");
+ pw.flush();
try {
- // flush anything that is already in the PrintWriter since the thread is going
- // to write to the file descriptor directly
- pw.flush();
- r.app.thread.dumpService(fd, r, args);
- pw.print("\n");
- pw.flush();
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.app.thread.dumpService(tp.getWriteFd().getFileDescriptor(), r, args);
+ tp.setBufferPrefix(prefix + " ");
+ tp.go(fd);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ pw.println(prefix + " Failure while dumping the service: " + e);
} catch (RemoteException e) {
- pw.println("got a RemoteException while dumping the service");
+ pw.println(prefix + " Got a RemoteException while dumping the service");
}
}
}
@@ -7999,34 +8036,40 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll) {
- String[] newArgs;
- ComponentName componentName = ComponentName.unflattenFromString(name);
- int objectId = 0;
- if (componentName == null) {
- // Not a '/' separated full component name; maybe an object ID?
- try {
- objectId = Integer.parseInt(name, 16);
- name = null;
- componentName = null;
- } catch (RuntimeException e) {
+ ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
+
+ if ("all".equals(name)) {
+ synchronized (this) {
+ for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
+ activities.add(r1);
+ }
+ }
+ } else {
+ ComponentName componentName = ComponentName.unflattenFromString(name);
+ int objectId = 0;
+ if (componentName == null) {
+ // Not a '/' separated full component name; maybe an object ID?
+ try {
+ objectId = Integer.parseInt(name, 16);
+ name = null;
+ componentName = null;
+ } catch (RuntimeException e) {
+ }
}
- }
- newArgs = new String[args.length - opti];
- if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
- ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
- synchronized (this) {
- for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
- if (componentName != null) {
- if (r1.intent.getComponent().equals(componentName)) {
- activities.add(r1);
- }
- } else if (name != null) {
- if (r1.intent.getComponent().flattenToString().contains(name)) {
+ synchronized (this) {
+ for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
+ if (componentName != null) {
+ if (r1.intent.getComponent().equals(componentName)) {
+ activities.add(r1);
+ }
+ } else if (name != null) {
+ if (r1.intent.getComponent().flattenToString().contains(name)) {
+ activities.add(r1);
+ }
+ } else if (System.identityHashCode(r1) == objectId) {
activities.add(r1);
}
- } else if (System.identityHashCode(r1) == objectId) {
- activities.add(r1);
}
}
}
@@ -8035,15 +8078,25 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
+ String[] newArgs = new String[args.length - opti];
+ if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
+
TaskRecord lastTask = null;
+ boolean needSep = false;
for (int i=activities.size()-1; i>=0; i--) {
ActivityRecord r = (ActivityRecord)activities.get(i);
- if (lastTask != r.task) {
- lastTask = r.task;
- pw.print("* Task "); pw.print(lastTask.affinity);
- pw.print(" id="); pw.println(lastTask.taskId);
- if (dumpAll) {
- lastTask.dump(pw, " ");
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ synchronized (this) {
+ if (lastTask != r.task) {
+ lastTask = r.task;
+ pw.print("TASK "); pw.print(lastTask.affinity);
+ pw.print(" id="); pw.println(lastTask.taskId);
+ if (dumpAll) {
+ lastTask.dump(pw, " ");
+ }
}
}
dumpActivity(" ", fd, pw, activities.get(i), newArgs, dumpAll);
@@ -8056,26 +8109,35 @@ public final class ActivityManagerService extends ActivityManagerNative
* there is a thread associated with the activity.
*/
private void dumpActivity(String prefix, FileDescriptor fd, PrintWriter pw,
- ActivityRecord r, String[] args, boolean dumpAll) {
+ final ActivityRecord r, String[] args, boolean dumpAll) {
+ String innerPrefix = prefix + " ";
synchronized (this) {
- pw.print(prefix); pw.print("* Activity ");
- pw.print(Integer.toHexString(System.identityHashCode(r)));
- pw.print(" "); pw.print(r.shortComponentName); pw.print(" pid=");
+ pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
+ pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
+ pw.print(" pid=");
if (r.app != null) pw.println(r.app.pid);
else pw.println("(not running)");
if (dumpAll) {
- r.dump(pw, prefix + " ");
+ r.dump(pw, innerPrefix);
}
}
if (r.app != null && r.app.thread != null) {
+ // flush anything that is already in the PrintWriter since the thread is going
+ // to write to the file descriptor directly
+ pw.flush();
try {
- // flush anything that is already in the PrintWriter since the thread is going
- // to write to the file descriptor directly
- pw.flush();
- r.app.thread.dumpActivity(fd, r, prefix + " ", args);
- pw.flush();
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
+ innerPrefix, args);
+ tp.go(fd);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ pw.println(innerPrefix + "Failure while dumping the activity: " + e);
} catch (RemoteException e) {
- pw.println("got a RemoteException while dumping the activity");
+ pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
}
}
}
@@ -8084,9 +8146,9 @@ public final class ActivityManagerService extends ActivityManagerNative
int opti, boolean dumpAll) {
boolean needSep = false;
+ pw.println("ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)");
if (dumpAll) {
if (mRegisteredReceivers.size() > 0) {
- pw.println(" ");
pw.println(" Registered Receivers:");
Iterator it = mRegisteredReceivers.values().iterator();
while (it.hasNext()) {
@@ -8096,16 +8158,16 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- pw.println(" ");
- pw.println("Receiver Resolver Table:");
- mReceiverResolver.dump(pw, null, " ", null, false);
+ pw.println();
+ pw.println(" Receiver Resolver Table:");
+ mReceiverResolver.dump(pw, null, " ", null, false);
needSep = true;
}
if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
|| mPendingBroadcast != null) {
if (mParallelBroadcasts.size() > 0) {
- pw.println(" ");
+ pw.println();
pw.println(" Active broadcasts:");
}
for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
@@ -8113,14 +8175,14 @@ public final class ActivityManagerService extends ActivityManagerNative
mParallelBroadcasts.get(i).dump(pw, " ");
}
if (mOrderedBroadcasts.size() > 0) {
- pw.println(" ");
+ pw.println();
pw.println(" Active ordered broadcasts:");
}
for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
pw.println(" Serialized Broadcast #" + i + ":");
mOrderedBroadcasts.get(i).dump(pw, " ");
}
- pw.println(" ");
+ pw.println();
pw.println(" Pending broadcast:");
if (mPendingBroadcast != null) {
mPendingBroadcast.dump(pw, " ");
@@ -8130,47 +8192,59 @@ public final class ActivityManagerService extends ActivityManagerNative
needSep = true;
}
- if (dumpAll) {
- pw.println(" ");
- pw.println(" Historical broadcasts:");
- for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
- BroadcastRecord r = mBroadcastHistory[i];
- if (r == null) {
+ if (needSep) {
+ pw.println();
+ }
+ pw.println(" Historical broadcasts:");
+ for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+ BroadcastRecord r = mBroadcastHistory[i];
+ if (r == null) {
+ break;
+ }
+ if (dumpAll) {
+ pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":");
+ r.dump(pw, " ");
+ } else {
+ if (i >= 50) {
+ pw.println(" ...");
break;
}
- pw.println(" Historical Broadcast #" + i + ":");
- r.dump(pw, " ");
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
}
- needSep = true;
}
+ needSep = true;
if (mStickyBroadcasts != null) {
- pw.println(" ");
+ pw.println();
pw.println(" Sticky broadcasts:");
StringBuilder sb = new StringBuilder(128);
for (Map.Entry<String, ArrayList<Intent>> ent
: mStickyBroadcasts.entrySet()) {
pw.print(" * Sticky action "); pw.print(ent.getKey());
- pw.println(":");
- ArrayList<Intent> intents = ent.getValue();
- final int N = intents.size();
- for (int i=0; i<N; i++) {
- sb.setLength(0);
- sb.append(" Intent: ");
- intents.get(i).toShortString(sb, true, false);
- pw.println(sb.toString());
- Bundle bundle = intents.get(i).getExtras();
- if (bundle != null) {
- pw.print(" ");
- pw.println(bundle.toString());
+ if (dumpAll) {
+ pw.println(":");
+ ArrayList<Intent> intents = ent.getValue();
+ final int N = intents.size();
+ for (int i=0; i<N; i++) {
+ sb.setLength(0);
+ sb.append(" Intent: ");
+ intents.get(i).toShortString(sb, true, false);
+ pw.println(sb.toString());
+ Bundle bundle = intents.get(i).getExtras();
+ if (bundle != null) {
+ pw.print(" ");
+ pw.println(bundle.toString());
+ }
}
+ } else {
+ pw.println("");
}
}
needSep = true;
}
if (dumpAll) {
- pw.println(" ");
+ pw.println();
pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
pw.println(" mHandler:");
mHandler.dump(new PrintWriterPrinter(pw), " ");
@@ -8181,20 +8255,55 @@ public final class ActivityManagerService extends ActivityManagerNative
}
boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll) {
+ int opti, boolean dumpAll, boolean dumpClient) {
boolean needSep = false;
- if (dumpAll) {
- if (mServices.size() > 0) {
- pw.println(" Active services:");
- Iterator<ServiceRecord> it = mServices.values().iterator();
- while (it.hasNext()) {
- ServiceRecord r = it.next();
- pw.print(" * "); pw.println(r);
+ pw.println("ACTIVITY MANAGER SERVICES (dumpsys activity services)");
+ if (mServices.size() > 0) {
+ pw.println(" Active services:");
+ long nowReal = SystemClock.elapsedRealtime();
+ Iterator<ServiceRecord> it = mServices.values().iterator();
+ needSep = false;
+ while (it.hasNext()) {
+ ServiceRecord r = it.next();
+ if (needSep) {
+ pw.println();
+ }
+ pw.print(" * "); pw.println(r);
+ if (dumpAll) {
r.dump(pw, " ");
+ needSep = true;
+ } else {
+ pw.print(" app="); pw.println(r.app);
+ pw.print(" created=");
+ TimeUtils.formatDuration(r.createTime, nowReal, pw);
+ pw.print(" started="); pw.print(r.startRequested);
+ pw.print(" connections="); pw.println(r.connections.size());
+ }
+ if (dumpClient && r.app != null && r.app.thread != null) {
+ pw.println(" Client:");
+ pw.flush();
+ try {
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.app.thread.dumpService(
+ tp.getWriteFd().getFileDescriptor(), r, args);
+ tp.setBufferPrefix(" ");
+ // Short timeout, since blocking here can
+ // deadlock with the application.
+ tp.go(fd, 2000);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ pw.println(" Failure while dumping the service: " + e);
+ } catch (RemoteException e) {
+ pw.println(" Got a RemoteException while dumping the service");
+ }
+ needSep = true;
}
- needSep = true;
}
+ needSep = true;
}
if (mPendingServices.size() > 0) {
@@ -8254,21 +8363,32 @@ public final class ActivityManagerService extends ActivityManagerNative
int opti, boolean dumpAll) {
boolean needSep = false;
- if (dumpAll) {
- if (mProvidersByClass.size() > 0) {
- if (needSep) pw.println(" ");
- pw.println(" Published content providers (by class):");
- Iterator<Map.Entry<String, ContentProviderRecord>> it
- = mProvidersByClass.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<String, ContentProviderRecord> e = it.next();
- ContentProviderRecord r = e.getValue();
+ pw.println("ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)");
+ if (mProvidersByClass.size() > 0) {
+ if (needSep) pw.println(" ");
+ pw.println(" Published content providers (by class):");
+ Iterator<Map.Entry<String, ContentProviderRecord>> it
+ = mProvidersByClass.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, ContentProviderRecord> e = it.next();
+ ContentProviderRecord r = e.getValue();
+ if (dumpAll) {
pw.print(" * "); pw.println(r);
r.dump(pw, " ");
+ } else {
+ pw.print(" * "); pw.print(r.name.toShortString());
+ if (r.app != null) {
+ pw.println(":");
+ pw.print(" "); pw.println(r.app);
+ } else {
+ pw.println();
+ }
}
- needSep = true;
}
+ needSep = true;
+ }
+ if (dumpAll) {
if (mProvidersByName.size() > 0) {
pw.println(" ");
pw.println(" Authority to provider mappings:");
@@ -8305,7 +8425,9 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println(" holds:");
for (UriPermission perm : perms.values()) {
pw.print(" "); pw.println(perm);
- perm.dump(pw, " ");
+ if (dumpAll) {
+ perm.dump(pw, " ");
+ }
}
}
needSep = true;
@@ -8318,20 +8440,21 @@ public final class ActivityManagerService extends ActivityManagerNative
int opti, boolean dumpAll) {
boolean needSep = false;
- if (dumpAll) {
- if (this.mIntentSenderRecords.size() > 0) {
- Iterator<WeakReference<PendingIntentRecord>> it
- = mIntentSenderRecords.values().iterator();
- while (it.hasNext()) {
- WeakReference<PendingIntentRecord> ref = it.next();
- PendingIntentRecord rec = ref != null ? ref.get(): null;
- needSep = true;
- if (rec != null) {
- pw.print(" * "); pw.println(rec);
+ if (this.mIntentSenderRecords.size() > 0) {
+ pw.println("ACTIVITY MANAGER PENDING INTENTS (dumpsys activity intents)");
+ Iterator<WeakReference<PendingIntentRecord>> it
+ = mIntentSenderRecords.values().iterator();
+ while (it.hasNext()) {
+ WeakReference<PendingIntentRecord> ref = it.next();
+ PendingIntentRecord rec = ref != null ? ref.get(): null;
+ needSep = true;
+ if (rec != null) {
+ pw.print(" * "); pw.println(rec);
+ if (dumpAll) {
rec.dump(pw, " ");
- } else {
- pw.print(" * "); pw.print(ref);
}
+ } else {
+ pw.print(" * "); pw.println(ref);
}
}
}
@@ -8339,12 +8462,19 @@ public final class ActivityManagerService extends ActivityManagerNative
return needSep;
}
- private static final void dumpHistoryList(PrintWriter pw, List list,
- String prefix, String label, boolean complete) {
+ private static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, List list,
+ String prefix, String label, boolean complete, boolean brief, boolean client) {
TaskRecord lastTask = null;
+ boolean needNL = false;
+ final String innerPrefix = prefix + " ";
+ final String[] args = new String[0];
for (int i=list.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)list.get(i);
- final boolean full = complete || !r.inHistory;
+ final ActivityRecord r = (ActivityRecord)list.get(i);
+ final boolean full = !brief && (complete || !r.inHistory);
+ if (needNL) {
+ pw.println(" ");
+ needNL = false;
+ }
if (lastTask != r.task) {
lastTask = r.task;
pw.print(prefix);
@@ -8352,13 +8482,46 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println(lastTask);
if (full) {
lastTask.dump(pw, prefix + " ");
+ } else if (complete) {
+ // Complete + brief == give a summary. Isn't that obvious?!?
+ if (lastTask.intent != null) {
+ pw.print(prefix); pw.print(" "); pw.println(lastTask.intent);
+ }
}
}
pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
pw.print(" #"); pw.print(i); pw.print(": ");
pw.println(r);
if (full) {
- r.dump(pw, prefix + " ");
+ r.dump(pw, innerPrefix);
+ } else if (complete) {
+ // Complete + brief == give a summary. Isn't that obvious?!?
+ pw.print(innerPrefix); pw.println(r.intent);
+ if (r.app != null) {
+ pw.print(innerPrefix); pw.println(r.app);
+ }
+ }
+ if (client && r.app != null && r.app.thread != null) {
+ // flush anything that is already in the PrintWriter since the thread is going
+ // to write to the file descriptor directly
+ pw.flush();
+ try {
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
+ innerPrefix, args);
+ // Short timeout, since blocking here can
+ // deadlock with the application.
+ tp.go(fd, 2000);
+ } finally {
+ tp.kill();
+ }
+ } catch (IOException e) {
+ pw.println(innerPrefix + "Failure while dumping the activity: " + e);
+ } catch (RemoteException e) {
+ pw.println(innerPrefix + "Got a RemoteException while dumping the activity");
+ }
+ needNL = true;
}
}
}
@@ -8444,7 +8607,7 @@ public final class ActivityManagerService extends ActivityManagerNative
N-i, oomAdj, schedGroup, r.toShortString(), r.adjType));
if (r.adjSource != null || r.adjTarget != null) {
pw.print(prefix);
- pw.print(" ");
+ pw.print(" ");
if (r.adjTarget instanceof ComponentName) {
pw.print(((ComponentName)r.adjTarget).flattenToShortString());
} else if (r.adjTarget != null) {
@@ -8514,8 +8677,44 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- static final void dumpApplicationMemoryUsage(FileDescriptor fd,
- PrintWriter pw, List list, String prefix, String[] args) {
+ ArrayList<ProcessRecord> collectProcesses(PrintWriter pw, String[] args) {
+ ArrayList<ProcessRecord> procs;
+ synchronized (this) {
+ if (args != null && args.length > 0
+ && args[0].charAt(0) != '-') {
+ procs = new ArrayList<ProcessRecord>();
+ int pid = -1;
+ try {
+ pid = Integer.parseInt(args[0]);
+ } catch (NumberFormatException e) {
+
+ }
+ for (int i=mLruProcesses.size()-1; i>=0; i--) {
+ ProcessRecord proc = mLruProcesses.get(i);
+ if (proc.pid == pid) {
+ procs.add(proc);
+ } else if (proc.processName.equals(args[0])) {
+ procs.add(proc);
+ }
+ }
+ if (procs.size() <= 0) {
+ pw.println("No process found for: " + args[0]);
+ return null;
+ }
+ } else {
+ procs = new ArrayList<ProcessRecord>(mLruProcesses);
+ }
+ }
+ return procs;
+ }
+
+ final void dumpApplicationMemoryUsage(FileDescriptor fd,
+ PrintWriter pw, String prefix, String[] args) {
+ ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
+ if (procs == null) {
+ return;
+ }
+
final boolean isCheckinRequest = scanArgs(args, "--checkin");
long uptime = SystemClock.uptimeMillis();
long realtime = SystemClock.elapsedRealtime();
@@ -8528,15 +8727,18 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println("Applications Memory Usage (kB):");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
}
- for (int i = list.size() - 1 ; i >= 0 ; i--) {
- ProcessRecord r = (ProcessRecord)list.get(i);
+ for (int i = procs.size() - 1 ; i >= 0 ; i--) {
+ ProcessRecord r = procs.get(i);
if (r.thread != null) {
if (!isCheckinRequest) {
pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
}
try {
- r.thread.asBinder().dump(fd, args);
+ TransferPipe.goDump(r.thread.asBinder(), fd, args);
+ } catch (IOException e) {
+ pw.println("Failure: " + e);
+ pw.flush();
} catch (RemoteException e) {
if (!isCheckinRequest) {
pw.println("Got RemoteException!");
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index cb0a0f0c2771..d27cbdaaa053 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -136,7 +136,7 @@ class ActivityRecord extends IApplicationToken.Stub {
pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
pw.print(" componentSpecified="); pw.print(componentSpecified);
pw.print(" isHomeActivity="); pw.println(isHomeActivity);
- pw.print(prefix); pw.print("configuration="); pw.println(configuration);
+ pw.print(prefix); pw.print("config="); pw.println(configuration);
if (resultTo != null || resultWho != null) {
pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
pw.print(" resultWho="); pw.print(resultWho);
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index 44c9742818dc..db235ee849e2 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -60,7 +60,7 @@ class ContentProviderRecord extends ContentProviderHolder {
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("package=");
pw.print(info.applicationInfo.packageName);
- pw.print("process="); pw.println(info.processName);
+ pw.print(" process="); pw.println(info.processName);
pw.print(prefix); pw.print("app="); pw.println(app);
if (launchingApp != null) {
pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index e5aceb45c4d9..1a617dd05620 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -211,7 +211,7 @@ class ServiceRecord extends Binder {
pw.print(" lastActivity=");
TimeUtils.formatDuration(lastActivity, now, pw);
pw.println("");
- pw.print(prefix); pw.print(" executingStart=");
+ pw.print(prefix); pw.print("executingStart=");
TimeUtils.formatDuration(executingStart, now, pw);
pw.print(" restartTime=");
TimeUtils.formatDuration(restartTime, now, pw);
diff --git a/services/java/com/android/server/am/TransferPipe.java b/services/java/com/android/server/am/TransferPipe.java
new file mode 100644
index 000000000000..c3f4f935d97d
--- /dev/null
+++ b/services/java/com/android/server/am/TransferPipe.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.server.am;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Slog;
+
+/**
+ * Helper for transferring data through a pipe from a client app.
+ */
+class TransferPipe implements Runnable {
+ static final String TAG = "TransferPipe";
+ static final boolean DEBUG = false;
+
+ static final long DEFAULT_TIMEOUT = 5000; // 5 seconds
+
+ final Thread mThread;;
+ final ParcelFileDescriptor[] mFds;
+
+ FileDescriptor mOutFd;
+ long mEndTime;
+ String mFailure;
+ boolean mComplete;
+
+ String mBufferPrefix;
+
+ interface Caller {
+ void go(IInterface iface, FileDescriptor fd, String prefix,
+ String[] args) throws RemoteException;
+ }
+
+ TransferPipe() throws IOException {
+ mThread = new Thread(this, "TransferPipe");
+ mFds = ParcelFileDescriptor.createPipe();
+ }
+
+ ParcelFileDescriptor getReadFd() {
+ return mFds[0];
+ }
+
+ ParcelFileDescriptor getWriteFd() {
+ return mFds[1];
+ }
+
+ void setBufferPrefix(String prefix) {
+ mBufferPrefix = prefix;
+ }
+
+ static void go(Caller caller, IInterface iface, FileDescriptor out,
+ String prefix, String[] args) throws IOException, RemoteException {
+ go(caller, iface, out, prefix, args, DEFAULT_TIMEOUT);
+ }
+
+ static void go(Caller caller, IInterface iface, FileDescriptor out,
+ String prefix, String[] args, long timeout) throws IOException, RemoteException {
+ if ((iface.asBinder()) instanceof Binder) {
+ // This is a local object... just call it directly.
+ try {
+ caller.go(iface, out, prefix, args);
+ } catch (RemoteException e) {
+ }
+ return;
+ }
+
+ TransferPipe tp = new TransferPipe();
+ try {
+ caller.go(iface, tp.getWriteFd().getFileDescriptor(), prefix, args);
+ tp.go(out, timeout);
+ } finally {
+ tp.kill();
+ }
+ }
+
+ static void goDump(IBinder binder, FileDescriptor out,
+ String[] args) throws IOException, RemoteException {
+ goDump(binder, out, args, DEFAULT_TIMEOUT);
+ }
+
+ static void goDump(IBinder binder, FileDescriptor out,
+ String[] args, long timeout) throws IOException, RemoteException {
+ if (binder instanceof Binder) {
+ // This is a local object... just call it directly.
+ try {
+ binder.dump(out, args);
+ } catch (RemoteException e) {
+ }
+ return;
+ }
+
+ TransferPipe tp = new TransferPipe();
+ try {
+ binder.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
+ tp.go(out, timeout);
+ } finally {
+ tp.kill();
+ }
+ }
+
+ void go(FileDescriptor out) throws IOException {
+ go(out, DEFAULT_TIMEOUT);
+ }
+
+ void go(FileDescriptor out, long timeout) throws IOException {
+ try {
+ synchronized (this) {
+ mOutFd = out;
+ mEndTime = SystemClock.uptimeMillis() + timeout;
+
+ if (DEBUG) Slog.i(TAG, "read=" + getReadFd() + " write=" + getWriteFd()
+ + " out=" + out);
+
+ // Close the write fd, so we know when the other side is done.
+ closeFd(1);
+
+ mThread.start();
+
+ while (mFailure == null && !mComplete) {
+ long waitTime = mEndTime - SystemClock.uptimeMillis();
+ if (waitTime <= 0) {
+ if (DEBUG) Slog.i(TAG, "TIMEOUT!");
+ mThread.interrupt();
+ throw new IOException("Timeout");
+ }
+
+ try {
+ wait(waitTime);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ if (DEBUG) Slog.i(TAG, "Finished: " + mFailure);
+ if (mFailure != null) {
+ throw new IOException(mFailure);
+ }
+ }
+ } finally {
+ kill();
+ }
+ }
+
+ void closeFd(int num) {
+ if (mFds[num] != null) {
+ if (DEBUG) Slog.i(TAG, "Closing: " + mFds[num]);
+ try {
+ mFds[num].close();
+ } catch (IOException e) {
+ }
+ mFds[num] = null;
+ }
+ }
+
+ void kill() {
+ closeFd(0);
+ closeFd(1);
+ }
+
+ @Override
+ public void run() {
+ final byte[] buffer = new byte[1024];
+ final FileInputStream fis = new FileInputStream(getReadFd().getFileDescriptor());
+ final FileOutputStream fos = new FileOutputStream(mOutFd);
+
+ if (DEBUG) Slog.i(TAG, "Ready to read pipe...");
+ byte[] bufferPrefix = null;
+ boolean needPrefix = true;
+ if (mBufferPrefix != null) {
+ bufferPrefix = mBufferPrefix.getBytes();
+ }
+
+ int size;
+ try {
+ while ((size=fis.read(buffer)) > 0) {
+ if (DEBUG) Slog.i(TAG, "Got " + size + " bytes");
+ if (bufferPrefix == null) {
+ fos.write(buffer, 0, size);
+ } else {
+ int start = 0;
+ for (int i=0; i<size; i++) {
+ if (buffer[i] != '\n') {
+ if (i > start) {
+ fos.write(buffer, start, i-start);
+ }
+ start = i;
+ if (needPrefix) {
+ fos.write(bufferPrefix);
+ needPrefix = false;
+ }
+ do {
+ i++;
+ } while (i<size && buffer[i] != '\n');
+ if (i < size) {
+ needPrefix = true;
+ }
+ }
+ }
+ if (size > start) {
+ fos.write(buffer, start, size-start);
+ }
+ }
+ }
+ if (DEBUG) Slog.i(TAG, "End of pipe: size=" + size);
+ if (mThread.isInterrupted()) {
+ if (DEBUG) Slog.i(TAG, "Interrupted!");
+ }
+ } catch (IOException e) {
+ synchronized (this) {
+ mFailure = e.toString();
+ notifyAll();
+ return;
+ }
+ }
+
+ synchronized (this) {
+ mComplete = true;
+ notifyAll();
+ }
+ }
+}