Merge "Add missing wrapper for VHAL Wheel enum" into pi-dev
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index fb74730..e18e573 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -498,7 +498,6 @@
     method public int getAreaType();
     method public int getChangeMode();
     method public java.util.List<java.lang.Integer> getConfigArray();
-    method public int getConfigFlags();
     method public java.lang.String getConfigString();
     method public int getFirstAndOnlyAreaId();
     method public float getMaxSampleRate();
@@ -533,7 +532,6 @@
     method public android.car.hardware.CarPropertyConfig.Builder<T> setAccess(int);
     method public android.car.hardware.CarPropertyConfig.Builder<T> setChangeMode(int);
     method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigArray(java.util.ArrayList<java.lang.Integer>);
-    method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigFlags(int);
     method public android.car.hardware.CarPropertyConfig.Builder<T> setConfigString(java.lang.String);
     method public android.car.hardware.CarPropertyConfig.Builder<T> setMaxSampleRate(float);
     method public android.car.hardware.CarPropertyConfig.Builder<T> setMinSampleRate(float);
diff --git a/car-lib/src/android/car/content/pm/CarPackageManager.java b/car-lib/src/android/car/content/pm/CarPackageManager.java
index 0cbef44..b1828db 100644
--- a/car-lib/src/android/car/content/pm/CarPackageManager.java
+++ b/car-lib/src/android/car/content/pm/CarPackageManager.java
@@ -27,6 +27,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -35,6 +36,7 @@
  * Provides car specific API related with package management.
  */
 public final class CarPackageManager implements CarManagerBase {
+    private static final String TAG = "CarPackageManager";
 
     /**
      * Flag for {@link #setAppBlockingPolicy(String, CarAppBlockingPolicy, int)}. When this
@@ -119,7 +121,21 @@
         } catch (IllegalStateException e) {
             CarApiUtil.checkCarNotConnectedExceptionFromCarService(e);
         } catch (RemoteException e) {
-            //ignore as CarApi will handle disconnection anyway.
+            // Ignore as CarApi will handle disconnection anyway.
+        }
+    }
+
+    /**
+     * Restarts the requested task. If task with {@code taskId} does not exist, do nothing.
+     *
+     * @hide
+     */
+    public void restartTask(int taskId) {
+        try {
+            mService.restartTask(taskId);
+        } catch (RemoteException e) {
+            // Ignore as CarApi will handle disconnection anyway.
+            Log.e(TAG, "Could not restart task " + taskId, e);
         }
     }
 
diff --git a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
index 77d89ee..7210f90 100644
--- a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
+++ b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
@@ -26,4 +26,5 @@
     boolean isServiceDistractionOptimized(in String packageName, in String className) = 2;
     boolean isActivityBackedBySafeActivity(in ComponentName activityName) = 3;
     void setEnableActivityBlocking(boolean enable) = 4;
+    void restartTask(int taskId) = 5;
 }
diff --git a/car-lib/src/android/car/hardware/CarPropertyConfig.java b/car-lib/src/android/car/hardware/CarPropertyConfig.java
index e0890c8..965253a 100644
--- a/car-lib/src/android/car/hardware/CarPropertyConfig.java
+++ b/car-lib/src/android/car/hardware/CarPropertyConfig.java
@@ -45,7 +45,6 @@
     private final int mAreaType;
     private final int mChangeMode;
     private final ArrayList<Integer> mConfigArray;
-    private final int mConfigFlags;
     private final String mConfigString;
     private final float mMaxSampleRate;
     private final float mMinSampleRate;
@@ -54,14 +53,13 @@
     private final Class<T> mType;
 
     private CarPropertyConfig(int access, int areaType, int changeMode,
-            ArrayList<Integer> configArray, int configFlags, String configString,
+            ArrayList<Integer> configArray, String configString,
             float maxSampleRate, float minSampleRate, int propertyId,
             SparseArray<AreaConfig<T>> supportedAreas, Class<T> type) {
         mAccess = access;
         mAreaType = areaType;
         mChangeMode = changeMode;
         mConfigArray = configArray;
-        mConfigFlags = configFlags;
         mConfigString = configString;
         mMaxSampleRate = maxSampleRate;
         mMinSampleRate = minSampleRate;
@@ -82,9 +80,6 @@
     public List<Integer> getConfigArray() {
         return Collections.unmodifiableList(mConfigArray);
     }
-    public int getConfigFlags() {
-        return mConfigFlags;
-    }
     public String getConfigString() {
         return mConfigString;
     }
@@ -172,7 +167,6 @@
         for (int i = 0; i < mConfigArray.size(); i++) {
             dest.writeInt(mConfigArray.get(i));
         }
-        dest.writeInt(mConfigFlags);
         dest.writeString(mConfigString);
         dest.writeFloat(mMaxSampleRate);
         dest.writeFloat(mMinSampleRate);
@@ -195,7 +189,6 @@
         for (int i = 0; i < configArraySize; i++) {
             mConfigArray.add(in.readInt());
         }
-        mConfigFlags = in.readInt();
         mConfigString = in.readString();
         mMaxSampleRate = in.readFloat();
         mMinSampleRate = in.readFloat();
@@ -235,7 +228,6 @@
                 + ", mAreaType=" + mAreaType
                 + ", mChangeMode=" + mChangeMode
                 + ", mConfigArray=" + mConfigArray
-                + ", mConfigFlags=" + mConfigFlags
                 + ", mConfigString=" + mConfigString
                 + ", mMaxSampleRate=" + mMaxSampleRate
                 + ", mMinSampleRate=" + mMinSampleRate
@@ -324,7 +316,6 @@
         private final int mAreaType;
         private int mChangeMode;
         private final ArrayList<Integer> mConfigArray;
-        private int mConfigFlags;
         private String mConfigString;
         private float mMaxSampleRate;
         private float mMinSampleRate;
@@ -411,16 +402,6 @@
         }
 
         /**
-         * Set configFlags parameter to CarPropertyConfig
-         *
-         * @return Builder<T>
-         */
-        public Builder<T> setConfigFlags(int configFlags) {
-            mConfigFlags = configFlags;
-            return this;
-        }
-
-        /**
          * Set configString parameter to CarPropertyConfig
          *
          * @return Builder<T>
@@ -452,8 +433,8 @@
 
         public CarPropertyConfig<T> build() {
             return new CarPropertyConfig<>(mAccess, mAreaType, mChangeMode, mConfigArray,
-                                           mConfigFlags, mConfigString, mMaxSampleRate,
-                                           mMinSampleRate, mPropertyId, mSupportedAreas, mType);
+                                           mConfigString, mMaxSampleRate, mMinSampleRate,
+                                           mPropertyId, mSupportedAreas, mType);
         }
     }
 }
diff --git a/evs/manager/service.cpp b/evs/manager/service.cpp
index f9e45eb..20504a0 100644
--- a/evs/manager/service.cpp
+++ b/evs/manager/service.cpp
@@ -38,6 +38,28 @@
 using namespace android;
 
 
+static void startService(const char *hardwareServiceName, const char * managerServiceName) {
+    ALOGI("EVS managed service connecting to hardware service at %s", hardwareServiceName);
+    android::sp<Enumerator> service = new Enumerator();
+    if (!service->init(hardwareServiceName)) {
+        ALOGE("Failed to connect to hardware service - quitting from registrationThread");
+        exit(1);
+    }
+
+    // Register our service -- if somebody is already registered by our name,
+    // they will be killed (their thread pool will throw an exception).
+    ALOGI("EVS managed service is starting as %s", managerServiceName);
+    status_t status = service->registerAsService(managerServiceName);
+    if (status != OK) {
+        ALOGE("Could not register service %s (%d) - quitting from registrationThread",
+              managerServiceName, status);
+        exit(2);
+    }
+
+    ALOGD("Registration complete");
+}
+
+
 int main(int argc, char** argv) {
     ALOGI("EVS manager starting\n");
 
@@ -72,26 +94,14 @@
     // threads beyond the main thread which will "join" the pool below.
     configureRpcThreadpool(1, true /* callerWillJoin */);
 
