am 700ab1c7
: Merge "DO NOT MERGE. Integrate from master: Improve activity manager debug dumps." into honeycomb-mr2
* commit '700ab1c75862babba90f54e02bdc877becd4f4fc': DO NOT MERGE. Integrate from master: Improve activity manager debug dumps.
This commit is contained in:
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
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");
|
||||
}
|
||||
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 (seq != 0) {
|
||||
sb.append(" seq=");
|
||||
sb.append(" s.");
|
||||
sb.append(seq);
|
||||
}
|
||||
sb.append('}');
|
||||
|
@ -255,6 +255,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.
|
||||
*
|
||||
@ -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);
|
||||
}
|
||||
|
@ -156,6 +156,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.
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -116,6 +116,17 @@ public class ParcelFileDescriptor implements Parcelable {
|
||||
return fd != null ? new ParcelFileDescriptor(fd) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -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},
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
242
services/java/com/android/server/am/TransferPipe.java
Normal file
242
services/java/com/android/server/am/TransferPipe.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user