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 name="args" type="java.lang.String[]">
|
||||||
</parameter>
|
</parameter>
|
||||||
</method>
|
</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"
|
<method name="flushPendingCommands"
|
||||||
return="void"
|
return="void"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
@ -147801,6 +147816,23 @@
|
|||||||
<exception name="RemoteException" type="android.os.RemoteException">
|
<exception name="RemoteException" type="android.os.RemoteException">
|
||||||
</exception>
|
</exception>
|
||||||
</method>
|
</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"
|
<method name="getInterfaceDescriptor"
|
||||||
return="java.lang.String"
|
return="java.lang.String"
|
||||||
abstract="true"
|
abstract="true"
|
||||||
@ -150155,6 +150187,21 @@
|
|||||||
visibility="public"
|
visibility="public"
|
||||||
>
|
>
|
||||||
</method>
|
</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"
|
<method name="fromSocket"
|
||||||
return="android.os.ParcelFileDescriptor"
|
return="android.os.ParcelFileDescriptor"
|
||||||
abstract="false"
|
abstract="false"
|
||||||
|
@ -186,11 +186,16 @@ static void dumpstate() {
|
|||||||
run_command("DUMPSYS", 60, "dumpsys", NULL);
|
run_command("DUMPSYS", 60, "dumpsys", NULL);
|
||||||
|
|
||||||
printf("========================================================\n");
|
printf("========================================================\n");
|
||||||
printf("== Application Services\n");
|
printf("== Running Application Activities\n");
|
||||||
printf("========================================================\n");
|
printf("========================================================\n");
|
||||||
|
|
||||||
/* Instead of a 60s timeout, we should give each service a 5 second timeout */
|
run_command("APP ACTIVITIES", 30, "dumpsys", "activity", "all", NULL);
|
||||||
run_command("APP SERVICES", 60, "dumpsys", "activity", "service", 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 {
|
static final class DumpComponentInfo {
|
||||||
FileDescriptor fd;
|
ParcelFileDescriptor fd;
|
||||||
IBinder token;
|
IBinder token;
|
||||||
String prefix;
|
String prefix;
|
||||||
String[] args;
|
String[] args;
|
||||||
boolean dumped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class ResultData {
|
static final class ResultData {
|
||||||
@ -639,20 +638,13 @@ public final class ActivityThread {
|
|||||||
|
|
||||||
public void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args) {
|
public void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args) {
|
||||||
DumpComponentInfo data = new DumpComponentInfo();
|
DumpComponentInfo data = new DumpComponentInfo();
|
||||||
data.fd = fd;
|
try {
|
||||||
data.token = servicetoken;
|
data.fd = ParcelFileDescriptor.dup(fd);
|
||||||
data.args = args;
|
data.token = servicetoken;
|
||||||
data.dumped = false;
|
data.args = args;
|
||||||
queueOrSendMessage(H.DUMP_SERVICE, data);
|
queueOrSendMessage(H.DUMP_SERVICE, data);
|
||||||
synchronized (data) {
|
} catch (IOException e) {
|
||||||
while (!data.dumped) {
|
Slog.w(TAG, "dumpService failed", e);
|
||||||
try {
|
|
||||||
data.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// no need to do anything here, we will keep waiting until
|
|
||||||
// dumped is set
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,21 +706,14 @@ public final class ActivityThread {
|
|||||||
public void dumpActivity(FileDescriptor fd, IBinder activitytoken,
|
public void dumpActivity(FileDescriptor fd, IBinder activitytoken,
|
||||||
String prefix, String[] args) {
|
String prefix, String[] args) {
|
||||||
DumpComponentInfo data = new DumpComponentInfo();
|
DumpComponentInfo data = new DumpComponentInfo();
|
||||||
data.fd = fd;
|
try {
|
||||||
data.token = activitytoken;
|
data.fd = ParcelFileDescriptor.dup(fd);
|
||||||
data.prefix = prefix;
|
data.token = activitytoken;
|
||||||
data.args = args;
|
data.prefix = prefix;
|
||||||
data.dumped = false;
|
data.args = args;
|
||||||
queueOrSendMessage(H.DUMP_ACTIVITY, data);
|
queueOrSendMessage(H.DUMP_ACTIVITY, data);
|
||||||
synchronized (data) {
|
} catch (IOException e) {
|
||||||
while (!data.dumped) {
|
Slog.w(TAG, "dumpActivity failed", e);
|
||||||
try {
|
|
||||||
data.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// no need to do anything here, we will keep waiting until
|
|
||||||
// dumped is set
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2154,33 +2139,27 @@ public final class ActivityThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleDumpService(DumpComponentInfo info) {
|
private void handleDumpService(DumpComponentInfo info) {
|
||||||
try {
|
Service s = mServices.get(info.token);
|
||||||
Service s = mServices.get(info.token);
|
if (s != null) {
|
||||||
if (s != null) {
|
PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor()));
|
||||||
PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd));
|
s.dump(info.fd.getFileDescriptor(), pw, info.args);
|
||||||
s.dump(info.fd, pw, info.args);
|
pw.flush();
|
||||||
pw.close();
|
try {
|
||||||
}
|
info.fd.close();
|
||||||
} finally {
|
} catch (IOException e) {
|
||||||
synchronized (info) {
|
|
||||||
info.dumped = true;
|
|
||||||
info.notifyAll();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDumpActivity(DumpComponentInfo info) {
|
private void handleDumpActivity(DumpComponentInfo info) {
|
||||||
try {
|
ActivityClientRecord r = mActivities.get(info.token);
|
||||||
ActivityClientRecord r = mActivities.get(info.token);
|
if (r != null && r.activity != null) {
|
||||||
if (r != null && r.activity != null) {
|
PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd.getFileDescriptor()));
|
||||||
PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd));
|
r.activity.dump(info.prefix, info.fd.getFileDescriptor(), pw, info.args);
|
||||||
r.activity.dump(info.prefix, info.fd, pw, info.args);
|
pw.flush();
|
||||||
pw.close();
|
try {
|
||||||
}
|
info.fd.close();
|
||||||
} finally {
|
} catch (IOException e) {
|
||||||
synchronized (info) {
|
|
||||||
info.dumped = true;
|
|
||||||
info.notifyAll();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -845,7 +845,7 @@ class ApplicationThreadProxy implements IApplicationThread {
|
|||||||
data.writeFileDescriptor(fd);
|
data.writeFileDescriptor(fd);
|
||||||
data.writeStrongBinder(token);
|
data.writeStrongBinder(token);
|
||||||
data.writeStringArray(args);
|
data.writeStringArray(args);
|
||||||
mRemote.transact(DUMP_SERVICE_TRANSACTION, data, null, 0);
|
mRemote.transact(DUMP_SERVICE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
|
||||||
data.recycle();
|
data.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -967,7 +967,7 @@ class ApplicationThreadProxy implements IApplicationThread {
|
|||||||
data.writeStrongBinder(token);
|
data.writeStrongBinder(token);
|
||||||
data.writeString(prefix);
|
data.writeString(prefix);
|
||||||
data.writeStringArray(args);
|
data.writeStringArray(args);
|
||||||
mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, 0);
|
mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
|
||||||
data.recycle();
|
data.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,45 +303,106 @@ public final class Configuration implements Parcelable, Comparable<Configuration
|
|||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder(128);
|
StringBuilder sb = new StringBuilder(128);
|
||||||
sb.append("{ scale=");
|
sb.append("{ fnt=");
|
||||||
sb.append(fontScale);
|
sb.append(fontScale);
|
||||||
sb.append(" imsi=");
|
sb.append(" imsi=");
|
||||||
sb.append(mcc);
|
sb.append(mcc);
|
||||||
sb.append("/");
|
sb.append("/");
|
||||||
sb.append(mnc);
|
sb.append(mnc);
|
||||||
sb.append(" loc=");
|
if (locale != null) {
|
||||||
sb.append(locale);
|
sb.append(" ");
|
||||||
sb.append(" touch=");
|
sb.append(locale);
|
||||||
sb.append(touchscreen);
|
} else {
|
||||||
sb.append(" keys=");
|
sb.append(" (no locale)");
|
||||||
sb.append(keyboard);
|
}
|
||||||
sb.append("/");
|
switch (touchscreen) {
|
||||||
sb.append(keyboardHidden);
|
case TOUCHSCREEN_UNDEFINED: sb.append(" ?touch"); break;
|
||||||
sb.append("/");
|
case TOUCHSCREEN_NOTOUCH: sb.append(" -touch"); break;
|
||||||
sb.append(hardKeyboardHidden);
|
case TOUCHSCREEN_STYLUS: sb.append(" stylus"); break;
|
||||||
sb.append(" nav=");
|
case TOUCHSCREEN_FINGER: sb.append(" finger"); break;
|
||||||
sb.append(navigation);
|
default: sb.append(" touch="); sb.append(touchscreen); break;
|
||||||
sb.append("/");
|
}
|
||||||
sb.append(navigationHidden);
|
switch (keyboard) {
|
||||||
sb.append(" orien=");
|
case KEYBOARD_UNDEFINED: sb.append(" ?keyb"); break;
|
||||||
switch(orientation) {
|
case KEYBOARD_NOKEYS: sb.append(" -keyb"); break;
|
||||||
case ORIENTATION_LANDSCAPE:
|
case KEYBOARD_QWERTY: sb.append(" qwerty"); break;
|
||||||
sb.append("L"); break;
|
case KEYBOARD_12KEY: sb.append(" 12key"); break;
|
||||||
case ORIENTATION_PORTRAIT:
|
default: sb.append(" keys="); sb.append(keyboard); break;
|
||||||
sb.append("P"); break;
|
}
|
||||||
default:
|
switch (keyboardHidden) {
|
||||||
sb.append(orientation);
|
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) {
|
if (seq != 0) {
|
||||||
sb.append(" seq=");
|
sb.append(" s.");
|
||||||
sb.append(seq);
|
sb.append(seq);
|
||||||
}
|
}
|
||||||
sb.append('}');
|
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.
|
* 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() {
|
BinderProxy() {
|
||||||
mSelf = new WeakReference(this);
|
mSelf = new WeakReference(this);
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,16 @@ public interface IBinder {
|
|||||||
*/
|
*/
|
||||||
public void dump(FileDescriptor fd, String[] args) throws RemoteException;
|
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.
|
* Perform a generic operation with the object.
|
||||||
*
|
*
|
||||||
|
@ -1383,6 +1383,8 @@ public final class Parcel {
|
|||||||
private native FileDescriptor internalReadFileDescriptor();
|
private native FileDescriptor internalReadFileDescriptor();
|
||||||
/*package*/ static native FileDescriptor openFileDescriptor(String file,
|
/*package*/ static native FileDescriptor openFileDescriptor(String file,
|
||||||
int mode) throws FileNotFoundException;
|
int mode) throws FileNotFoundException;
|
||||||
|
/*package*/ static native FileDescriptor dupFileDescriptor(FileDescriptor orig)
|
||||||
|
throws IOException;
|
||||||
/*package*/ static native void closeFileDescriptor(FileDescriptor desc)
|
/*package*/ static native void closeFileDescriptor(FileDescriptor desc)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
/*package*/ static native void clearFileDescriptor(FileDescriptor desc);
|
/*package*/ static native void clearFileDescriptor(FileDescriptor desc);
|
||||||
|
@ -116,6 +116,17 @@ public class ParcelFileDescriptor implements Parcelable {
|
|||||||
return fd != null ? new ParcelFileDescriptor(fd) : null;
|
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.
|
* 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);
|
int fd = open(name8.string(), flags, realMode);
|
||||||
if (fd < 0) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
jobject object = newFileDescriptor(env, fd);
|
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)
|
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);
|
int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
|
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)
|
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);
|
int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
|
env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
|
||||||
@ -1735,6 +1767,7 @@ static const JNINativeMethod gParcelMethods[] = {
|
|||||||
{"readStrongBinder", "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
|
{"readStrongBinder", "()Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
|
||||||
{"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
|
{"internalReadFileDescriptor", "()Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
|
||||||
{"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
|
{"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},
|
{"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
|
||||||
{"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
|
{"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
|
||||||
{"freeBuffer", "()V", (void*)android_os_Parcel_freeBuffer},
|
{"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(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
|
||||||
pw.print(" componentSpecified="); pw.print(componentSpecified);
|
pw.print(" componentSpecified="); pw.print(componentSpecified);
|
||||||
pw.print(" isHomeActivity="); pw.println(isHomeActivity);
|
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) {
|
if (resultTo != null || resultWho != null) {
|
||||||
pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
|
pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
|
||||||
pw.print(" resultWho="); pw.print(resultWho);
|
pw.print(" resultWho="); pw.print(resultWho);
|
||||||
|
@ -60,7 +60,7 @@ class ContentProviderRecord extends ContentProviderHolder {
|
|||||||
void dump(PrintWriter pw, String prefix) {
|
void dump(PrintWriter pw, String prefix) {
|
||||||
pw.print(prefix); pw.print("package=");
|
pw.print(prefix); pw.print("package=");
|
||||||
pw.print(info.applicationInfo.packageName);
|
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);
|
pw.print(prefix); pw.print("app="); pw.println(app);
|
||||||
if (launchingApp != null) {
|
if (launchingApp != null) {
|
||||||
pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
|
pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp);
|
||||||
|
@ -211,7 +211,7 @@ class ServiceRecord extends Binder {
|
|||||||
pw.print(" lastActivity=");
|
pw.print(" lastActivity=");
|
||||||
TimeUtils.formatDuration(lastActivity, now, pw);
|
TimeUtils.formatDuration(lastActivity, now, pw);
|
||||||
pw.println("");
|
pw.println("");
|
||||||
pw.print(prefix); pw.print(" executingStart=");
|
pw.print(prefix); pw.print("executingStart=");
|
||||||
TimeUtils.formatDuration(executingStart, now, pw);
|
TimeUtils.formatDuration(executingStart, now, pw);
|
||||||
pw.print(" restartTime=");
|
pw.print(" restartTime=");
|
||||||
TimeUtils.formatDuration(restartTime, now, pw);
|
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