-    ALOGI("EVS managed service connecting to hardware service at %s", evsHardwareServiceName);
-    android::sp<Enumerator> service = new Enumerator();
-    if (!service->init(evsHardwareServiceName)) {
-        ALOGE("Failed to initialize");
-        return 1;
-    }
+    // The connection to the underlying hardware service must happen on a dedicated thread to ensure
+    // that the hwbinder response can be processed by the thread pool without blocking.
+    std::thread registrationThread(startService, evsHardwareServiceName, kManagedEnumeratorName);
 
-    // Register our service -- if somebody is already registered by our name,
-    // they will be killed (their thread pool will throw an exception).
-    ALOGI("EVS managed service is starting as %s", kManagedEnumeratorName);
-    status_t status = service->registerAsService(kManagedEnumeratorName);
-    if (status == OK) {
-        ALOGD("Registration complete");
-
-        // Send this main thread to become a permanent part of the thread pool.
-        // This is not expected to return.
-        joinRpcThreadpool();
-    } else {
-        ALOGE("Could not register service %s (%d).", kManagedEnumeratorName, status);
-    }
+    // Send this main thread to become a permanent part of the thread pool.
+    // This is not expected to return.
+    ALOGD("Main thread entering thread pool");
+    joinRpcThreadpool();
 
     // In normal operation, we don't expect the thread pool to exit
     ALOGE("EVS Hardware Enumerator is shutting down");
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index d58c01a..5477f1e 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -253,7 +253,8 @@
         <activity android:name="com.android.car.pm.ActivityBlockingActivity"
                   android:excludeFromRecents="true"
                   android:theme="@android:style/Theme.Translucent.NoTitleBar"
-                  android:exported="false">
+                  android:exported="false"
+                  android:launchMode="singleTask">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
             </intent-filter>
diff --git a/service/res/drawable/exit_button_background.xml b/service/res/drawable/exit_button_background.xml
new file mode 100644
index 0000000..7daa69b
--- /dev/null
+++ b/service/res/drawable/exit_button_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/exit_button_background"/>
+    <corners
+        android:radius="@dimen/exit_button_radius"/>
+</shape>
\ No newline at end of file
diff --git a/service/res/layout/activity_blocking.xml b/service/res/layout/activity_blocking.xml
index 6a41c7f..9cd854a 100644
--- a/service/res/layout/activity_blocking.xml
+++ b/service/res/layout/activity_blocking.xml
@@ -13,16 +13,30 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
-    android:background="@color/activity_blocking_activity_background">
+    android:background="@color/activity_blocking_activity_background"
+    android:padding="@dimen/blocking_activity_padding"
+    android:gravity="center">
     <TextView
         android:id="@+id/activity_blocked_title"
-        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
+        android:layout_width="wrap_content"
+        android:textColor="@color/blocking_text"
         android:textAppearance="@style/ActivityBlockingActivityText" />
-</FrameLayout>
+    <Button
+        android:id="@+id/exit"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_marginTop="@dimen/exit_button_top_margin"
+        android:background="@drawable/exit_button_background"
+        android:paddingEnd="@dimen/exit_button_padding"
+        android:paddingStart="@dimen/exit_button_padding"
+        android:textColor="@color/exit_button_text"
+        android:textAllCaps="true"
+        android:textAppearance="@style/ActivityBlockingActivityText"
+        android:text="@string/exit_button"/>
+</LinearLayout>
diff --git a/service/res/values-h1920dp/dimens.xml b/service/res/values-h1920dp/dimens.xml
index 1cd38f3..938fb17 100644
--- a/service/res/values-h1920dp/dimens.xml
+++ b/service/res/values-h1920dp/dimens.xml
@@ -19,4 +19,8 @@
 <resources>
     <!-- Text size in ActivityBlockingActivity. -->
     <dimen name="blocking_text_size">40sp</dimen>
+    <!-- Padding of exit button in ActivityBlockingActivity. -->
+    <dimen name="exit_button_padding">28dp</dimen>
+    <!-- Top margin of exit button in ActivityBlockingActivity. -->
+    <dimen name="exit_button_top_margin">20dp</dimen>
 </resources>
diff --git a/service/res/values-h800dp/dimens.xml b/service/res/values-h800dp/dimens.xml
new file mode 100644
index 0000000..9594554
--- /dev/null
+++ b/service/res/values-h800dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Padding of exit button in ActivityBlockingActivity. -->
+    <dimen name="exit_button_padding">28dp</dimen>
+</resources>
diff --git a/service/res/values-night/colors.xml b/service/res/values-night/colors.xml
index 794759e..d19a164 100644
--- a/service/res/values-night/colors.xml
+++ b/service/res/values-night/colors.xml
@@ -22,5 +22,11 @@
     <color name="activity_blocking_activity_background">#cc000000</color>
 
     <!-- Color of text in blocking activity. -->
-    <color name="activity_blocking_activity_text_color">#fff5f5f5</color>
+    <color name="blocking_text">#fff5f5f5</color>
+
+    <!-- Background color of exit button. -->
+    <color name="exit_button_background">#ff80cbc4</color>
+
+    <!-- Color of exit button text. -->
+    <color name="exit_button_text">#ff212121</color>
 </resources>
