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

Commit e6c492bf authored by Mike Ma's avatar Mike Ma Committed by Android (Google) Code Review
Browse files

Merge "Record proto to file in am instrument"

parents 5e96c6c0 d2239828
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ message ResultsBundleEntry {
    optional double value_double = 5;
    optional sint64 value_long = 6;
    optional ResultsBundle value_bundle = 7;
    optional bytes value_bytes = 8;
}

message ResultsBundle {
+5 −1
Original line number Diff line number Diff line
@@ -160,7 +160,11 @@ public class Am extends BaseCommand {
            } else if (opt.equals("-r")) {
                instrument.rawMode = true;
            } else if (opt.equals("-m")) {
                instrument.proto = true;
                instrument.protoStd = true;
            } else if (opt.equals("-f")) {
                instrument.protoFile = true;
                if (peekNextArg() != null && !peekNextArg().startsWith("-"))
                    instrument.logPath = nextArg();
            } else if (opt.equals("-e")) {
                final String argKey = nextArgRequired();
                final String argValue = nextArgRequired();
+92 −43
Original line number Diff line number Diff line
@@ -25,23 +25,32 @@ import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.AndroidException;
import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;


/**
 * Runs the am instrument command
 */
public class Instrument {
    public static final String DEFAULT_LOG_DIR = "instrument-logs";

    private final IActivityManager mAm;
    private final IPackageManager mPm;
    private final IWindowManager mWm;
@@ -50,7 +59,9 @@ public class Instrument {
    public String profileFile = null;
    public boolean wait = false;
    public boolean rawMode = false;
    public boolean proto = false;
    boolean protoStd = false;  // write proto to stdout
    boolean protoFile = false;  // write proto to a file
    String logPath = null;
    public boolean noWindowAnimation = false;
    public String abi = null;
    public int userId = UserHandle.USER_CURRENT;
@@ -178,18 +189,49 @@ public class Instrument {
     * Printer for the protobuf based status reporting.
     */
    private class ProtoStatusReporter implements StatusReporter {

        private File mLog;

        ProtoStatusReporter() {
            if (protoFile) {
                if (logPath == null) {
                    File logDir = new File(Environment.getLegacyExternalStorageDirectory(),
                            DEFAULT_LOG_DIR);
                    if (!logDir.exists() && !logDir.mkdirs()) {
                        System.err.format("Unable to create log directory: %s\n",
                                logDir.getAbsolutePath());
                        protoFile = false;
                        return;
                    }
                    SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-hhmmss-SSS", Locale.US);
                    String fileName = String.format("log-%s.instrumentation_data_proto",
                            format.format(new Date()));
                    mLog = new File(logDir, fileName);
                } else {
                    mLog = new File(Environment.getLegacyExternalStorageDirectory(), logPath);
                    File logDir = mLog.getParentFile();
                    if (!logDir.exists() && !logDir.mkdirs()) {
                        System.err.format("Unable to create log directory: %s\n",
                                logDir.getAbsolutePath());
                        protoFile = false;
                        return;
                    }
                }
                if (mLog.exists()) mLog.delete();
            }
        }

        @Override
        public void onInstrumentationStatusLocked(ComponentName name, int resultCode,
                Bundle results) {
            final ProtoOutputStream proto = new ProtoOutputStream();

            final long token = proto.startRepeatedObject(InstrumentationData.Session.TEST_STATUS);

            proto.writeSInt32(InstrumentationData.TestStatus.RESULT_CODE, resultCode);
            final long token = proto.start(InstrumentationData.Session.TEST_STATUS);
            proto.write(InstrumentationData.TestStatus.RESULT_CODE, resultCode);
            writeBundle(proto, InstrumentationData.TestStatus.RESULTS, results);
            proto.end(token);

            proto.endRepeatedObject(token);
            writeProtoToStdout(proto);
            outputProto(proto);
        }

        @Override
@@ -197,82 +239,89 @@ public class Instrument {
                Bundle results) {
            final ProtoOutputStream proto = new ProtoOutputStream();

            final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS);

            proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE,
            final long token = proto.start(InstrumentationData.Session.SESSION_STATUS);
            proto.write(InstrumentationData.SessionStatus.STATUS_CODE,
                    InstrumentationData.SESSION_FINISHED);
            proto.writeSInt32(InstrumentationData.SessionStatus.RESULT_CODE, resultCode);
            proto.write(InstrumentationData.SessionStatus.RESULT_CODE, resultCode);
            writeBundle(proto, InstrumentationData.SessionStatus.RESULTS, results);
            proto.end(token);

            proto.endObject(token);
            writeProtoToStdout(proto);
            outputProto(proto);
        }

        @Override
        public void onError(String errorText, boolean commandError) {
            final ProtoOutputStream proto = new ProtoOutputStream();

            final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS);

            proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE,
            final long token = proto.start(InstrumentationData.Session.SESSION_STATUS);
            proto.write(InstrumentationData.SessionStatus.STATUS_CODE,
                    InstrumentationData.SESSION_ABORTED);
            proto.writeString(InstrumentationData.SessionStatus.ERROR_TEXT, errorText);
            proto.write(InstrumentationData.SessionStatus.ERROR_TEXT, errorText);
            proto.end(token);

            proto.endObject(token);
            writeProtoToStdout(proto);
            outputProto(proto);
        }

        private void writeBundle(ProtoOutputStream proto, long fieldId, Bundle bundle) {
            final long bundleToken = proto.startObject(fieldId);
            final long bundleToken = proto.start(fieldId);

            for (final String key: sorted(bundle.keySet())) {
                final long entryToken = proto.startRepeatedObject(
                        InstrumentationData.ResultsBundle.ENTRIES);

                proto.writeString(InstrumentationData.ResultsBundleEntry.KEY, key);
                proto.write(InstrumentationData.ResultsBundleEntry.KEY, key);

                final Object val = bundle.get(key);
                if (val instanceof String) {
                    proto.writeString(InstrumentationData.ResultsBundleEntry.VALUE_STRING,
                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_STRING,
                            (String)val);
                } else if (val instanceof Byte) {
                    proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT,
                            ((Byte)val).intValue());
                } else if (val instanceof Double) {
                    proto.writeDouble(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE,
                            ((Double)val).doubleValue());
                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE, (double)val);
                } else if (val instanceof Float) {
                    proto.writeFloat(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT,
                            ((Float)val).floatValue());
                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT, (float)val);
                } else if (val instanceof Integer) {
                    proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
                            ((Integer)val).intValue());
                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT, (int)val);
                } else if (val instanceof Long) {
                    proto.writeSInt64(InstrumentationData.ResultsBundleEntry.VALUE_LONG,
                            ((Long)val).longValue());
                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_LONG, (long)val);
                } else if (val instanceof Short) {
                    proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
                            ((Short)val).intValue());
                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT, (short)val);
                } else if (val instanceof Bundle) {
                    writeBundle(proto, InstrumentationData.ResultsBundleEntry.VALUE_BUNDLE,
                            (Bundle)val);
                } else if (val instanceof byte[]) {
                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_BYTES, (byte[])val);
                }

                proto.endRepeatedObject(entryToken);
                proto.end(entryToken);
            }

            proto.endObject(bundleToken);
            proto.end(bundleToken);
        }

        private void writeProtoToStdout(ProtoOutputStream proto) {
        private void outputProto(ProtoOutputStream proto) {
            byte[] out = proto.getBytes();
            if (protoStd) {
                try {
                System.out.write(proto.getBytes());
                    System.out.write(out);
                    System.out.flush();
                } catch (IOException ex) {
                    System.err.println("Error writing finished response: ");
                    ex.printStackTrace(System.err);
                }
            }
            if (protoFile) {
                try (OutputStream os = new FileOutputStream(mLog, true)) {
                    os.write(proto.getBytes());
                    os.flush();
                } catch (IOException ex) {
                    System.err.format("Cannot write to %s:\n", mLog.getAbsolutePath());
                    ex.printStackTrace();
                }
            }
        }
    }


