Merge "Add support of ignition state to Car API"
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index 7e3dea4..2f834ce 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -229,8 +229,8 @@
         }
 
         if (config == null) {
-            throw new IllegalArgumentException("subscribe error: config is null for property " +
-                    property);
+            throw new IllegalArgumentException("subscribe error: config is null for property 0x" +
+                    toHexString(property));
         } else if (isPropertySubscribable(config)) {
             synchronized (this) {
                 assertServiceOwnerLocked(service, property);
@@ -415,7 +415,6 @@
                     .append("Property:0x").append(toHexString(config.prop))
                     .append(",access:0x").append(toHexString(config.access))
                     .append(",changeMode:0x").append(toHexString(config.changeMode))
-                    .append(",permission:0x").append(toHexString(config.permissionModel))
                     .append(",areas:0x").append(toHexString(config.supportedAreas))
                     .append(",config:0x").append(Arrays.toString(config.configArray.toArray()))
                     .append(",fs min:").append(config.minSampleRate)
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/radio/RadioTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/radio/RadioTestFragment.java
index 89efdf5..baba61b 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/radio/RadioTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/radio/RadioTestFragment.java
@@ -401,6 +401,8 @@
         mRadioNext.setEnabled(mRadioTuner != null);
         mRadioPrev.setEnabled(mRadioTuner != null);
         mRadioBand.setEnabled(mRadioTuner != null);
+        mRadioScanCancel.setEnabled(mRadioTuner != null);
+        mRadioGetProgramInfo.setEnabled(mRadioTuner != null);
     }
 
     private void updateMessages() {
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
index 7c757ee..ca5c76a 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/sensor/SensorsTestFragment.java
@@ -272,6 +272,7 @@
                         break;
                     case CarSensorManager.SENSOR_TYPE_GYROSCOPE:
                         summary.add(getGyroscopeString(event));
+                        break;
                     default:
                         // Should never happen.
                         Log.w(TAG, "Unrecognized event type: " + i);
diff --git a/tests/carservice_test/src/com/android/car/test/AudioRoutingPolicyTest.java b/tests/carservice_test/src/com/android/car/test/AudioRoutingPolicyTest.java
index fa8c149..b4c17d3 100644
--- a/tests/carservice_test/src/com/android/car/test/AudioRoutingPolicyTest.java
+++ b/tests/carservice_test/src/com/android/car/test/AudioRoutingPolicyTest.java
@@ -17,7 +17,6 @@
 
 import android.hardware.vehicle.V2_0.VehicleAudioContextFlag;
 import android.hardware.vehicle.V2_0.VehicleAudioRoutingPolicyIndex;
-import android.hardware.vehicle.V2_0.VehiclePermissionModel;
 import android.hardware.vehicle.V2_0.VehiclePropValue;
 import android.hardware.vehicle.V2_0.VehicleProperty;
 import android.hardware.vehicle.V2_0.VehiclePropertyAccess;
@@ -60,8 +59,7 @@
     @Override
     protected synchronized void configureMockedHal() {
         addProperty(VehicleProperty.AUDIO_ROUTING_POLICY, mAudioRoutingPolicyHandler)
-                .setAccess(VehiclePropertyAccess.WRITE)
-                .setPermissionModel(VehiclePermissionModel.SYSTEM_APP_ONLY);
+                .setAccess(VehiclePropertyAccess.WRITE);
     }
 
     public void testNoHwVariant() throws Exception {
diff --git a/tools/bootanalyze/bootanalyze.py b/tools/bootanalyze/bootanalyze.py
index a4df623..55cf7ef 100755
--- a/tools/bootanalyze/bootanalyze.py
+++ b/tools/bootanalyze/bootanalyze.py
@@ -44,6 +44,7 @@
 DEBUG = False
 ADB_CMD = "adb"
 TIMING_THRESHOLD = 5.0
+BOOT_PROP = "\[ro\.boottime\.([^\]]+)\]:\s+\[(\d+)\]"
 
 def main():
   global ADB_CMD
@@ -73,18 +74,20 @@
 
   data_points = {}
   timing_points = collections.OrderedDict()
+  boottime_points = collections.OrderedDict()
   for it in range(0, args.iterate):
     if args.iterate > 1:
       print "Run: {0}".format(it + 1)
     attempt = 1
     processing_data = None
     timings = None
+    boottime_events = None
     while attempt <= MAX_RETRIES and processing_data is None:
       attempt += 1
-      processing_data, timings = iterate(
+      processing_data, timings, boottime_events = iterate(
         args, search_events, timing_events, cfg, error_time)
 
-    if processing_data is None:
+    if not processing_data or not boottime_events:
       # Processing error
       print "Failed to collect valid samples for run {0}".format(it + 1)
       continue
@@ -99,7 +102,20 @@
           timing_points[k] = []
         timing_points[k].append(v)
 
+    for k, v in boottime_events.iteritems():
+      if not k in boottime_points:
+        boottime_points[k] = []
+      boottime_points[k].append(v)
+
   if args.iterate > 1:
+    print "-----------------"
+    print "ro.boottime.* after {0} runs".format(args.iterate)
+    print '{0:30}: {1:<7} {2:<7}'.format("Event", "Mean", "stddev")
+    for item in boottime_points.items():
+        print '{0:30}: {1:<7.5} {2:<7.5} {3}'.format(
+          item[0], sum(item[1])/len(item[1]), stddev(item[1]),\
+          "*time taken" if item[0].startswith("init.") else "")
+
     if timing_points and args.timings:
       print "-----------------"
       print "Timing in order, Avg time values after {0} runs".format(args.iterate)
@@ -147,6 +163,7 @@
     logcat_events, TIME_LOGCAT, str);
   dmesg_event_time = extract_time(
     dmesg_events, TIME_DMESG, float);
+  boottime_events = fetch_boottime_property()
   events = {}
   diff_time = 0
   max_time = 0
@@ -174,7 +191,7 @@
 
   if not logcat_event_time.get(KERNEL_TIME_KEY):
     print "kernel time not captured in logcat, cannot get time diff"
-    return None, None
+    return None, None, None
   diffs = []
   diffs.append((logcat_event_time[KERNEL_TIME_KEY], logcat_event_time[KERNEL_TIME_KEY]))
   if logcat_event_time.get(BOOT_ANIM_END_TIME_KEY) and dmesg_event_time.get(BOOT_ANIM_END_TIME_KEY):
@@ -184,7 +201,7 @@
   if not dmesg_event_time.get(KERNEL_BOOT_COMPLETE):
       print "BootAnimEnd time or BootComplete-kernel not captured in both log" +\
         ", cannot get time diff"
-      return None, None
+      return None, None, None
   diffs.append((logcat_event_time[KERNEL_BOOT_COMPLETE],\
                 logcat_event_time[KERNEL_BOOT_COMPLETE] - dmesg_event_time[KERNEL_BOOT_COMPLETE]))
 
@@ -252,6 +269,13 @@
       logcat_original_time[item[0]])
 
   print '\n* - event time was obtained from dmesg log\n'
+
+  print "-----------------"
+  print "ro.boottime.*: time"
+  for item in boottime_events.items():
+    print '{0:30}: {1:<7.5} {2}'.format(item[0], item[1],\
+      "*time taken" if item[0].startswith("init.") else "")
+
   if events[LOGCAT_BOOT_COMPLETE] > error_time:
     now = datetime.now()
     bugreport_file = "bugreport-bootuptoolong-%s_%s.zip" % (str(events[LOGCAT_BOOT_COMPLETE]),\
@@ -259,9 +283,9 @@
     print "Boot up time too big, treated as error, will capture bugreport %s and reject data"\
        % (bugreport_file)
     os.system(ADB_CMD + " bugreport " + bugreport_file)
-    return None, None
+    return None, None, None
 
-  return data_points, timing_points
+  return data_points, timing_points, boottime_events
 
 def debug(string):
   if DEBUG:
@@ -362,6 +386,23 @@
   process.terminate()
   return events, timing_events
 
+def fetch_boottime_property():
+  cmd = ADB_CMD + ' shell su root getprop'
+  events = {}
+  process = subprocess.Popen(cmd, shell=True,
+                             stdout=subprocess.PIPE);
+  out = process.stdout
+  pattern = re.compile(BOOT_PROP)
+  for line in out:
+    match = pattern.match(line)
+    if match:
+      events[match.group(1)] = float(match.group(2)) / 1000000000.0 #ns to s
+  ordered_event = collections.OrderedDict()
+  for item in sorted(events.items(), key=operator.itemgetter(1)):
+    ordered_event[item[0]] = item[1]
+  return ordered_event
+
+
 def get_boot_event(line, events):
   for event_key, event_pattern in events.iteritems():
     if event_pattern.search(line):
diff --git a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
index c801067..8ff9603 100644
--- a/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
+++ b/vehicle-hal-support-lib/src/com/android/car/vehiclehal/test/VehiclePropConfigBuilder.java
@@ -18,7 +18,6 @@
 
 import android.annotation.CheckResult;
 import android.hardware.vehicle.V2_0.VehicleAreaConfig;
-import android.hardware.vehicle.V2_0.VehiclePermissionModel;
 import android.hardware.vehicle.V2_0.VehiclePropConfig;
 import android.hardware.vehicle.V2_0.VehiclePropertyAccess;
 import android.hardware.vehicle.V2_0.VehiclePropertyChangeMode;
@@ -42,7 +41,6 @@
         mConfig.prop = propId;
         mConfig.access = VehiclePropertyAccess.READ_WRITE;
         mConfig.changeMode = VehiclePropertyChangeMode.ON_CHANGE;
-        mConfig.permissionModel = VehiclePermissionModel.NO_RESTRICTION;
     }
 
     private VehiclePropConfig clone(VehiclePropConfig propConfig) {
@@ -51,7 +49,6 @@
         newConfig.prop = propConfig.prop;
         newConfig.access = propConfig.access;
         newConfig.changeMode = propConfig.changeMode;
-        newConfig.permissionModel = propConfig.permissionModel;
         newConfig.supportedAreas = propConfig.supportedAreas;
         newConfig.configFlags = propConfig.configFlags;
         newConfig.configString = propConfig.configString;
@@ -86,12 +83,6 @@
     }
 
     @CheckResult
-    public VehiclePropConfigBuilder setPermissionModel(int permissionModel) {
-        mConfig.permissionModel = permissionModel;
-        return this;
-    }
-
-    @CheckResult
     public VehiclePropConfigBuilder setSupportedAreas(int supportedAreas) {
         mConfig.supportedAreas = supportedAreas;
         return this;