diff --git a/service/res/values-w1280dp/dimens.xml b/service/res/values-w1280dp/dimens.xml
new file mode 100644
index 0000000..f5469f2
--- /dev/null
+++ b/service/res/values-w1280dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Padding of ActivityBlockingActivity. -->
+    <dimen name="blocking_activity_padding">148dp</dimen>
+</resources>
diff --git a/service/res/values-w1920dp/dimens.xml b/service/res/values-w1920dp/dimens.xml
new file mode 100644
index 0000000..75d2deb
--- /dev/null
+++ b/service/res/values-w1920dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Padding of ActivityBlockingActivity. -->
+    <dimen name="blocking_activity_padding">192dp</dimen>
+</resources>
diff --git a/service/res/values-w690dp/dimens.xml b/service/res/values-w690dp/dimens.xml
new file mode 100644
index 0000000..0b06ada
--- /dev/null
+++ b/service/res/values-w690dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Padding of ActivityBlockingActivity. -->
+    <dimen name="blocking_activity_padding">112dp</dimen>
+</resources>
diff --git a/service/res/values/colors.xml b/service/res/values/colors.xml
index 9fd06a1..4f61234 100644
--- a/service/res/values/colors.xml
+++ b/service/res/values/colors.xml
@@ -22,5 +22,11 @@
     <color name="activity_blocking_activity_background">#e6eeeeee</color>
 
     <!-- Color of text in blocking activity. -->
-    <color name="activity_blocking_activity_text_color">#ff212121</color>
+    <color name="blocking_text">#ff212121</color>
+
+    <!-- Background color of exit button. -->
+    <color name="exit_button_background">#ff00796b</color>
+
+    <!-- Color of exit button text. -->
+    <color name="exit_button_text">#fffafafa</color>
 </resources>
diff --git a/service/res/values/config.xml b/service/res/values/config.xml
index 4e30d7f..294bd3b 100644
--- a/service/res/values/config.xml
+++ b/service/res/values/config.xml
@@ -52,9 +52,6 @@
     <!--  The com.android.car.VmsPublisherService will bind to this list of clients -->
     <string-array translatable="false" name="vmsPublisherClients">
     </string-array>
-    <!--  System privileged packages in this list can access the VMS subscribers API -->
-    <string-array translatable="false" name="allowedVmsSubscriberClients">
-    </string-array>
     <!--  Permissions that the com.android.car.VmsPublisherService is allowed to grant to publishers -->
     <string-array translatable="false" name="vmsSafePermissions">
         <item>"android.permission.ACCESS_FINE_LOCATION"</item>
diff --git a/service/res/values/dimens.xml b/service/res/values/dimens.xml
index c32770b..1289080 100644
--- a/service/res/values/dimens.xml
+++ b/service/res/values/dimens.xml
@@ -19,4 +19,12 @@
 <resources>
     <!-- Text size in ActivityBlockingActivity. -->
     <dimen name="blocking_text_size">32sp</dimen>
-</resources>
\ No newline at end of file
+    <!-- Padding of ActivityBlockingActivity. -->
+    <dimen name="blocking_activity_padding">20dp</dimen>
+    <!-- Padding of exit button in ActivityBlockingActivity. -->
+    <dimen name="exit_button_padding">16dp</dimen>
+    <!-- Radius of exit button in ActivityBlockingActivity. -->
+    <dimen name="exit_button_radius">4dp</dimen>
+    <!-- Top margin of exit button in ActivityBlockingActivity. -->
+    <dimen name="exit_button_top_margin">16dp</dimen>
+</resources>
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index 8604abc..9423e85 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!--  For permissions -->
     <!-- Permission text: can access your car's information [CHAR LIMIT=NONE] -->
     <string name="car_permission_label">Car information</string>
@@ -101,8 +101,10 @@
     <string name="car_can_bus_failure_desc">CAN bus does not respond. Unplug and plug back headunit
         box and restart the car</string>
 
-    <!--  Blocking activity: Message to show to user when an application is not allowed. [CHAR LIMIT=NONE] -->
-    <string name="activity_blocked_string">%1$s can\'t be used while driving.</string>
+    <!-- Blocking activity: Message to show to user when a feature of current application is not allowed. [CHAR LIMIT=60] -->
+    <string name="activity_blocked_string">This <xliff:g id="app_name" example="Google Maps">%1$s</xliff:g> feature can\'t be used while driving.</string>
+    <!-- Blocking activity: Button text that restarts the current blocked application. [CHAR LIMIT=10] -->
+    <string name="exit_button">OK</string>
 
     <!-- Permission text: apps can control diagnostic data [CHAR LIMIT=NONE] -->
     <string name="car_permission_label_diag_read">Diagnostic Data</string>
diff --git a/service/res/values/styles.xml b/service/res/values/styles.xml
index 213eb2e..7571362 100644
--- a/service/res/values/styles.xml
+++ b/service/res/values/styles.xml
@@ -19,7 +19,6 @@
         <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:textStyle">normal</item>
         <item name="android:textSize">@dimen/blocking_text_size</item>
-        <item name="android:textColor">@color/activity_blocking_activity_text_color</item>
     </style>
 </resources>
 
diff --git a/service/src/com/android/car/CarNightService.java b/service/src/com/android/car/CarNightService.java
index 497f77c..212bb1a 100644
--- a/service/src/com/android/car/CarNightService.java
+++ b/service/src/com/android/car/CarNightService.java
@@ -64,14 +64,20 @@
             return;
         }
         if (event.sensorType == CarSensorManager.SENSOR_TYPE_NIGHT) {
-            if (event.intValues[0] == 1) {
-                mNightSetting = UiModeManager.MODE_NIGHT_YES;
+            if (event.intValues[0] == 0) {
+                mNightSetting = UiModeManager.MODE_NIGHT_NO;
+                if (DBG)  Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent DAY");
             }
             else {
-                mNightSetting = UiModeManager.MODE_NIGHT_NO;
+                mNightSetting = UiModeManager.MODE_NIGHT_YES;
+                if (DBG)  Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent NIGHT");
             }
+
             if (mUiModeManager != null && (mForcedMode == FORCED_SENSOR_MODE)) {
                 mUiModeManager.setNightMode(mNightSetting);
+                if (DBG)  Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent APPLIED");
+            } else {
+                if (DBG)  Log.d(CarLog.TAG_SENSOR,"CAR dayNight handleSensorEvent IGNORED");
             }
         }
     }
@@ -107,7 +113,7 @@
         mCarSensorService = sensorService;
         mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
         if (mUiModeManager == null) {
-            Log.w(CarLog.TAG_SENSOR,"Failed to get UI_MODE_SERVICE");
+            Log.w(CarLog.TAG_SENSOR, "Failed to get UI_MODE_SERVICE");
         }
     }
 
