Add new -W option to Am to wait for the start to complete.
This commit is contained in:
@@ -35,6 +35,7 @@ import android.view.IWindowManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
@@ -47,6 +48,7 @@ public class Am {
|
||||
private String mCurArgData;
|
||||
|
||||
private boolean mDebugOption = false;
|
||||
private boolean mWaitOption = false;
|
||||
|
||||
// These are magic strings understood by the Eclipse plugin.
|
||||
private static final String FATAL_ERROR_CODE = "Error type 1";
|
||||
@@ -106,6 +108,7 @@ public class Am {
|
||||
boolean hasIntentInfo = false;
|
||||
|
||||
mDebugOption = false;
|
||||
mWaitOption = false;
|
||||
Uri data = null;
|
||||
String type = null;
|
||||
|
||||
@@ -153,6 +156,8 @@ public class Am {
|
||||
intent.setFlags(Integer.decode(str).intValue());
|
||||
} else if (opt.equals("-D")) {
|
||||
mDebugOption = true;
|
||||
} else if (opt.equals("-W")) {
|
||||
mWaitOption = true;
|
||||
} else {
|
||||
System.err.println("Error: Unknown option: " + opt);
|
||||
showUsage();
|
||||
@@ -199,58 +204,90 @@ public class Am {
|
||||
System.out.println("Starting: " + intent);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
// XXX should do something to determine the MIME type.
|
||||
int res = mAm.startActivity(null, intent, intent.getType(),
|
||||
null, 0, null, null, 0, false, mDebugOption);
|
||||
IActivityManager.WaitResult result = null;
|
||||
int res;
|
||||
if (mWaitOption) {
|
||||
result = mAm.startActivityAndWait(null, intent, intent.getType(),
|
||||
null, 0, null, null, 0, false, mDebugOption);
|
||||
res = result.result;
|
||||
} else {
|
||||
res = mAm.startActivity(null, intent, intent.getType(),
|
||||
null, 0, null, null, 0, false, mDebugOption);
|
||||
}
|
||||
PrintStream out = mWaitOption ? System.out : System.err;
|
||||
boolean launched = false;
|
||||
switch (res) {
|
||||
case IActivityManager.START_SUCCESS:
|
||||
launched = true;
|
||||
break;
|
||||
case IActivityManager.START_SWITCHES_CANCELED:
|
||||
System.err.println(
|
||||
launched = true;
|
||||
out.println(
|
||||
"Warning: Activity not started because the "
|
||||
+ " current activity is being kept for the user.");
|
||||
break;
|
||||
case IActivityManager.START_DELIVERED_TO_TOP:
|
||||
System.err.println(
|
||||
launched = true;
|
||||
out.println(
|
||||
"Warning: Activity not started, intent has "
|
||||
+ "been delivered to currently running "
|
||||
+ "top-most instance.");
|
||||
break;
|
||||
case IActivityManager.START_RETURN_INTENT_TO_CALLER:
|
||||
System.err.println(
|
||||
launched = true;
|
||||
out.println(
|
||||
"Warning: Activity not started because intent "
|
||||
+ "should be handled by the caller");
|
||||
break;
|
||||
case IActivityManager.START_TASK_TO_FRONT:
|
||||
System.err.println(
|
||||
launched = true;
|
||||
out.println(
|
||||
"Warning: Activity not started, its current "
|
||||
+ "task has been brought to the front");
|
||||
break;
|
||||
case IActivityManager.START_INTENT_NOT_RESOLVED:
|
||||
System.err.println(
|
||||
out.println(
|
||||
"Error: Activity not started, unable to "
|
||||
+ "resolve " + intent.toString());
|
||||
break;
|
||||
case IActivityManager.START_CLASS_NOT_FOUND:
|
||||
System.err.println(NO_CLASS_ERROR_CODE);
|
||||
System.err.println("Error: Activity class " +
|
||||
out.println(NO_CLASS_ERROR_CODE);
|
||||
out.println("Error: Activity class " +
|
||||
intent.getComponent().toShortString()
|
||||
+ " does not exist.");
|
||||
break;
|
||||
case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
|
||||
System.err.println(
|
||||
out.println(
|
||||
"Error: Activity not started, you requested to "
|
||||
+ "both forward and receive its result");
|
||||
break;
|
||||
case IActivityManager.START_PERMISSION_DENIED:
|
||||
System.err.println(
|
||||
out.println(
|
||||
"Error: Activity not started, you do not "
|
||||
+ "have permission to access it.");
|
||||
break;
|
||||
default:
|
||||
System.err.println(
|
||||
out.println(
|
||||
"Error: Activity not started, unknown error code " + res);
|
||||
break;
|
||||
}
|
||||
if (mWaitOption && launched) {
|
||||
if (result == null) {
|
||||
result = new IActivityManager.WaitResult();
|
||||
result.who = intent.getComponent();
|
||||
}
|
||||
System.out.println("Status: " + (result.timeout ? "timeout" : "ok"));
|
||||
if (result.who != null) {
|
||||
System.out.println("Activity: " + result.who.flattenToShortString());
|
||||
}
|
||||
if (result.thisTime >= 0) {
|
||||
System.out.println("ThisTime: " + result.thisTime);
|
||||
}
|
||||
if (result.totalTime >= 0) {
|
||||
System.out.println("TotalTime: " + result.totalTime);
|
||||
}
|
||||
System.out.println("Complete");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendBroadcast() throws Exception {
|
||||
@@ -504,8 +541,9 @@ public class Am {
|
||||
System.err.println(
|
||||
"usage: am [subcommand] [options]\n" +
|
||||
"\n" +
|
||||
" start an Activity: am start [-D] <INTENT>\n" +
|
||||
" start an Activity: am start [-D] [-W] <INTENT>\n" +
|
||||
" -D: enable debugging\n" +
|
||||
" -W: wait for launch to complete\n" +
|
||||
"\n" +
|
||||
" start a Service: am startservice <INTENT>\n" +
|
||||
"\n" +
|
||||
|
||||
@@ -146,6 +146,28 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
|
||||
return true;
|
||||
}
|
||||
|
||||
case START_ACTIVITY_AND_WAIT_TRANSACTION:
|
||||
{
|
||||
data.enforceInterface(IActivityManager.descriptor);
|
||||
IBinder b = data.readStrongBinder();
|
||||
IApplicationThread app = ApplicationThreadNative.asInterface(b);
|
||||
Intent intent = Intent.CREATOR.createFromParcel(data);
|
||||
String resolvedType = data.readString();
|
||||
Uri[] grantedUriPermissions = data.createTypedArray(Uri.CREATOR);
|
||||
int grantedMode = data.readInt();
|
||||
IBinder resultTo = data.readStrongBinder();
|
||||
String resultWho = data.readString();
|
||||
int requestCode = data.readInt();
|
||||
boolean onlyIfNeeded = data.readInt() != 0;
|
||||
boolean debug = data.readInt() != 0;
|
||||
WaitResult result = startActivityAndWait(app, intent, resolvedType,
|
||||
grantedUriPermissions, grantedMode, resultTo, resultWho,
|
||||
requestCode, onlyIfNeeded, debug);
|
||||
reply.writeNoException();
|
||||
result.writeToParcel(reply, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
case START_ACTIVITY_INTENT_SENDER_TRANSACTION:
|
||||
{
|
||||
data.enforceInterface(IActivityManager.descriptor);
|
||||
@@ -1238,6 +1260,31 @@ class ActivityManagerProxy implements IActivityManager
|
||||
data.recycle();
|
||||
return result;
|
||||
}
|
||||
public WaitResult startActivityAndWait(IApplicationThread caller, Intent intent,
|
||||
String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
|
||||
IBinder resultTo, String resultWho,
|
||||
int requestCode, boolean onlyIfNeeded,
|
||||
boolean debug) throws RemoteException {
|
||||
Parcel data = Parcel.obtain();
|
||||
Parcel reply = Parcel.obtain();
|
||||
data.writeInterfaceToken(IActivityManager.descriptor);
|
||||
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
|
||||
intent.writeToParcel(data, 0);
|
||||
data.writeString(resolvedType);
|
||||
data.writeTypedArray(grantedUriPermissions, 0);
|
||||
data.writeInt(grantedMode);
|
||||
data.writeStrongBinder(resultTo);
|
||||
data.writeString(resultWho);
|
||||
data.writeInt(requestCode);
|
||||
data.writeInt(onlyIfNeeded ? 1 : 0);
|
||||
data.writeInt(debug ? 1 : 0);
|
||||
mRemote.transact(START_ACTIVITY_AND_WAIT_TRANSACTION, data, reply, 0);
|
||||
reply.readException();
|
||||
WaitResult result = WaitResult.CREATOR.createFromParcel(reply);
|
||||
reply.recycle();
|
||||
data.recycle();
|
||||
return result;
|
||||
}
|
||||
public int startActivityIntentSender(IApplicationThread caller,
|
||||
IntentSender intent, Intent fillInIntent, String resolvedType,
|
||||
IBinder resultTo, String resultWho, int requestCode,
|
||||
|
||||
@@ -84,6 +84,10 @@ public interface IActivityManager extends IInterface {
|
||||
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
|
||||
int grantedMode, IBinder resultTo, String resultWho, int requestCode,
|
||||
boolean onlyIfNeeded, boolean debug) throws RemoteException;
|
||||
public WaitResult startActivityAndWait(IApplicationThread caller,
|
||||
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
|
||||
int grantedMode, IBinder resultTo, String resultWho, int requestCode,
|
||||
boolean onlyIfNeeded, boolean debug) throws RemoteException;
|
||||
public int startActivityIntentSender(IApplicationThread caller,
|
||||
IntentSender intent, Intent fillInIntent, String resolvedType,
|
||||
IBinder resultTo, String resultWho, int requestCode,
|
||||
@@ -348,6 +352,49 @@ public interface IActivityManager extends IInterface {
|
||||
}
|
||||
};
|
||||
|
||||
/** Information returned after waiting for an activity start. */
|
||||
public static class WaitResult implements Parcelable {
|
||||
public int result;
|
||||
public boolean timeout;
|
||||
public ComponentName who;
|
||||
public long thisTime;
|
||||
public long totalTime;
|
||||
|
||||
public WaitResult() {
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(result);
|
||||
dest.writeInt(timeout ? 1 : 0);
|
||||
ComponentName.writeToParcel(who, dest);
|
||||
dest.writeLong(thisTime);
|
||||
dest.writeLong(totalTime);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<WaitResult> CREATOR
|
||||
= new Parcelable.Creator<WaitResult>() {
|
||||
public WaitResult createFromParcel(Parcel source) {
|
||||
return new WaitResult(source);
|
||||
}
|
||||
|
||||
public WaitResult[] newArray(int size) {
|
||||
return new WaitResult[size];
|
||||
}
|
||||
};
|
||||
|
||||
private WaitResult(Parcel source) {
|
||||
result = source.readInt();
|
||||
timeout = source.readInt() != 0;
|
||||
who = ComponentName.readFromParcel(source);
|
||||
thisTime = source.readLong();
|
||||
totalTime = source.readLong();
|
||||
}
|
||||
};
|
||||
|
||||
String descriptor = "android.app.IActivityManager";
|
||||
|
||||
// Please keep these transaction codes the same -- they are also
|
||||
@@ -453,4 +500,5 @@ public interface IActivityManager extends IInterface {
|
||||
int HANDLE_APPLICATION_WTF_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+101;
|
||||
int KILL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+102;
|
||||
int IS_USER_A_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+103;
|
||||
int START_ACTIVITY_AND_WAIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+104;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.app.AlertDialog;
|
||||
import android.app.ApplicationErrorReport;
|
||||
import android.app.Dialog;
|
||||
import android.app.IActivityController;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.IActivityWatcher;
|
||||
import android.app.IApplicationThread;
|
||||
import android.app.IInstrumentationWatcher;
|
||||
@@ -387,6 +388,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
|
||||
= new ArrayList<PendingActivityLaunch>();
|
||||
|
||||
/**
|
||||
* List of people waiting to find out about the next launched activity.
|
||||
*/
|
||||
final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
|
||||
= new ArrayList<IActivityManager.WaitResult>();
|
||||
|
||||
/**
|
||||
* List of people waiting to find out about the next visible activity.
|
||||
*/
|
||||
final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
|
||||
= new ArrayList<IActivityManager.WaitResult>();
|
||||
|
||||
/**
|
||||
* List of all active broadcasts that are to be executed immediately
|
||||
* (without waiting for another broadcast to finish). Currently this only
|
||||
@@ -3559,11 +3572,38 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
return START_SUCCESS;
|
||||
}
|
||||
|
||||
public final int startActivity(IApplicationThread caller,
|
||||
void reportActivityLaunchedLocked(boolean timeout, HistoryRecord r,
|
||||
long thisTime, long totalTime) {
|
||||
for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
|
||||
WaitResult w = mWaitingActivityLaunched.get(i);
|
||||
w.timeout = timeout;
|
||||
if (r != null) {
|
||||
w.who = new ComponentName(r.info.packageName, r.info.name);
|
||||
}
|
||||
w.thisTime = thisTime;
|
||||
w.totalTime = totalTime;
|
||||
}
|
||||
notify();
|
||||
}
|
||||
|
||||
void reportActivityVisibleLocked(HistoryRecord r) {
|
||||
for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
|
||||
WaitResult w = mWaitingActivityVisible.get(i);
|
||||
w.timeout = false;
|
||||
if (r != null) {
|
||||
w.who = new ComponentName(r.info.packageName, r.info.name);
|
||||
}
|
||||
w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
|
||||
w.thisTime = w.totalTime;
|
||||
}
|
||||
notify();
|
||||
}
|
||||
|
||||
private final int startActivityMayWait(IApplicationThread caller,
|
||||
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
|
||||
int grantedMode, IBinder resultTo,
|
||||
String resultWho, int requestCode, boolean onlyIfNeeded,
|
||||
boolean debug) {
|
||||
boolean debug, WaitResult outResult) {
|
||||
// Refuse possible leaked file descriptors
|
||||
if (intent != null && intent.hasFileDescriptors()) {
|
||||
throw new IllegalArgumentException("File descriptors passed in Intent");
|
||||
@@ -3603,7 +3643,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
}
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
synchronized (this) {
|
||||
int callingPid;
|
||||
int callingUid;
|
||||
if (caller == null) {
|
||||
@@ -3618,11 +3658,62 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
resultTo, resultWho, requestCode, callingPid, callingUid,
|
||||
onlyIfNeeded, componentSpecified);
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
|
||||
if (outResult != null) {
|
||||
outResult.result = res;
|
||||
if (res == IActivityManager.START_SUCCESS) {
|
||||
mWaitingActivityLaunched.add(outResult);
|
||||
do {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
} while (!outResult.timeout && outResult.who == null);
|
||||
} else if (res == IActivityManager.START_TASK_TO_FRONT) {
|
||||
HistoryRecord r = this.topRunningActivityLocked(null);
|
||||
if (r.nowVisible) {
|
||||
outResult.timeout = false;
|
||||
outResult.who = new ComponentName(r.info.packageName, r.info.name);
|
||||
outResult.totalTime = 0;
|
||||
outResult.thisTime = 0;
|
||||
} else {
|
||||
outResult.thisTime = SystemClock.uptimeMillis();
|
||||
mWaitingActivityVisible.add(outResult);
|
||||
do {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
} while (!outResult.timeout && outResult.who == null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
public int startActivityIntentSender(IApplicationThread caller,
|
||||
public final int startActivity(IApplicationThread caller,
|
||||
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
|
||||
int grantedMode, IBinder resultTo,
|
||||
String resultWho, int requestCode, boolean onlyIfNeeded,
|
||||
boolean debug) {
|
||||
return startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions,
|
||||
grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, null);
|
||||
}
|
||||
|
||||
public final WaitResult startActivityAndWait(IApplicationThread caller,
|
||||
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
|
||||
int grantedMode, IBinder resultTo,
|
||||
String resultWho, int requestCode, boolean onlyIfNeeded,
|
||||
boolean debug) {
|
||||
WaitResult res = new WaitResult();
|
||||
startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions,
|
||||
grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
public int startActivityIntentSender(IApplicationThread caller,
|
||||
IntentSender intent, Intent fillInIntent, String resolvedType,
|
||||
IBinder resultTo, String resultWho, int requestCode,
|
||||
int flagsMask, int flagsValues) {
|
||||
@@ -5505,6 +5596,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
if (index >= 0) {
|
||||
HistoryRecord r = (HistoryRecord)mHistory.get(index);
|
||||
|
||||
if (fromTimeout) {
|
||||
reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
|
||||
}
|
||||
|
||||
// This is a hack to semi-deal with a race condition
|
||||
// in the client where it can be constructed with a
|
||||
// newer configuration from when we asked it to launch.
|
||||
@@ -5539,6 +5634,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
mBooted = true;
|
||||
enableScreen = true;
|
||||
}
|
||||
|
||||
} else if (fromTimeout) {
|
||||
reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
|
||||
}
|
||||
|
||||
// Atomically retrieve all of the other things to do.
|
||||
|
||||
@@ -387,12 +387,14 @@ class HistoryRecord extends IApplicationToken.Stub {
|
||||
sb.append(" ms)");
|
||||
Log.i(ActivityManagerService.TAG, sb.toString());
|
||||
}
|
||||
service.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
|
||||
if (totalTime > 0) {
|
||||
service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
|
||||
}
|
||||
startTime = 0;
|
||||
service.mInitialStartTime = 0;
|
||||
}
|
||||
service.reportActivityVisibleLocked(this);
|
||||
if (ActivityManagerService.DEBUG_SWITCH) Log.v(
|
||||
ActivityManagerService.TAG, "windowsVisible(): " + this);
|
||||
if (!nowVisible) {
|
||||
|
||||
Reference in New Issue
Block a user