Add new -W option to Am to wait for the start to complete.

This commit is contained in:
Dianne Hackborn
2010-02-25 18:48:12 -08:00
parent 59dc9ecec6
commit 8f7f35e0cc
5 changed files with 250 additions and 17 deletions

View File

@@ -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" +

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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.

View File

@@ -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) {