@@ -130,8 +136,8 @@
     @Override
     public synchronized void dump(PrintWriter writer) {
         writer.println("*DAY NIGHT POLICY*");
-        writer.println("Mode:" + ((mNightSetting == UiModeManager.MODE_NIGHT_YES) ? "night" : "day")
-                );
+        writer.println("Mode:" +
+                ((mNightSetting == UiModeManager.MODE_NIGHT_YES) ? "night" : "day"));
         writer.println("Forced Mode? " + (mForcedMode == FORCED_SENSOR_MODE ? "false"
                 : (mForcedMode == FORCED_DAY_MODE ? "day" : "night")));
     }
diff --git a/service/src/com/android/car/CarSensorService.java b/service/src/com/android/car/CarSensorService.java
index 8c5a960..4b0227e 100644
--- a/service/src/com/android/car/CarSensorService.java
+++ b/service/src/com/android/car/CarSensorService.java
@@ -40,10 +40,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
-import com.android.car.hal.SensorBase;
 import com.android.car.hal.SensorHalService;
-import com.android.car.hal.SensorHalService.SensorListener;
-import com.android.car.hal.SensorHalServiceBase;
 import com.android.internal.annotations.GuardedBy;
 
 import com.google.android.collect.Lists;
@@ -62,37 +59,6 @@
         implements CarServiceBase, SensorHalService.SensorListener {
 
     /**
-     * <pre>
-     * Abstraction for logical sensor which is not physical sensor but presented
-     * as sensor to upper layer. Currently {@link CarSensorManager#SENSOR_TYPE_NIGHT}
-     * falls into this category.
-     * Implementation can call {@link CarSensorService#onSensorData(CarSensorEvent)} when there
-     * is state change for the given sensor after {@link SensorHalServiceBase#init()}
-     * is called.
-     * </pre>
-     */
-    public static abstract class LogicalSensor implements SensorBase {
-        private final LinkedList<CarSensorEvent> mDispatchQ = new LinkedList<>();
-
-        /** Sensor service is ready and all vehicle sensors are available. */
-        public abstract void onSensorServiceReady();
-
-        /**
-         * Utility to help service to send one event as listener only takes list form.
-         * @param listener
-         * @param event
-         *
-         */
-        protected void dispatchCarSensorEvent(SensorListener listener, CarSensorEvent event) {
-            synchronized (mDispatchQ) {
-                mDispatchQ.add(event);
-                listener.onSensorEvents(mDispatchQ);
-                mDispatchQ.clear();
-            }
-        }
-    }
-
-    /**
      * When set, sensor service sets its own dispatching rate limit.
      * VehicleNetworkService is already doing this, so not necessary to set it for now.
      */
@@ -168,7 +134,8 @@
             event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT, 0, 0, 1, 0);
             event.intValues[0] = 1; // 1 means night mode!
         }
-        Log.i(CarLog.TAG_SENSOR, "initial daynight: " + event.intValues[0]);
+        Log.i(CarLog.TAG_SENSOR, "initial daynight: " +
+            (event.intValues[0] == 1 ? "Night" : "Day"));
 
         return event;
     }
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 9db071b..037069a 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -21,6 +21,7 @@
 import android.car.Car;
 import android.car.ICar;
 import android.car.cluster.renderer.IInstrumentClusterNavigation;
+import android.car.user.CarUserManagerHelper;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.automotive.vehicle.V2_0.IVehicle;
@@ -39,6 +40,7 @@
 import com.android.car.internal.FeatureConfiguration;
 import com.android.car.pm.CarPackageManagerService;
 import com.android.car.systeminterface.SystemInterface;
+import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.car.ICarServiceHelper;
 
@@ -81,6 +83,8 @@
     private final CarDiagnosticService mCarDiagnosticService;
     private final CarStorageMonitoringService mCarStorageMonitoringService;
     private final CarConfigurationService mCarConfigurationService;
+    private final CarUserManagerHelper mCarUserManagerHelper;
+    private final CarUserService mCarUserService;
 
     private VmsSubscriberService mVmsSubscriberService;
     private VmsPublisherService mVmsPublisherService;
@@ -144,10 +148,13 @@
                 systemInterface);
         mCarConfigurationService =
                 new CarConfigurationService(serviceContext, new JsonReaderImpl());
+        mCarUserManagerHelper = new CarUserManagerHelper(serviceContext);
+        mCarUserService = new CarUserService(serviceContext, mCarUserManagerHelper);
 
         // Be careful with order. Service depending on other service should be inited later.
         mAllServices = new CarServiceBase[] {
             mSystemActivityMonitoringService,
+            mCarUserService,
             mCarPowerManagementService,
             mCarSensorService,
             mCarDrivingStateService,
diff --git a/service/src/com/android/car/SystemActivityMonitoringService.java b/service/src/com/android/car/SystemActivityMonitoringService.java
index 24ce2e7..2df9b00 100644
--- a/service/src/com/android/car/SystemActivityMonitoringService.java
+++ b/service/src/com/android/car/SystemActivityMonitoringService.java
@@ -85,10 +85,6 @@
         void onActivityLaunch(TopTaskInfoContainer topTask);
     }
 
-    private static final boolean DBG = false;
-
-    private static final int NUM_MAX_TASK_TO_FETCH = 10;
-
     private final Context mContext;
     private final IActivityManager mAm;
     private final ProcessObserver mProcessObserver;
@@ -192,6 +188,57 @@
         return false;
     }
 
