Merge "profiling: Add matcher."
diff --git a/src/perfetto_cmd/config.cc b/src/perfetto_cmd/config.cc
index 106d3ff..d786818 100644
--- a/src/perfetto_cmd/config.cc
+++ b/src/perfetto_cmd/config.cc
@@ -86,16 +86,22 @@
 bool CreateConfigFromOptions(const ConfigOptions& options,
                              TraceConfig* config) {
   uint64_t duration_ms = 0;
-  if (!ConvertTimeToMs(options.time, &duration_ms))
+  if (!ConvertTimeToMs(options.time, &duration_ms)) {
+    PERFETTO_ELOG("--time argument is invalid");
     return false;
+  }
 
   uint64_t buffer_size_kb = 0;
-  if (!ConvertSizeToKb(options.buffer_size, &buffer_size_kb))
+  if (!ConvertSizeToKb(options.buffer_size, &buffer_size_kb)) {
+    PERFETTO_ELOG("--buffer argument is invalid");
     return false;
+  }
 
   uint64_t max_file_size_kb = 0;
-  if (!ConvertSizeToKb(options.max_file_size, &max_file_size_kb))
+  if (!ConvertSizeToKb(options.max_file_size, &max_file_size_kb)) {
+    PERFETTO_ELOG("--size argument is invalid");
     return false;
+  }
 
   std::vector<std::string> ftrace_events;
   std::vector<std::string> atrace_categories;
@@ -110,7 +116,7 @@
   }
 
   config->set_duration_ms(static_cast<unsigned int>(duration_ms));
-  config->set_max_file_size_bytes(static_cast<unsigned int>(max_file_size_kb));
+  config->set_max_file_size_bytes(max_file_size_kb * 1024);
   if (max_file_size_kb)
     config->set_write_into_file(true);
   config->add_buffers()->set_size_kb(static_cast<unsigned int>(buffer_size_kb));
diff --git a/src/perfetto_cmd/config.h b/src/perfetto_cmd/config.h
index 6d4b48c..65bad22 100644
--- a/src/perfetto_cmd/config.h
+++ b/src/perfetto_cmd/config.h
@@ -29,7 +29,7 @@
 // options in a proto is the job of CreateConfigFromOptions.
 
 struct ConfigOptions {
-  std::string time;
+  std::string time = "10s";
   std::string max_file_size;
   std::string buffer_size = "32mb";
   std::vector<std::string> atrace_apps;
diff --git a/src/perfetto_cmd/config_unittest.cc b/src/perfetto_cmd/config_unittest.cc
index 527e9da..3b90cc8 100644
--- a/src/perfetto_cmd/config_unittest.cc
+++ b/src/perfetto_cmd/config_unittest.cc
@@ -105,6 +105,16 @@
   ASSERT_TRUE(CreateConfigFromOptions(options, &config));
 }
 