@@ -374,7 +423,7 @@ public class Instrument {

        try {
            // Choose which output we will do.
            if (proto) {
            if (protoFile || protoStd) {
                reporter = new ProtoStatusReporter();
            } else if (wait) {
                reporter = new TextStatusReporter(rawMode);
@@ -396,7 +445,7 @@ public class Instrument {
                mWm.setAnimationScale(2, 0.0f);
            }

            // Figure out which component we are tring to do.
            // Figure out which component we are trying to do.
            final ComponentName cn = parseComponentName(componentNameArg);

            // Choose an ABI if necessary
+8 −0
Original line number Diff line number Diff line
@@ -105,6 +105,14 @@ public abstract class BaseCommand {
        return mArgs.getNextArg();
    }

    /**
     * Peek the next argument on the command line, whatever it is; if there are
     * no arguments left, return null.
     */
    public String peekNextArg() {
        return mArgs.peekNextArg();
    }

    /**
     * Return the next argument on the command line, whatever it is; if there are
     * no arguments left, throws an IllegalArgumentException to report this to the user.
+4 −1
Original line number Diff line number Diff line
@@ -2476,7 +2476,10 @@ final class ActivityManagerShellCommand extends ShellCommand {
            pw.println("      -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a");
            pw.println("          common form is [-e <testrunner_flag> <value>[,<value>...]].");
            pw.println("      -p <FILE>: write profiling data to <FILE>");
            pw.println("      -m: Write output as protobuf (machine readable)");
            pw.println("      -m: Write output as protobuf to stdout (machine readable)");
            pw.println("      -f <Optional PATH/TO/FILE>: Write output as protobuf to a file (machine");
            pw.println("          readable). If path is not specified, default directory and file name will");
            pw.println("          be used: /sdcard/instrument-logs/log-yyyyMMdd-hhmmss-SSS.instrumentation_data_proto");
            pw.println("      -w: wait for instrumentation to finish before returning.  Required for");
            pw.println("          test runners.");
            pw.println("      --user <USER_ID> | current: Specify user instrumentation runs in;");