+    /**
+     * Attempts to restart a task.
+     *
+     * <p>Restarts a task by sending an empty intent with flag
+     * {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} to its root activity. If the task does not exist,
+     * do nothing.
+     *
+     * @param taskId id of task to be restarted.
+     */
+    public void restartTask(int taskId) {
+        String rootActivityName = null;
+        int userId = 0;
+        try {
+            findRootActivityName:
+            for (StackInfo info : mAm.getAllStackInfos()) {
+                for (int i = 0; i < info.taskIds.length; i++) {
+                    if (info.taskIds[i] == taskId) {
+                        rootActivityName = info.taskNames[i];
+                        userId = info.userId;
+                        if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
+                            Log.d(CarLog.TAG_AM, "Root activity is " + rootActivityName);
+                            Log.d(CarLog.TAG_AM, "User id is " + userId);
+                        }
+                        // Break out of nested loop.
+                        break findRootActivityName;
+                    }
+                }
+            }
+        } catch (RemoteException e) {
+            Log.e(CarLog.TAG_AM, "Could not get stack info", e);
+            return;
+        }
+
+        if (rootActivityName == null) {
+            Log.e(CarLog.TAG_AM, "Could not find root activity with task id " + taskId);
+            return;
+        }
+
+        Intent rootActivityIntent = new Intent();
+        rootActivityIntent.setComponent(ComponentName.unflattenFromString(rootActivityName));
+        // Clear the task the root activity is running in and start it in a new task.
+        // Effectively restart root activity.
+        rootActivityIntent.addFlags(
+                Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
+            Log.i(CarLog.TAG_AM, "restarting root activity with user id " + userId);
+        }
+        mContext.startActivityAsUser(rootActivityIntent, new UserHandle(userId));
+    }
+
     public void registerActivityLaunchListener(ActivityLaunchListener listener) {
         synchronized (this) {
             mActivityLaunchListener = listener;
@@ -238,7 +285,7 @@
                         (focusedStackId == stackId && focusedStackId != mFocusedStackId)) {
                     mTopTasks.put(stackId, newTopTaskInfo);
                     mTasksToDispatch.add(newTopTaskInfo);
-                    if (DBG) {
+                    if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
                         Log.i(CarLog.TAG_AM, "New top task: " + newTopTaskInfo);
                     }
                 }
@@ -247,7 +294,7 @@
         }
         if (listener != null) {
             for (TopTaskInfoContainer topTask : mTasksToDispatch) {
-                if (DBG) {
+                if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
                     Log.i(CarLog.TAG_AM, "activity launched:" + topTask.toString());
                 }
                 listener.onActivityLaunch(topTask);
@@ -310,11 +357,9 @@
      * block the current task with the provided new activity.
      */
     private void handleBlockActivity(TopTaskInfoContainer currentTask, Intent newActivityIntent) {
-        newActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
         mContext.startActivityAsUser(newActivityIntent,
                 new UserHandle(currentTask.stackInfo.userId));
-        // now make stack with new activity focused.
+        // Now make stack with new activity focused.
         findTaskAndGrantFocus(newActivityIntent.getComponent());
     }
 
@@ -347,7 +392,7 @@
     private class ProcessObserver extends IProcessObserver.Stub {
         @Override
         public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
-            if (DBG) {
+            if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
                 Log.i(CarLog.TAG_AM,
                         String.format("onForegroundActivitiesChanged uid %d pid %d fg %b",
                     uid, pid, foregroundActivities));
@@ -364,7 +409,7 @@
     private class TaskListener extends TaskStackListener {
         @Override
         public void onTaskStackChanged() {
-            if (DBG) {
+            if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
                 Log.i(CarLog.TAG_AM, "onTaskStackChanged");
             }
             mHandler.requestUpdatingTask();
diff --git a/service/src/com/android/car/VmsSubscriberService.java b/service/src/com/android/car/VmsSubscriberService.java
index aea0274..371b418 100644
--- a/service/src/com/android/car/VmsSubscriberService.java
+++ b/service/src/com/android/car/VmsSubscriberService.java
@@ -20,12 +20,9 @@
 import android.car.Car;
 import android.car.vms.IVmsSubscriberClient;
 import android.car.vms.IVmsSubscriberService;
-import android.car.vms.VmsAssociatedLayer;
-import android.car.vms.VmsLayer;
 import android.car.vms.VmsAvailableLayers;
+import android.car.vms.VmsLayer;
 import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
@@ -34,9 +31,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -56,7 +51,6 @@
 
     private final Context mContext;
     private final VmsHalService mHal;
-    private final Set<String> mWhitelistedSubscribersNames;
 
     @GuardedBy("mSubscriberServiceLock")
     private final VmsSubscribersManager mSubscribersManager = new VmsSubscribersManager();
@@ -205,30 +199,6 @@
     public VmsSubscriberService(Context context, VmsHalService hal) {
         mContext = context;
         mHal = hal;
-        mWhitelistedSubscribersNames = Collections.unmodifiableSet(
-                new HashSet(Arrays.asList(
-                        mContext.getResources().getStringArray(R.array.allowedVmsSubscriberClients))));
-        Log.d(TAG, "Initialized VMS subscribers whitelist: " + mWhitelistedSubscribersNames);
-    }
-
-    private void verifySubscriberOrThrow() {
-        // Assert permissions.
-        ICarImpl.assertVmsSubscriberPermission(mContext);
-
-        // Assert whitelisted.
-        int callingUid = Binder.getCallingUid();
-        PackageManager pm = mContext.getPackageManager();
-        Set<String> packagesForUid = new HashSet<>(Arrays.asList(pm.getPackagesForUid(callingUid)));
-
-        packagesForUid.retainAll(mWhitelistedSubscribersNames);
-        if (packagesForUid.isEmpty()) {
-            throw new SecurityException(
-                    "Package is not whitelisted as a VMS Subscriber. got : "
-                            + Arrays.asList(pm.getPackagesForUid(callingUid))
-                            + " expected :"
-                            + mWhitelistedSubscribersNames);
-        }
-        Log.d(TAG, "verified package for VMS subscriber API: " + packagesForUid);
     }
 
     // Implements CarServiceBase interface.
@@ -250,7 +220,7 @@
     // Implements IVmsService interface.
     @Override
     public void addVmsSubscriberToNotifications(IVmsSubscriberClient subscriber) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             // Add the subscriber so it can subscribe.
             mSubscribersManager.add(subscriber);
@@ -259,7 +229,7 @@
 
     @Override
     public void removeVmsSubscriberToNotifications(IVmsSubscriberClient subscriber) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             if (mHal.containsSubscriber(subscriber)) {
                 throw new IllegalArgumentException("Subscriber has active subscriptions.");
@@ -270,7 +240,7 @@
 
     @Override
     public void addVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             // Add the subscriber so it can subscribe.
             mSubscribersManager.add(subscriber);
@@ -282,7 +252,7 @@
 
     @Override
     public void removeVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             // Remove the subscription.
             mHal.removeSubscription(subscriber, layer);
@@ -293,7 +263,7 @@
     public void addVmsSubscriberToPublisher(IVmsSubscriberClient subscriber,
                                             VmsLayer layer,
                                             int publisherId) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             // Add the subscriber so it can subscribe.
             mSubscribersManager.add(subscriber);
@@ -307,7 +277,7 @@
     public void removeVmsSubscriberToPublisher(IVmsSubscriberClient subscriber,
                                                VmsLayer layer,
                                                int publisherId) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             // Remove the subscription.
             mHal.removeSubscription(subscriber, layer, publisherId);
@@ -316,7 +286,7 @@
 
     @Override
     public void addVmsSubscriberPassive(IVmsSubscriberClient subscriber) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             mSubscribersManager.add(subscriber);
             mHal.addSubscription(subscriber);
@@ -325,7 +295,7 @@
 
     @Override
     public void removeVmsSubscriberPassive(IVmsSubscriberClient subscriber) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             // Remove the subscription.
             mHal.removeSubscription(subscriber);
@@ -334,7 +304,7 @@
 
     @Override
     public byte[] getPublisherInfo(int publisherId) {
-        verifySubscriberOrThrow();
+        ICarImpl.assertVmsSubscriberPermission(mContext);
         synchronized (mSubscriberServiceLock) {
             return mHal.getPublisherInfo(publisherId);
         }
diff --git a/service/src/com/android/car/hal/CarPropertyUtils.java b/service/src/com/android/car/hal/CarPropertyUtils.java
index 6b04b02..8b5c446 100644
--- a/service/src/com/android/car/hal/CarPropertyUtils.java
+++ b/service/src/com/android/car/hal/CarPropertyUtils.java
@@ -117,7 +117,6 @@
                     .setAccess(p.access)
                     .setChangeMode(p.changeMode)
                     .setConfigArray(p.configArray)
-                    .setConfigFlags(p.configFlags)
                     .setConfigString(p.configString)
                     .setMaxSampleRate(p.maxSampleRate)
                     .setMinSampleRate(p.minSampleRate)
@@ -128,7 +127,6 @@
                     .setAccess(p.access)
                     .setChangeMode(p.changeMode)
                     .setConfigArray(p.configArray)
-                    .setConfigFlags(p.configFlags)
                     .setConfigString(p.configString)
                     .setMaxSampleRate(p.maxSampleRate)
                     .setMinSampleRate(p.minSampleRate);
diff --git a/service/src/com/android/car/pm/ActivityBlockingActivity.java b/service/src/com/android/car/pm/ActivityBlockingActivity.java
index 3ce74df..3e55405 100644
--- a/service/src/com/android/car/pm/ActivityBlockingActivity.java
+++ b/service/src/com/android/car/pm/ActivityBlockingActivity.java
@@ -18,15 +18,20 @@
 import android.app.Activity;
 import android.car.Car;
 import android.car.CarNotConnectedException;
+import android.car.content.pm.CarPackageManager;
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.CarUxRestrictionsManager;
 import android.content.ComponentName;
+import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.text.TextUtils;
 import android.util.Log;
+import android.view.View;
+import android.widget.Button;
 import android.widget.TextView;
 
 import com.android.car.CarLog;
@@ -39,20 +44,29 @@
  */
 public class ActivityBlockingActivity extends Activity {
     public static final String INTENT_KEY_BLOCKED_ACTIVITY = "blocked_activity";
+    public static final String EXTRA_BLOCKED_TASK = "blocked_task";
+
+    private static final int INVALID_TASK_ID = -1;
 
     private Car mCar;
     private CarUxRestrictionsManager mUxRManager;
 
+    private TextView mBlockedTitle;
+    private Button mExitButton;
+    // Exiting depends on Car connection, which might not be available at the time exit was
+    // requested (e.g. user presses Exit Button). In that case, we record exiting was requested, and
+    // Car connection will perform exiting once it is established.
+    private boolean mExitRequested;
+    private int mBlockedTaskId;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_blocking);
 
-        String blockedActivity = getIntent().getStringExtra(INTENT_KEY_BLOCKED_ACTIVITY);
-
-        TextView blockedTitle = findViewById(R.id.activity_blocked_title);
-        blockedTitle.setText(getString(R.string.activity_blocked_string,
-                findBlockedApplicationLabel(blockedActivity)));
+        mBlockedTitle = findViewById(R.id.activity_blocked_title);
+        mExitButton = findViewById(R.id.exit);
+        mExitButton.setOnClickListener(v -> handleFinish());
 
         // Listen to the CarUxRestrictions so this blocking activity can be dismissed when the
         // restrictions are lifted.
@@ -60,6 +74,9 @@
             @Override
             public void onServiceConnected(ComponentName name, IBinder service) {
                 try {
+                    if (mExitRequested) {
+                        handleFinish();
+                    }
                     mUxRManager = (CarUxRestrictionsManager) mCar.getCarManager(
                             Car.CAR_UX_RESTRICTION_SERVICE);
                     // This activity would have been launched only in a restricted state.
@@ -81,29 +98,34 @@
         mCar.connect();
     }
 
-    /**
-     * Returns the application label of blockedActivity. If that fails, the original activity will
-     * be returned.
-     */
-    private String findBlockedApplicationLabel(String blockedActivity) {
-        String label = blockedActivity;
-        // Attempt to update blockedActivity name to application label.
-        try {
-            ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(
-                    ComponentName.unflattenFromString(blockedActivity).getPackageName(), 0);
-            CharSequence appLabel = getPackageManager().getApplicationLabel(applicationInfo);
-            if (appLabel != null) {
-                label = appLabel.toString();
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            e.printStackTrace();
-        }
-        return label;
-    }
-
     @Override
     protected void onResume() {
         super.onResume();
+
+        // Display message about the current blocked activity, and optionally show an exit button
+        // to restart the blocked task (stack of activities) if its root activity is DO.
+
+        // blockedActivity is expected to be always passed in as the topmost activity of task.
+        String blockedActivity = getIntent().getStringExtra(INTENT_KEY_BLOCKED_ACTIVITY);
+        mBlockedTitle.setText(getString(R.string.activity_blocked_string,
+                findHumanReadableLabel(blockedActivity)));
+        if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG)) {
+            Log.d(CarLog.TAG_AM, "Blocking activity " + blockedActivity);
+        }
+
+        // taskId is available as extra if the task can be restarted.
+        mBlockedTaskId = getIntent().getIntExtra(EXTRA_BLOCKED_TASK, INVALID_TASK_ID);
+
+        mExitButton.setVisibility(mBlockedTaskId == INVALID_TASK_ID ? View.GONE : View.VISIBLE);
+        if (Log.isLoggable(CarLog.TAG_AM, Log.DEBUG) && mBlockedTaskId == INVALID_TASK_ID) {
+            Log.d(CarLog.TAG_AM, "Blocked task ID is not available. Hiding exit button.");
+        }
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        setIntent(intent);
     }
 
     @Override
@@ -130,4 +152,57 @@
             finish();
         }
     }
+
+    /**
+     * Returns a human-readable string for {@code flattenComponentName}.
+     *
+     * <p>It first attempts to return the application label for this activity. If that fails,
+     * it will return the last part in the activity name.
+     */
+    private String findHumanReadableLabel(String flattenComponentName) {
+        ComponentName componentName = ComponentName.unflattenFromString(flattenComponentName);
+        String label = null;
+        // Attempt to find application label.
+        try {
+            ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(
+                    componentName.getPackageName(), 0);
+            CharSequence appLabel = getPackageManager().getApplicationLabel(applicationInfo);
+            if (appLabel != null) {
+                label = appLabel.toString();
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            if (Log.isLoggable(CarLog.TAG_AM, Log.INFO)) {
+                Log.i(CarLog.TAG_AM, "Could not find package for component name "
+                        + componentName.toString());
+            }
+        }
+        if (TextUtils.isEmpty(label)) {
+            label = componentName.getClass().getSimpleName();
+        }
+        return label;
+    }
+
+    private void handleFinish() {
+        if (!mCar.isConnected()) {
+            mExitRequested = true;
+            return;
+        }
+        if (isFinishing()) {
+            return;
+        }
+
+        // Lock on self (assuming single instance) to avoid restarting the same task twice.
+        synchronized (this) {
+            try {
+                CarPackageManager carPm = (CarPackageManager)
+                        mCar.getCarManager(Car.PACKAGE_SERVICE);
+                carPm.restartTask(mBlockedTaskId);
+            } catch (CarNotConnectedException e) {
+                // We should never be here since Car connection is already checked.
+                Log.e(CarLog.TAG_AM, "Car connection is not available.", e);
+                return;
+            }
+            finish();
+        }
+    }
 }
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index 916bf1c..930a9e4 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -45,6 +45,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
+import android.text.format.DateFormat;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
@@ -76,6 +77,7 @@
     // Delimiters to parse packages and activities in the configuration XML resource.
     private static final String PACKAGE_DELIMITER = ",";
     private static final String PACKAGE_ACTIVITY_DELIMITER = "/";
+    private static final int LOG_SIZE = 20;
 
     private final Context mContext;
     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
@@ -84,6 +86,9 @@
     private final HandlerThread mHandlerThread;
     private final PackageHandler mHandler;
 
+    // For dumpsys logging.
+    private final LinkedList<String> mBlockedActivityLogs = new LinkedList<>();
+
     // Store the white list and black list strings from the resource file.
     private String mConfiguredWhitelist;
     private String mConfiguredBlacklist;
@@ -157,6 +162,14 @@
         doSetAppBlockingPolicy(packageName, policy, flags, true /*setNow*/);
     }
 
+    /**
+     * Restarts the requested task. If task with {@code taskId} does not exist, do nothing.
+     */
+    @Override
+    public void restartTask(int taskId) {
+        mSystemActivityMonitoringService.restartTask(taskId);
+    }
+
     private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy, int flags,
             boolean setNow) {
         if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING)
@@ -801,6 +814,7 @@
             writer.println("mHasParsedPackages:" + mHasParsedPackages);
             writer.println("mBootLockedIntentRx:" + mBootLockedIntentRx);
             writer.println("ActivityRestricted:" + mUxRestrictionsListener.isRestricted());
+            writer.println(String.join("\n", mBlockedActivityLogs));
             writer.print(dumpPoliciesLocked(true));
         }
     }
@@ -879,11 +893,42 @@
                     " not allowed, will block, number of tasks in stack:" +
                     topTask.stackInfo.taskIds.length);
         }