+TEST_F(CreateConfigFromOptionsTest, InvalidTime) {
+  options.time = "2mb";
+  ASSERT_FALSE(CreateConfigFromOptions(options, &config));
+}
+
+TEST_F(CreateConfigFromOptionsTest, InvalidSize) {
+  options.max_file_size = "2s";
+  ASSERT_FALSE(CreateConfigFromOptions(options, &config));
+}
+
 TEST_F(CreateConfigFromOptionsTest, FullConfig) {
   options.buffer_size = "100mb";
   options.max_file_size = "1gb";
@@ -114,7 +124,7 @@
   options.atrace_apps.push_back("com.android.chrome");
   ASSERT_TRUE(CreateConfigFromOptions(options, &config));
   EXPECT_EQ(config.duration_ms(), 60 * 60 * 1000);
-  EXPECT_EQ(config.max_file_size_bytes(), 1 * 1024 * 1024);
+  EXPECT_EQ(config.max_file_size_bytes(), 1 * 1024 * 1024 * 1024);
   EXPECT_EQ(config.buffers().Get(0).size_kb(), 100 * 1024);
   EXPECT_EQ(config.data_sources().Get(0).config().name(), "linux.ftrace");
   EXPECT_EQ(config.data_sources().Get(0).config().target_buffer(), 0);
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 48a3740..d0b59a9 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -146,7 +146,7 @@
 light configuration flags: (only when NOT using -c/--config)
   --time           -t      : Trace duration N[s,m,h] (default: 10s)
   --buffer         -b      : Ring buffer size N[mb,gb] (default: 32mb)
-  --size           -s      : Maximum trace size N[mb,gb] (default: 100mb)
+  --size           -s      : Max file size N[mb,gb] (default: in-memory ring-buffer only)
   ATRACE_CAT               : Record ATRACE_CAT (e.g. wm)
   FTRACE_GROUP/FTRACE_NAME : Record ftrace event (e.g. sched/sched_switch)
   FTRACE_GROUP/*           : Record all events in group (e.g. sched/*)
@@ -353,11 +353,11 @@
     } else {
       parsed = trace_config_proto.ParseFromString(trace_config_raw);
     }
+  }
 
-    if (!parsed) {
-      PERFETTO_ELOG("Could not parse TraceConfig proto");
-      return 1;
-    }
+  if (!parsed) {
+    PERFETTO_ELOG("The trace config is invalid, bailing out.");
+    return 1;
   }
 
   *trace_config_proto.mutable_statsd_metadata() = std::move(statsd_metadata);
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index 51b4579..f4810db 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -347,6 +347,13 @@
     }
     if (sql_query.back() == '\n')
       sql_query.resize(sql_query.size() - 1);
+
+    // If we have a new line at the end of the file or an extra new line
+    // somewhere in the file, we'll end up with an empty query which we should
+    // just ignore.
+    if (sql_query.empty())
+      continue;
+
     PERFETTO_ILOG("Executing query: %s", sql_query.c_str());
 
     protos::RawQueryArgs query;
diff --git a/tools/heap_profile b/tools/heap_profile
index ef49ffe..d37f325 100755
--- a/tools/heap_profile
+++ b/tools/heap_profile
@@ -91,7 +91,7 @@
 '''
 
 PERFETTO_CMD=('CFG=\'{}\'; echo ${{CFG}} | '
-              'perfetto -t -c - -o /data/misc/perfetto-traces/profile -b')
+              'perfetto --txt -c - -o /data/misc/perfetto-traces/profile -d')
 IS_INTERRUPTED = False
 def sigint_handler(sig, frame):
   global IS_INTERRUPTED
diff --git a/tools/tmux b/tools/tmux
index e3d7a82..18e387f 100755
--- a/tools/tmux
+++ b/tools/tmux
@@ -120,9 +120,6 @@
 if ! is_monolithic $OUT; then
   PREFIX="$PREFIX LD_LIBRARY_PATH=$DIR"
   push $OUT/libperfetto.so
-  if is_android $OUT; then
-    push $OUT/libperfetto_android_internal.so
-  fi
 fi
 
 CONFIG_DEVICE_PATH=$CONFIG
diff --git a/ui/src/common/protos.ts b/ui/src/common/protos.ts
index 3db7694..3ada5fd 100644
--- a/ui/src/common/protos.ts
+++ b/ui/src/common/protos.ts
@@ -16,10 +16,13 @@
 
 // Aliases protos to avoid the super nested namespaces.
 // See https://www.typescriptlang.org/docs/handbook/namespaces.html#aliases
+import IAndroidPowerConfig = protos.perfetto.protos.IAndroidPowerConfig;
 import IProcessStatsConfig = protos.perfetto.protos.IProcessStatsConfig;
 import IRawQueryArgs = protos.perfetto.protos.IRawQueryArgs;
 import ISysStatsConfig = protos.perfetto.protos.ISysStatsConfig;
 import ITraceConfig = protos.perfetto.protos.ITraceConfig;
+import BatteryCounters =
+    protos.perfetto.protos.AndroidPowerConfig.BatteryCounters;
 import MeminfoCounters = protos.perfetto.protos.MeminfoCounters;
 import RawQueryArgs = protos.perfetto.protos.RawQueryArgs;
 import RawQueryResult = protos.perfetto.protos.RawQueryResult;
@@ -84,10 +87,12 @@
 }
 
 export {
+  IAndroidPowerConfig,
   IProcessStatsConfig,
   IRawQueryArgs,
   ISysStatsConfig,
   ITraceConfig,
+  BatteryCounters,
   MeminfoCounters,
   RawQueryArgs,
   RawQueryResult,
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 564104e..36d6b3b 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -95,6 +95,11 @@
   vmstatCounters: string[];
   statPeriodMs: number|null;
   statCounters: string[];
+
+  // Battery and power
+  power: boolean;
+  batteryPeriodMs: number|null;
+  batteryCounters: string[];
 }
 
 export interface TraceTime {
@@ -185,5 +190,9 @@
     vmstatCounters: [],
     statPeriodMs: null,
     statCounters: [],
+
+    power: false,
+    batteryPeriodMs: 1000,
+    batteryCounters: [],
   };
 }
diff --git a/ui/src/controller/record_controller.ts b/ui/src/controller/record_controller.ts
index 8901585..6d0ae99 100644
--- a/ui/src/controller/record_controller.ts
+++ b/ui/src/controller/record_controller.ts
@@ -14,6 +14,8 @@
 
 import {TraceConfig} from '../common/protos';
 import {
+  BatteryCounters,
+  IAndroidPowerConfig,
   IProcessStatsConfig,
   ISysStatsConfig,
   ITraceConfig,
@@ -106,6 +108,22 @@
     });
   }
 
+  if (config.power) {
+    const androidPowerConfig: IAndroidPowerConfig = {};
+    androidPowerConfig.batteryPollMs = config.batteryPeriodMs;
+    androidPowerConfig.batteryCounters = config.batteryCounters.map(name => {
+      // tslint:disable-next-line no-any
+      return BatteryCounters[name as any as number] as any as number;
+    });
+
+    dataSources.push({
+      config: {
+        name: 'android.power',
+        androidPowerConfig,
+      },
+    });
+  }
+
   const proto: ITraceConfig = {
     durationMs,
     buffers: [
@@ -137,7 +155,7 @@
   // fields are enums.
   function looksLikeEnum(value: string): boolean {
     return value.startsWith('MEMINFO_') || value.startsWith('VMSTAT_') ||
-        value.startsWith('STAT_');
+        value.startsWith('STAT_') || value.startsWith('BATTERY_COUNTER_');
   }
   function* message(msg: {}, indent: number): IterableIterator<string> {
     for (const [key, value] of Object.entries(msg)) {
diff --git a/ui/src/frontend/record_page.ts b/ui/src/frontend/record_page.ts
index fe60595..6abc4bc 100644
--- a/ui/src/frontend/record_page.ts
+++ b/ui/src/frontend/record_page.ts
@@ -382,6 +382,10 @@
       vmstatCounters: [],
       statPeriodMs: null,
       statCounters: [],
+
+      power: true,
+      batteryPeriodMs: 1000,
+      batteryCounters: ['BATTERY_COUNTER_CHARGE', 'BATTERY_COUNTER_CURRENT'],
     },
   },
   {
@@ -421,6 +425,10 @@
       vmstatCounters: [],
       statPeriodMs: null,
       statCounters: [],
+
+      power: false,
+      batteryPeriodMs: null,
+      batteryCounters: [],
     },
   },
   {
@@ -449,6 +457,10 @@
       vmstatCounters: [],
       statPeriodMs: null,
       statCounters: [],
+
+      power: false,
+      batteryPeriodMs: null,
+      batteryCounters: [],
     },
   },
 ];
@@ -465,11 +477,21 @@
 ];
 ATRACE_CATERGORIES.sort();
 
+
+const BATTERY_COUNTERS = [
+  'BATTERY_COUNTER_CHARGE',
+  'BATTERY_COUNTER_CAPACITY_PERCENT',
+  'BATTERY_COUNTER_CURRENT',
+  'BATTERY_COUNTER_CURRENT_AVG'
+];
+BATTERY_COUNTERS.sort();
+
 const DURATION_HELP = `Duration to trace for`;
 const BUFFER_SIZE_HELP = `Size of the ring buffer which stores the trace`;
 const PROCESS_METADATA_HELP =
     `Record process names and parent child relationships`;
 const FTRACE_AND_ATRACE_HELP = `Record ftrace & atrace events`;
+const POWER_HELP = `Poll battery counters from the Power Management Unit`;
 const SYS_STATS_HELP = ``;
 
 function toId(label: string): string {
@@ -929,6 +951,39 @@
 
             ),
 
+            m('.heading', m(Toggle, {
+              label: 'Battery and power',
+              help: POWER_HELP,
+              value: config.power,
+              enabled: true,
+              onchange: onChange<boolean|null>('power'),
+            })),
+
+            m('.control-group',
+              m(Numeric, {
+                enabled: config.power,
+                label: 'Polling rate',
+                sublabel: 'ms',
+                help: '',
+                placeholder: 'never',
+                value: config.batteryPeriodMs,
+                onchange: onChange<number|null>('batteryPeriodMs'),
+                presets: [
+                  {label: '1000ms', value: 1000},
+                  {label: '5000ms', value: 5000},
+                  {label: '10000ms', value: 10000},
+                ]
+              }),
+              m(MultiSelect, {
+                label: 'Battery counters',
+                enabled: config.power && isTruthy(config.batteryPeriodMs),
+                selected: config.batteryCounters,
+                options: BATTERY_COUNTERS,
+                onadd: onAdd('batteryCounters'),
+                onsubtract: onSubtract('batteryCounters'),
+              }),
+            ),
+
           m('hr'),
 
           m(Toggle, {