Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f7f35e0 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

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

parent 59dc9ece
Loading
Loading
Loading
Loading
+51 −13
Original line number Diff line number Diff line
@@ -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(),
        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" +
+47 −0
Original line number Diff line number Diff line
@@ -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,
+48 −0
Original line number Diff line number Diff line
@@ -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;
}
+102 −4
Original line number Diff line number Diff line
@@ -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");
@@ -3618,10 +3658,61 @@ 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 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,
@@ -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.
+2 −0
Original line number Diff line number Diff line
@@ -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) {