+        StringBuilder blockedActivityLog = new StringBuilder();
         Intent newActivityIntent = new Intent();
         newActivityIntent.setComponent(mActivityBlockingActivity);
         newActivityIntent.putExtra(
                 ActivityBlockingActivity.INTENT_KEY_BLOCKED_ACTIVITY,
                 topTask.topActivity.flattenToString());
+        blockedActivityLog.append("Blocked activity ")
+                .append(topTask.topActivity.flattenToShortString())
+                .append(". Task id ").append(topTask.taskId);
+
+        // If root activity of blocked task is DO, also pass its task id into blocking activity,
+        // which uses the id to display a button for restarting the blocked task.
+        for (int i = 0; i < topTask.stackInfo.taskIds.length; i++) {
+            // topTask.taskId is the task that should be blocked.
+            if (topTask.stackInfo.taskIds[i] == topTask.taskId) {
+                // stackInfo represents an ActivityStack. Its fields taskIds and taskNames
+                // are 1:1 mapped, where taskNames is the name of root activity in this task.
+                String taskRootActivity = topTask.stackInfo.taskNames[i];
+
+                ComponentName rootActivityName = ComponentName.unflattenFromString(
+                        taskRootActivity);
+                if (isActivityDistractionOptimized(
+                        rootActivityName.getPackageName(), rootActivityName.getClassName())) {
+                    newActivityIntent.putExtra(
+                            ActivityBlockingActivity.EXTRA_BLOCKED_TASK, topTask.taskId);
+                    if (Log.isLoggable(CarLog.TAG_PACKAGE, Log.INFO)) {
+                        Log.i(CarLog.TAG_PACKAGE, "Blocked task " + topTask.taskId
+                                + " has DO root activity " + taskRootActivity);
+                    }
+                    blockedActivityLog.append(". Root DO activity ")
+                            .append(rootActivityName.flattenToShortString());
+                }
+                break;
+            }
+        }
+        addLog(blockedActivityLog.toString());
         mSystemActivityMonitoringService.blockActivity(topTask, newActivityIntent);
     }
 
