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

Commit 9f4af535 authored by Dan Egnor's avatar Dan Egnor
Browse files

Make intent broadcasts in "am" synchronous (they wait until exit).

Clean up error handling and reporting in "am".
Make the usage message for "am" more informative.

Make it easier to turn on logging in GoogleHttpClient.
parent 2f140bdb
Loading
Loading
Loading
Loading
+261 −305
Original line number Diff line number Diff line
@@ -23,16 +23,19 @@ import android.app.IActivityManager;
import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.AndroidException;
import android.view.IWindowManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.Set;

@@ -45,16 +48,29 @@ public class Am {

    private boolean mDebugOption = false;

    // These are magic strings understood by the Eclipse plugin.
    private static final String FATAL_ERROR_CODE = "Error type 1";
    private static final String NO_SYSTEM_ERROR_CODE = "Error type 2";
    private static final String NO_CLASS_ERROR_CODE = "Error type 3";

    /**
     * Command-line entry point.
     *
     * @param args The command-line arguments
     */
    public static void main(String[] args) {
        try {
            (new Am()).run(args);
        } catch (IllegalArgumentException e) {
            showUsage();
            System.err.println("Error: " + e.getMessage());
        } catch (Exception e) {
            System.err.println(e.toString());
            System.exit(1);
        }
    }

    private void run(String[] args) {
    private void run(String[] args) throws Exception {
        if (args.length < 1) {
            showUsage();
            return;
@@ -62,16 +78,14 @@ public class Am {

        mAm = ActivityManagerNative.getDefault();
        if (mAm == null) {
            System.err.println("Error type 2");
            System.err.println("Error: Unable to connect to activity manager; is the system running?");
            showUsage();
            return;
            System.err.println(NO_SYSTEM_ERROR_CODE);
            throw new AndroidException("Can't connect to activity manager; is the system running?");
        }

        mArgs = args;

        String op = args[0];
        mNextArg = 1;

        if (op.equals("start")) {
            runStart();
        } else if (op.equals("instrument")) {
@@ -81,13 +95,11 @@ public class Am {
        } else if (op.equals("profile")) {
            runProfile();
        } else {
            System.err.println("Error: Unknown command: " + op);
            showUsage();
            return;
            throw new IllegalArgumentException("Unknown command: " + op);
        }
    }

    private Intent makeIntent() {
    private Intent makeIntent() throws URISyntaxException {
        Intent intent = new Intent();
        boolean hasIntentInfo = false;

@@ -95,48 +107,43 @@ public class Am {
        Uri data = null;
        String type = null;

        try {
        String opt;
        while ((opt=nextOption()) != null) {
            if (opt.equals("-a")) {
                    intent.setAction(nextOptionData());
                intent.setAction(nextArgRequired());
                hasIntentInfo = true;
            } else if (opt.equals("-d")) {
                    data = Uri.parse(nextOptionData());
                data = Uri.parse(nextArgRequired());
                hasIntentInfo = true;
            } else if (opt.equals("-t")) {
                    type = nextOptionData();
                type = nextArgRequired();
                hasIntentInfo = true;
            } else if (opt.equals("-c")) {
                    intent.addCategory(nextOptionData());
                intent.addCategory(nextArgRequired());
                hasIntentInfo = true;
            } else if (opt.equals("-e") || opt.equals("--es")) {
                    String key = nextOptionData();
                    String value = nextOptionData();
                String key = nextArgRequired();
                String value = nextArgRequired();
                intent.putExtra(key, value);
                hasIntentInfo = true;
            } else if (opt.equals("--ei")) {
                    String key = nextOptionData();
                    String value = nextOptionData();
                String key = nextArgRequired();
                String value = nextArgRequired();
                intent.putExtra(key, Integer.valueOf(value));
                hasIntentInfo = true;
            } else if (opt.equals("--ez")) {
                    String key = nextOptionData();
                    String value = nextOptionData();
                String key = nextArgRequired();
                String value = nextArgRequired();
                intent.putExtra(key, Boolean.valueOf(value));
                hasIntentInfo = true;
            } else if (opt.equals("-n")) {
                    String str = nextOptionData();
                String str = nextArgRequired();
                ComponentName cn = ComponentName.unflattenFromString(str);
                    if (cn == null) {
                        System.err.println("Error: Bad component name: " + str);
                        showUsage();
                        return null;
                    }
                if (cn == null) throw new IllegalArgumentException("Bad component name: " + str);
                intent.setComponent(cn);
                hasIntentInfo = true;
            } else if (opt.equals("-f")) {
                    String str = nextOptionData();
                String str = nextArgRequired();
                intent.setFlags(Integer.decode(str).intValue());
            } else if (opt.equals("-D")) {
                mDebugOption = true;
@@ -146,24 +153,12 @@ public class Am {
                return null;
            }
        }
        } catch (RuntimeException ex) {
            System.err.println("Error: " + ex.toString());
            showUsage();
            return null;
        }
        intent.setDataAndType(data, type);

        String uri = nextArg();
        if (uri != null) {
            try {
            Intent oldIntent = intent;
                try {
            intent = Intent.getIntent(uri);
                } catch (java.net.URISyntaxException ex) {
                    System.err.println("Bad URI: " + uri);
                    showUsage();
                    return null;
                }
            if (oldIntent.getAction() != null) {
                intent.setAction(oldIntent.getAction());
            }
@@ -177,26 +172,16 @@ public class Am {
                    intent.addCategory((String)it.next());
                }
            }
            } catch (RuntimeException ex) {
                System.err.println("Error creating from URI: " + ex.toString());
                showUsage();
                return null;
            }
        } else if (!hasIntentInfo) {
            System.err.println("Error: No intent supplied");
            showUsage();
            return null;
            hasIntentInfo = true;
        }

        if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied");
        return intent;
    }

    private void runStart() {
    private void runStart() throws Exception {
        Intent intent = makeIntent();
        
        if (intent != null) {
        System.out.println("Starting: " + intent);
            try {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        // XXX should do something to determine the MIME type.
        int res = mAm.startActivity(null, intent, intent.getType(),
@@ -231,7 +216,7 @@ public class Am {
                        + "resolve " + intent.toString());
                break;
            case IActivityManager.START_CLASS_NOT_FOUND:
                        System.err.println("Error type 3");
                System.err.println(NO_CLASS_ERROR_CODE);
                System.err.println("Error: Activity class " +
                        intent.getComponent().toShortString()
                        + " does not exist.");
@@ -248,33 +233,20 @@ public class Am {
                break;
            default:
                System.err.println(
                                "Error: Activity not started, unknown error "
                                + "code " + res);
                        "Error: Activity not started, unknown error code " + res);
                break;
        }
            } catch (RemoteException e) {
                System.err.println("Error type 1");
                System.err.println(
                        "Error: Activity not started, unable to "
                        + "call on to activity manager service");
            }
        }
    }

    private void sendBroadcast() {
    private void sendBroadcast() throws Exception {
        Intent intent = makeIntent();
        
        if (intent != null) {
        IntentReceiver receiver = new IntentReceiver();
        System.out.println("Broadcasting: " + intent);
            try {
                mAm.broadcastIntent(null, intent, null, null, 0, null, null,
                        null, true, false);
            } catch (RemoteException e) {
            }
        }
        mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false);
        receiver.waitForFinish();
    }

    private void runInstrument() {
    private void runInstrument() throws Exception {
        String profileFile = null;
        boolean wait = false;
        boolean rawMode = false;
@@ -283,18 +255,17 @@ public class Am {
        String argKey = null, argValue = null;
        IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));

        try {
        String opt;
        while ((opt=nextOption()) != null) {
            if (opt.equals("-p")) {
                    profileFile = nextOptionData();
                profileFile = nextArgRequired();
            } else if (opt.equals("-w")) {
                wait = true;
            } else if (opt.equals("-r")) {
                rawMode = true;
            } else if (opt.equals("-e")) {
                    argKey = nextOptionData();
                    argValue = nextOptionData();
                argKey = nextArgRequired();
                argValue = nextArgRequired();
                args.putString(argKey, argValue);
            } else if (opt.equals("--no_window_animation")) {
                no_window_animation = true;
@@ -304,25 +275,10 @@ public class Am {
                return;
            }
        }
        } catch (RuntimeException ex) {
            System.err.println("Error: " + ex.toString());
            showUsage();
            return;
        }

        String cnArg = nextArg();
        if (cnArg == null) {
            System.err.println("Error: No instrumentation component supplied");
            showUsage();
            return;
        }

        String cnArg = nextArgRequired();
        ComponentName cn = ComponentName.unflattenFromString(cnArg);
        if (cn == null) {
            System.err.println("Error: Bad component name: " + cnArg);
            showUsage();
            return;
        }
        if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);

        InstrumentationWatcher watcher = null;
        if (wait) {
@@ -331,22 +287,13 @@ public class Am {
        }
        float[] oldAnims = null;
        if (no_window_animation) {
            try {
            oldAnims = wm.getAnimationScales();
            wm.setAnimationScale(0, 0.0f);
            wm.setAnimationScale(1, 0.0f);
            } catch (RemoteException e) {
            }
        }

        try {
        if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
                System.out.println("INSTRUMENTATION_FAILED: " +
                        cn.flattenToString());
                showUsage();
                return;
            }
        } catch (RemoteException e) {
            throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
        }

        if (watcher != null) {
@@ -356,9 +303,57 @@ public class Am {
        }

        if (oldAnims != null) {
            try {
            wm.setAnimationScales(oldAnims);
            } catch (RemoteException e) {
        }
    }

    private void runProfile() throws Exception {
        String profileFile = null;
        boolean start = false;
        String process = nextArgRequired();
        ParcelFileDescriptor fd = null;

        String cmd = nextArgRequired();
        if ("start".equals(cmd)) {
            start = true;
            profileFile = nextArgRequired();
            try {
                fd = ParcelFileDescriptor.open(
                        new File(profileFile),
                        ParcelFileDescriptor.MODE_CREATE |
                        ParcelFileDescriptor.MODE_TRUNCATE |
                        ParcelFileDescriptor.MODE_READ_WRITE);
            } catch (FileNotFoundException e) {
                System.err.println("Error: Unable to open file: " + profileFile);
                return;
            }
        } else if (!"stop".equals(cmd)) {
            throw new IllegalArgumentException("Profile command " + cmd + " not valid");
        }

        if (!mAm.profileControl(process, start, profileFile, fd)) {
            throw new AndroidException("PROFILE FAILED on process " + process);
        }
    }

    private class IntentReceiver extends IIntentReceiver.Stub {
        private boolean mFinished = false;

        public synchronized void performReceive(
                Intent intent, int rc, String data, Bundle ext, boolean ord) {
            String line = "Broadcast completed: result=" + rc;
            if (data != null) line = line + ", data=\"" + data + "\"";
            if (ext != null) line = line + ", extras: " + ext;
            System.out.println(line);
            mFinished = true;
            notifyAll();
        }

        public synchronized void waitForFinish() {
            try {
                while (!mFinished) wait();
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
        }
    }
@@ -431,6 +426,7 @@ public class Am {
                        }
                        wait(1000);
                    } catch (InterruptedException e) {
                        throw new IllegalStateException(e);
                    }
                }
            }
@@ -438,62 +434,11 @@ public class Am {
        }
    }

    private void runProfile() {
        String profileFile = null;
        boolean start = false;

        String process = nextArg();
        if (process == null) {
            System.err.println("Error: No profile process supplied");
            showUsage();
            return;
        }
        
        ParcelFileDescriptor fd = null;
        
        String cmd = nextArg();
        if ("start".equals(cmd)) {
            start = true;
            profileFile = nextArg();
            if (profileFile == null) {
                System.err.println("Error: No profile file path supplied");
                showUsage();
                return;
            }
            try {
                fd = ParcelFileDescriptor.open(
                        new File(profileFile),
                        ParcelFileDescriptor.MODE_CREATE |
                        ParcelFileDescriptor.MODE_TRUNCATE |
                        ParcelFileDescriptor.MODE_READ_WRITE);
            } catch (FileNotFoundException e) {
                System.err.println("Error: Unable to open file: " + profileFile);
                return;
            }
        } else if (!"stop".equals(cmd)) {
            System.err.println("Error: Profile command " + cmd + " not valid");
            showUsage();
            return;
        }
        
        try {
            if (!mAm.profileControl(process, start, profileFile, fd)) {
                System.err.println("PROFILE FAILED on process " + process);
                return;
            }
        } catch (IllegalArgumentException e) {
            System.out.println("PROFILE FAILED: " + e.getMessage());
            return;
        } catch (IllegalStateException e) {
            System.out.println("PROFILE FAILED: " + e.getMessage());
            return;
        } catch (RemoteException e) {
            System.out.println("PROFILE FAILED: activity manager gone");
            return;
        }
    }

    private String nextOption() {
        if (mCurArgData != null) {
            String prev = mArgs[mNextArg - 1];
            throw new IllegalArgumentException("No argument expected after \"" + prev + "\"");
        }
        if (mNextArg >= mArgs.length) {
            return null;
        }
@@ -518,41 +463,52 @@ public class Am {
        return arg;
    }

    private String nextOptionData() {
    private String nextArg() {
        if (mCurArgData != null) {
            return mCurArgData;
        }
        if (mNextArg >= mArgs.length) {
            String arg = mCurArgData;
            mCurArgData = null;
            return arg;
        } else if (mNextArg < mArgs.length) {
            return mArgs[mNextArg++];
        } else {
            return null;
        }
        String data = mArgs[mNextArg];
        mNextArg++;
        return data;
    }

    private String nextArg() {
        if (mNextArg >= mArgs.length) {
            return null;
    private String nextArgRequired() {
        String arg = nextArg();
        if (arg == null) {
            String prev = mArgs[mNextArg - 1];
            throw new IllegalArgumentException("Argument expected after \"" + prev + "\"");
        }
        String arg = mArgs[mNextArg];
        mNextArg++;
        return arg;
    }

    private void showUsage() {
        System.err.println("usage: am [start|broadcast|instrument|profile]");
        System.err.println("       am start [-D] INTENT");
        System.err.println("       am broadcast INTENT");
        System.err.println("       am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]");
        System.err.println("                [-w] <COMPONENT> ");
        System.err.println("       am profile <PROCESS> [start <PROF_FILE>|stop]");
        System.err.println("");
        System.err.println("       INTENT is described with:");
        System.err.println("                [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]");
        System.err.println("                [-c <CATEGORY> [-c <CATEGORY>] ...]");
        System.err.println("                [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]");
        System.err.println("                [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]");
        System.err.println("                [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]");
        System.err.println("                [-n <COMPONENT>] [-f <FLAGS>] [<URI>]");
    private static void showUsage() {
        System.err.println(
                "usage: am [subcommand] [options]\n" +
                "\n" +
                "    start an Activity: am start [-D] <INTENT>\n" +
                "        -D: enable debugging\n" +
                "\n" +
                "    send a broadcast Intent: am broadcast <INTENT>\n" +
                "\n" +
                "    start an Instrumentation: am instrument [flags] <COMPONENT>\n" +
                "        -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)\n" +
                "        -e <NAME> <VALUE>: set argument <NAME> to <VALUE>\n" +
                "        -p <FILE>: write profiling data to <FILE>\n" +
                "        -w: wait for instrumentation to finish before returning\n" +
                "\n" +
                "    start profiling: am profile <PROCESS> start <FILE>\n" +
                "    stop profiling: am profile <PROCESS> stop\n" +
                "\n" +
                "    <INTENT> specifications include these flags:\n" +
                "        [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
                "        [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
                "        [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" +
                "        [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
                "        [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
                "        [-n <COMPONENT>] [-f <FLAGS>] [<URI>]\n"
                );
    }
}
+2 −4
Original line number Diff line number Diff line
@@ -58,8 +58,8 @@ import java.net.URISyntaxException;
 * and otherwise tweak HTTP requests.
 */
public class GoogleHttpClient implements HttpClient {

    private static final String TAG = "GoogleHttpClient";
    private static final boolean LOCAL_LOGV = Config.LOGV || false;

    /** Exception thrown when a request is blocked by the URL rules. */
    public static class BlockedRequestException extends IOException {
@@ -289,9 +289,7 @@ public class GoogleHttpClient implements HttpClient {
        wrapper.setURI(uri);
        request = wrapper;

        if (Config.LOGV) {
            Log.v(TAG, "Rule " + rule.mName + ": " + original + " -> " + rewritten);
        }
        if (LOCAL_LOGV) Log.v(TAG, "Rule " + rule.mName + ": " + original + " -> " + rewritten);
        return executeWithoutRewriting(request, context);
    }