@@ -926,6 +971,23 @@
     }
 
     /**
+     * Append one line of log for dumpsys.
+     *
+     * <p>Maintains the size of log by {@link #LOG_SIZE} and appends tag and timestamp to the line.
+     */
+    private void addLog(String log) {
+        while (mBlockedActivityLogs.size() >= LOG_SIZE) {
+            mBlockedActivityLogs.remove();
+        }
+        StringBuffer sb = new StringBuffer()
+                .append(CarLog.TAG_PACKAGE).append(':')
+                .append(DateFormat.format(
+                        "MM-dd HH:mm:ss", System.currentTimeMillis())).append(": ")
+                .append(log);
+        mBlockedActivityLogs.add(sb.toString());
+    }
+
+    /**
      * Reading policy and setting policy can take time. Run it in a separate handler thread.
      */
     private class PackageHandler extends Handler {
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
new file mode 100644
index 0000000..1c830f2
--- /dev/null
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import android.annotation.NonNull;
+import android.car.user.CarUserManagerHelper;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.util.Log;
+
+import com.android.car.CarServiceBase;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.PrintWriter;
+
+/**
+ * User service for cars. Manages users at boot time. Including:
+ *
+ * <ol>
+ *   <li> Creates a secondary admin user on first run.
+ *   <li> Log in to a default user.
+ * <ol/>
+ */
+public class CarUserService extends BroadcastReceiver implements CarServiceBase {
+    // Place holder for user name of the first user created.
+    @VisibleForTesting
+    static final String OWNER_NAME = "Owner";
+    private static final String TAG = "CarUserService";
+    private final Context mContext;
+    private final CarUserManagerHelper mCarUserManagerHelper;
+
+    public CarUserService(
+                @NonNull Context context, @NonNull CarUserManagerHelper carUserManagerHelper) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "constructed");
+        }
+        mContext = context;
+        mCarUserManagerHelper = carUserManagerHelper;
+    }
+
+    @Override
+    public void init() {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "init");
+        }
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+
+        mContext.registerReceiver(this, filter);
+    }
+
+    @Override
+    public void release() {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "release");
+        }
+        mContext.unregisterReceiver(this);
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        writer.println(TAG);
+        writer.println("Context: " + mContext);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Log.d(TAG, "onReceive " + intent);
+        }
+
+        if (intent.getAction() == Intent.ACTION_LOCKED_BOOT_COMPLETED) {
+            if (mCarUserManagerHelper.getAllUsers().size() == 0) {
+                UserInfo admin = mCarUserManagerHelper.createNewAdminUser(OWNER_NAME);
+                mCarUserManagerHelper.switchToUser(admin);
+            } else {
+                // Add logic for boot into default user.
+            }
+        }
+    }
+}
diff --git a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
index 30313c0..a57d800 100644
--- a/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
+++ b/tests/carservice_test/src/com/android/car/MockedCarTestBase.java
@@ -397,6 +397,11 @@
                     return super.getSystemService(name);
             }
         }
+
+        @Override
+        public Context getApplicationContext() {
+            return this;
+        }
     }
 
     static final class MockStorageMonitoringInterface implements StorageMonitoringInterface {}
diff --git a/tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
similarity index 91%
rename from tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java
rename to tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
index ff24b8e..480b84b 100644
--- a/tests/carservice_unit_test/src/com/android/car/CarUserManagerTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/CarUserManagerHelperTest.java
@@ -57,7 +57,7 @@
  * 4. {@link CarUserManagerHelper.OnUsersUpdateListener} registers a listener for user updates.
  */
 @RunWith(AndroidJUnit4.class)
-public class CarUserManagerTest {
+public class CarUserManagerHelperTest {
     @Mock
     private Context mContext;
     @Mock
@@ -142,34 +142,6 @@
             .containsExactly(mCurrentProcessUser, otherUser1, otherUser2, otherUser3);
     }
 
-    // Get all users should exclude system user by default.
-    @Test
-    public void testGetAllSwitchableUsers() {
-        UserInfo user1 = createUserInfoForId(10);
-        UserInfo user2 = createUserInfoForId(11);
-        UserInfo user3 = createUserInfoForId(12);
-
-        List<UserInfo> testUsers = new ArrayList<>();
-        testUsers.add(mSystemUser);
-        testUsers.add(user1);
-        testUsers.add(user2);
-        testUsers.add(user3);
-
-        when(mUserManager.getUsers(true)).thenReturn(new ArrayList<>(testUsers));
-
-        // Should return all 3 non-system users.
-        assertThat(mHelper.getAllUsers().size())
-                .isEqualTo(3);
-
-        when(mUserManager.getUserInfo(UserHandle.myUserId())).thenReturn(user1);
-        // Should return user 10, 11 and 12.
-        assertThat(mHelper.getAllSwitchableUsers().size())
-                .isEqualTo(3);
-        assertThat(mHelper.getAllSwitchableUsers()).contains(user1);
-        assertThat(mHelper.getAllSwitchableUsers()).contains(user2);
-        assertThat(mHelper.getAllSwitchableUsers()).contains(user3);
-    }
-
     @Test
     public void testUserCanBeRemoved() {
         UserInfo testInfo = new UserInfo();
diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
new file mode 100644
index 0000000..faa7bd0
--- /dev/null
+++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.user;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.user.CarUserManagerHelper;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * This class contains unit tests for the {@link CarUserService}.
+ *
+ * The following mocks are used:
+ * <ol>
+ *   <li> {@link Context} provides system services and resources.
+ *   <li> {@link CarUserManagerHelper} provides user info and actions.
+ * <ol/>
+ */
+@RunWith(AndroidJUnit4.class)
+public class CarUserServiceTest {
+    private CarUserService mCarUserService;
+
+    @Mock
+    private Context mMockContext;
+
+    @Mock
+    private Context mApplicationContext;
+
+    @Mock
+    private CarUserManagerHelper mCarUserManagerHelper;
+
+    /**
+     * Initialize all of the objects with the @Mock annotation.
+     */
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mMockContext.getApplicationContext()).thenReturn(mApplicationContext);
+
+        mCarUserService = new CarUserService(mMockContext, mCarUserManagerHelper);
+    }
+
+    /**
+     * Test that the {@link CarUserService} registers to receive the locked boot completed
+     * intent.
+     */
+    @Test
+    public void testRegistersToReceiveEvents() {
+        ArgumentCaptor<IntentFilter> argument = ArgumentCaptor.forClass(IntentFilter.class);
+        mCarUserService.init();
+        verify(mMockContext).registerReceiver(eq(mCarUserService), argument.capture());
+        IntentFilter intentFilter = argument.getValue();
+        assertThat(intentFilter.countActions()).isEqualTo(1);
+
+        assertThat(intentFilter.getAction(0)).isEqualTo(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+    }
+
+    /**
+     * Test that the {@link CarUserService} unregisters its event receivers.
+     */
+    @Test
+    public void testUnregistersEventReceivers() {
+        mCarUserService.release();
+        verify(mMockContext).unregisterReceiver(mCarUserService);
+    }
+
+    /**
+     * Test that the {@link CarUserService} starts up a secondary admin user upon first run.
+     */
+    @Test
+    public void testStartsSecondaryAdminUserOnFirstRun() {
+        List<UserInfo> users = new ArrayList<>();
+
+        int adminUserId = 10;
+        UserInfo admin = new UserInfo(adminUserId, CarUserService.OWNER_NAME, UserInfo.FLAG_ADMIN);
+
+        doReturn(users).when(mCarUserManagerHelper).getAllUsers();
+        // doReturn(users).when(mCarUserManagerHelper.getAllUsers());
+        doReturn(admin).when(mCarUserManagerHelper).createNewAdminUser(CarUserService.OWNER_NAME);
+        doReturn(true).when(mCarUserManagerHelper).switchToUser(admin);
+
+        mCarUserService.onReceive(mMockContext,
+                new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED));
+
+        verify(mCarUserManagerHelper).createNewAdminUser(CarUserService.OWNER_NAME);
+        verify(mCarUserManagerHelper).switchToUser(admin);
+    }
+}
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 2bf442d..59868d5 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
@@ -49,7 +49,6 @@
         newConfig.prop = propConfig.prop;
         newConfig.access = propConfig.access;
         newConfig.changeMode = propConfig.changeMode;
-        newConfig.configFlags = propConfig.configFlags;
         newConfig.configString = propConfig.configString;
         newConfig.minSampleRate = propConfig.minSampleRate;
         newConfig.maxSampleRate = propConfig.maxSampleRate;
@@ -82,12 +81,6 @@
     }
 
     @CheckResult
-    public VehiclePropConfigBuilder setConfigFlags(int configFlags) {
-        mConfig.configFlags = configFlags;
-        return this;
-    }
-
-    @CheckResult
     public VehiclePropConfigBuilder setConfigString(String configString) {
         mConfig.configString = configString;
         return this;