Add vehicle HAL mocking with carsystem and carsystemtest API

- System API and system test API for testing only added. Client
  should link only one of them.
- vehicle HAL mocking allows mocking vehicle HAL completely.
- Once mocking is started, for now, all previous states are forgotton,
  so stopping mocking does not return to original state. It is
  better to simply restart framework after test.
- Added skeleton code for audio focus handling. Detailed implementaiton
  will be added later.

bug: 24874617

Change-Id: I6e60daab3dc96769a94acc09a695f8f49dbb8536
(cherry picked from commit a32e24f50d5895a94d3a13d6ec2233af6e43dac5)
diff --git a/carsupport-lib/src/android/support/car/Car.java b/carsupport-lib/src/android/support/car/Car.java
index 7b2fcfd..49246cf 100644
--- a/carsupport-lib/src/android/support/car/Car.java
+++ b/carsupport-lib/src/android/support/car/Car.java
@@ -51,12 +51,6 @@
     /** Service name for {@link CarInfoManager}, to be used in {@link #getCarManager(String)}. */
     public static final String INFO_SERVICE = "info";
 
-    /**
-     * Service for testing. This is system app only feature.
-     * @hide
-     */
-    public static final String TEST_SERVICE = "car-service-test";
-
     /** Type of car connection: car emulator, not physical connection. */
     public static final int CONNECTION_TYPE_EMULATOR        = 0;
     /** Type of car connection: connected to a car via USB. */
@@ -120,7 +114,7 @@
     private final ServiceConnectionListener mServiceConnectionListener =
             new ServiceConnectionListener () {
         public void onServiceConnected(ComponentName name, IBinder service) {
-            synchronized (this) {
+            synchronized (Car.this) {
                 mService = ICar.Stub.asInterface(service);
                 mConnectionState = STATE_CONNECTED;
                 // getVersion can fail but let it pass through as it is better to
@@ -139,7 +133,7 @@
         }
 
         public void onServiceDisconnected(ComponentName name) {
-            synchronized (this) {
+            synchronized (Car.this) {
                 mService = null;
                 if (mConnectionState  == STATE_DISCONNECTED) {
                     return;
@@ -166,6 +160,17 @@
     private final CarServiceLoader mCarServiceLoader;
 
     /**
+     * This defines CarServiceLoader that will be tried for FEATURE_AUTOMOTIVE case.
+     * For system test and system api, there are separate static libraries. If those
+     * libraries are linked, CarServiceLoader from those libraries are loaded so that
+     * custom car managers can be populated from there.
+     * This is done to prevent bloating the library which is not relevant for the app.
+     */
+    private static final String[] CAR_SERVICE_LOADERS_FOR_FEATURE_AUTOMOTIVE = {
+        "com.android.car.SystemTestApiCarServiceLoader",
+        "com.android.car.SystemApiCarServiceLoader",
+    };
+    /**
      * Create Car instance for all Car API access.
      * @param context
      * @param serviceConnectionListener listner for monitoring service connection.
@@ -182,33 +187,56 @@
             mLooper = looper;
         }
         if (mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)) {
-            //TODO allow overriding this for system api
-            mCarServiceLoader = new DefaultCarServiceLoader(context, mServiceConnectionListener);
+            CarServiceLoader loader = null;
+            for (String classToTry : CAR_SERVICE_LOADERS_FOR_FEATURE_AUTOMOTIVE) {
+                try {
+                    loader = loadCarServiceLoader(classToTry, context, mServiceConnectionListener,
+                            mLooper);
+                } catch (IllegalArgumentException e) {
+                    // expected when only lower level libraries are linked.
+                }
+                if (loader != null) {
+                    break;
+                }
+            }
+            if (loader == null) {
+                mCarServiceLoader = new DefaultCarServiceLoader(context,
+                        mServiceConnectionListener, mLooper);
+            } else {
+                mCarServiceLoader = loader;
+            }
         } else {
-            Class carServiceLoaderClass = null;
-            try {
-                carServiceLoaderClass = Class.forName(PROJECTED_CAR_SERVICE_LOADER);
-            } catch (ClassNotFoundException e) {
-                throw new RuntimeException("Cannot find CarServiceLoader implementation:" +
-                        PROJECTED_CAR_SERVICE_LOADER, e);
-            }
-            Constructor<?> ctor;
-            try {
-                ctor = carServiceLoaderClass.getDeclaredConstructor(Context.class,
-                        ServiceConnectionListener.class);
-            } catch (NoSuchMethodException e) {
-                throw new RuntimeException("Cannot construct CarServiceLoader, no constructor: " +
-                        PROJECTED_CAR_SERVICE_LOADER, e);
-            }
-            try {
-                mCarServiceLoader = (CarServiceLoader) ctor.newInstance(context,
-                        serviceConnectionListener);
-            } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
-                    | InvocationTargetException e) {
-                throw new RuntimeException(
-                        "Cannot construct CarServiceLoader, constructor failed for "
-                        + carServiceLoaderClass.getName(), e);
-            }
+            mCarServiceLoader = loadCarServiceLoader(PROJECTED_CAR_SERVICE_LOADER, context,
+                    mServiceConnectionListener, mLooper);
+        }
+    }
+
+    private CarServiceLoader loadCarServiceLoader(String carServiceLoaderClassName,
+            Context context, ServiceConnectionListener serviceConnectionListener, Looper looper)
+                    throws IllegalArgumentException {
+        Class carServiceLoaderClass = null;
+        try {
+            carServiceLoaderClass = Class.forName(carServiceLoaderClassName);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("Cannot find CarServiceLoader implementation:" +
+                    carServiceLoaderClassName, e);
+        }
+        Constructor<?> ctor;
+        try {
+            ctor = carServiceLoaderClass.getDeclaredConstructor(Context.class,
+                    ServiceConnectionListener.class, Looper.class);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException("Cannot construct CarServiceLoader, no constructor: "
+                    + carServiceLoaderClassName, e);
+        }
+        try {
+            return (CarServiceLoader) ctor.newInstance(context,
+                    serviceConnectionListener, looper);
+        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+                | InvocationTargetException e) {
+            throw new IllegalArgumentException(
+                    "Cannot construct CarServiceLoader, constructor failed for "
+                    + carServiceLoaderClass.getName(), e);
         }
     }
 
@@ -297,17 +325,18 @@
      */
     public Object getCarManager(String serviceName) throws CarNotConnectedException {
         CarManagerBase manager = null;
+        ICar service = getICarOrThrow();
         synchronized (mCarManagerLock) {
             manager = mServiceMap.get(serviceName);
             if (manager == null) {
                 try {
-                    IBinder binder = mService.getCarService(serviceName);
+                    IBinder binder = service.getCarService(serviceName);
                     if (binder == null) {
                         Log.w(CarLibLog.TAG_CAR, "getCarManager could not get binder for service:" +
                                 serviceName);
                         return null;
                     }
-                    manager = createCarManager(serviceName, binder);
+                    manager = mCarServiceLoader.createCarManager(serviceName, binder);
                     if (manager == null) {
                         Log.w(CarLibLog.TAG_CAR,
                                 "getCarManager could not create manager for service:" +
@@ -339,23 +368,6 @@
         return Car.CONNECTION_TYPE_EMULATOR;
     }
 
-    private CarManagerBase createCarManager(String serviceName, IBinder binder) {
-        CarManagerBase manager = null;
-        switch (serviceName) {
-            case SENSOR_SERVICE:
-                manager = new CarSensorManager(mContext, ICarSensor.Stub.asInterface(binder),
-                        mLooper);
-                break;
-            case INFO_SERVICE:
-                manager = new CarInfoManager(ICarInfo.Stub.asInterface(binder));
-                break;
-            default:
-                manager = mCarServiceLoader.createCustomCarManager(serviceName, binder);
-                break;
-        }
-        return manager;
-    }
-
     private synchronized ICar getICarOrThrow() throws IllegalStateException {
         if (mService == null) {
             throw new IllegalStateException("not connected");
diff --git a/carsupport-lib/src/android/support/car/CarManagerBase.java b/carsupport-lib/src/android/support/car/CarManagerBase.java
index 832188c..79a28f8 100644
--- a/carsupport-lib/src/android/support/car/CarManagerBase.java
+++ b/carsupport-lib/src/android/support/car/CarManagerBase.java
@@ -18,7 +18,8 @@
 
 /**
  * Common interface for Car*Manager
+ * @hide
  */
-interface CarManagerBase {
+public interface CarManagerBase {
     void onCarDisconnected();
 }
diff --git a/carsupport-lib/src/android/support/car/CarServiceLoader.java b/carsupport-lib/src/android/support/car/CarServiceLoader.java
index 1989093..ac5c29e 100644
--- a/carsupport-lib/src/android/support/car/CarServiceLoader.java
+++ b/carsupport-lib/src/android/support/car/CarServiceLoader.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.os.IBinder;
+import android.os.Looper;
 
 /**
  * CarServiceLoader is the abstraction for loading different types of car service.
@@ -27,26 +28,39 @@
 
     private final Context mContext;
     private final ServiceConnectionListener mListener;
+    private final Looper mLooper;
 
-    public CarServiceLoader(Context context, ServiceConnectionListener listener) {
+    public CarServiceLoader(Context context, ServiceConnectionListener listener, Looper looper) {
         mContext = context;
         mListener = listener;
+        mLooper = looper;
     }
 
     public abstract void connect() throws IllegalStateException;
     public abstract void disconnect();
 
     /**
-     * Factory method to create non-standard Car*Manager for the given car service implementation.
-     * This is necessary for Car*Manager which is relevant for one specific implementation like
-     * projected.
+     * Factory method to create Car*Manager for the given car service implementation.
+     * Each implementation can add its own custom Car*Manager while default implementation will
+     * handle all standard Car*Managers.
      * @param serviceName service name for the given Car*Manager.
      * @param binder binder implementation received from car service
      * @return Car*Manager instance for the given serviceName / binder. null if given service is
      *         not supported.
      */
-    public CarManagerBase createCustomCarManager(String serviceName, IBinder binder) {
-        return null;
+    public CarManagerBase createCarManager(String serviceName,
+            IBinder binder) {
+        CarManagerBase manager = null;
+        switch (serviceName) {
+            case Car.SENSOR_SERVICE:
+                manager = new CarSensorManager(mContext, ICarSensor.Stub.asInterface(binder),
+                        mLooper);
+                break;
+            case Car.INFO_SERVICE:
+                manager = new CarInfoManager(ICarInfo.Stub.asInterface(binder));
+                break;
+        }
+        return manager;
     }
 
     protected Context getContext() {
@@ -56,4 +70,8 @@
     protected ServiceConnectionListener getConnectionListener() {
         return mListener;
     }
+
+    protected Looper getLooper() {
+        return mLooper;
+    }
 }
diff --git a/carsupport-lib/src/android/support/car/DefaultCarServiceLoader.java b/carsupport-lib/src/android/support/car/DefaultCarServiceLoader.java
index f3fcc68..b008017 100644
--- a/carsupport-lib/src/android/support/car/DefaultCarServiceLoader.java
+++ b/carsupport-lib/src/android/support/car/DefaultCarServiceLoader.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.IBinder;
+import android.os.Looper;
 
 /**
  * Default CarServiceLoader for system with built-in car service.
@@ -45,8 +46,9 @@
         }
     };
 
-    public DefaultCarServiceLoader(Context context, ServiceConnectionListener listener) {
-        super(context, listener);
+    public DefaultCarServiceLoader(Context context, ServiceConnectionListener listener,
+            Looper looper) {
+        super(context, listener, looper);
     }
 
     @Override
diff --git a/carsystem-lib/Android.mk b/carsystem-lib/Android.mk
new file mode 100644
index 0000000..baca9ae
--- /dev/null
+++ b/carsystem-lib/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2015 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.
+#
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcarsystem
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES += libcarsupport
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/carsystem-lib/src/com/android/car/CarSystem.java b/carsystem-lib/src/com/android/car/CarSystem.java
new file mode 100644
index 0000000..aee4bf1
--- /dev/null
+++ b/carsystem-lib/src/com/android/car/CarSystem.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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;
+
+/**
+ * Container class to hold static definitions for system api for Car.
+ * Client should still use Car api for all operations, and this class is only for defining
+ * additional parameters available when car api becomes system api.
+ * @hide
+ */
+public class CarSystem {
+
+}
diff --git a/carsystem-lib/src/com/android/car/SystemApiCarServiceLoader.java b/carsystem-lib/src/com/android/car/SystemApiCarServiceLoader.java
new file mode 100644
index 0000000..258bc0d
--- /dev/null
+++ b/carsystem-lib/src/com/android/car/SystemApiCarServiceLoader.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.Looper;
+import android.support.car.CarManagerBase;
+import android.support.car.DefaultCarServiceLoader;
+import android.support.car.ServiceConnectionListener;
+
+public class SystemApiCarServiceLoader extends DefaultCarServiceLoader {
+
+    public SystemApiCarServiceLoader(Context context, ServiceConnectionListener listener,
+            Looper looper) {
+        super(context, listener, looper);
+    }
+
+    @Override
+    public CarManagerBase createCarManager(String serviceName, IBinder binder) {
+        //TODO populate system only Car*Managers
+        //switch (serviceName) {
+        //}
+        return super.createCarManager(serviceName, binder);
+    }
+}
diff --git a/carsystemtest-lib/Android.mk b/carsystemtest-lib/Android.mk
new file mode 100644
index 0000000..2852bfd
--- /dev/null
+++ b/carsystemtest-lib/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 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.
+#
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcarsystemtest
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES += packages/services/Car/libvehiclenetwork/java/src/
+
+LOCAL_STATIC_JAVA_LIBRARIES += libcarsystem libvehiclenetwork-java
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/carsystemtest-lib/src/com/android/car/CarSystemTest.java b/carsystemtest-lib/src/com/android/car/CarSystemTest.java
new file mode 100644
index 0000000..b7997c0
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/CarSystemTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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;
+
+/**
+ * Container class to hold static definitions for system test api for Car.
+ * Client should still use Car api for all operations, and this class is only for defining
+ * additional parameters available when car api becomes system api.
+ * @hide
+ */
+public class CarSystemTest {
+    /**
+     * Service for testing. This is system app only feature.
+     * Service name for {@link CarTestManager}, to be used in {@link #getCarManager(String)}.
+     * @hide
+     */
+    public static final String TEST_SERVICE = "car-service-test";
+
+    /** permission necessary to mock vehicle hal for testing */
+    public static final String PERMISSION_MOCK_VEHICLE_HAL =
+            "android.support.car.permission.CAR_MOCK_VEHICLE_HAL";
+}
diff --git a/carsystemtest-lib/src/com/android/car/CarTestManager.java b/carsystemtest-lib/src/com/android/car/CarTestManager.java
new file mode 100644
index 0000000..6c65954
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/CarTestManager.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.os.RemoteException;
+import android.support.car.CarManagerBase;
+
+import com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
+import com.android.car.vehiclenetwork.VehicleNetwork;
+import com.android.car.vehiclenetwork.VehiclePropConfigsParcelable;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+
+public class CarTestManager implements CarManagerBase {
+
+    private final ICarTest mService;
+
+    @GuardedBy("this")
+    private VehicleNetworkHalMock mHalMock;
+    private IVehicleNetworkHalMockImpl mHalMockImpl;
+
+    public CarTestManager(ICarTest service) {
+        mService = service;
+    }
+
+    @Override
+    public void onCarDisconnected() {
+        // should not happen for embedded
+    }
+
+    public synchronized void injectEvent(VehiclePropValue value) {
+        try {
+            mService.injectEvent(new VehiclePropValueParcelable(value));
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        }
+    }
+
+    /**
+     * Start mocking vehicle HAL. It is somewhat strange to re-use interface in lower level
+     * API, but this is only for testing, and interface is exactly the same.
+     * @param mock
+     */
+    public synchronized void startMocking(VehicleNetworkHalMock mock) {
+        mHalMock = mock;
+        mHalMockImpl = new IVehicleNetworkHalMockImpl(this);
+        try {
+            mService.startMocking(mHalMockImpl);
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        }
+    }
+
+    public synchronized void stopMocking() {
+        try {
+            mService.stopMocking(mHalMockImpl);
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        } finally {
+            mHalMock = null;
+            mHalMockImpl = null;
+        }
+    }
+
+    private synchronized VehicleNetworkHalMock getHalMock() {
+        return mHalMock;
+    }
+
+    private void handleRemoteException(RemoteException e) {
+        //TODO
+    }
+
+    private static class IVehicleNetworkHalMockImpl extends IVehicleNetworkHalMock.Stub {
+        private final WeakReference<CarTestManager> mTestManager;
+
+        private IVehicleNetworkHalMockImpl(CarTestManager testManager) {
+            mTestManager = new WeakReference<CarTestManager>(testManager);
+        }
+
+        @Override
+        public VehiclePropConfigsParcelable onListProperties() {
+            CarTestManager testManager = mTestManager.get();
+            if (testManager == null) {
+                return null;
+            }
+            VehiclePropConfigs configs = testManager.getHalMock().onListProperties();
+            return new VehiclePropConfigsParcelable(configs);
+        }
+
+        @Override
+        public void onPropertySet(VehiclePropValueParcelable value) {
+            CarTestManager testManager = mTestManager.get();
+            if (testManager == null) {
+                return;
+            }
+            testManager.getHalMock().onPropertySet(value.value);
+        }
+
+        @Override
+        public VehiclePropValueParcelable onPropertyGet(int property) {
+            CarTestManager testManager = mTestManager.get();
+            if (testManager == null) {
+                return null;
+            }
+            VehiclePropValue value = testManager.getHalMock().onPropertyGet(property);
+            return new VehiclePropValueParcelable(value);
+        }
+
+        @Override
+        public void onPropertySubscribe(int property, int sampleRate) {
+            CarTestManager testManager = mTestManager.get();
+            if (testManager == null) {
+                return;
+            }
+            testManager.getHalMock().onPropertySubscribe(property, sampleRate);
+        }
+
+        @Override
+        public void onPropertyUnsubscribe(int property) {
+            CarTestManager testManager = mTestManager.get();
+            if (testManager == null) {
+                return;
+            }
+            testManager.getHalMock().onPropertyUnsubscribe(property);
+        }
+    }
+}
diff --git a/carsystemtest-lib/src/com/android/car/ICarTest.aidl b/carsystemtest-lib/src/com/android/car/ICarTest.aidl
new file mode 100644
index 0000000..23f0b42
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/ICarTest.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 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;
+
+import com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+
+/** @hide */
+interface ICarTest {
+    int getVersion()                                              = 0;
+    /** For testing only. inject events. */
+    void injectEvent(in VehiclePropValueParcelable value)         = 1;
+    /** For testing only. Start in mocking mode. */
+    void startMocking(in IVehicleNetworkHalMock mock)             = 2;
+    /** Finish mocking mode. */
+    void stopMocking(in IVehicleNetworkHalMock mock)              = 3;
+}
diff --git a/carsystemtest-lib/src/com/android/car/SystemTestApiCarServiceLoader.java b/carsystemtest-lib/src/com/android/car/SystemTestApiCarServiceLoader.java
new file mode 100644
index 0000000..2025748
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/SystemTestApiCarServiceLoader.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.Looper;
+import android.support.car.CarManagerBase;
+import android.support.car.ServiceConnectionListener;
+
+public class SystemTestApiCarServiceLoader extends SystemApiCarServiceLoader {
+
+    public SystemTestApiCarServiceLoader(Context context, ServiceConnectionListener listener,
+            Looper looper) {
+        super(context, listener, looper);
+    }
+
+    @Override
+    public CarManagerBase createCarManager(String serviceName, IBinder binder) {
+        switch (serviceName) {
+            case CarSystemTest.TEST_SERVICE:
+                return new CarTestManager(ICarTest.Stub.asInterface(binder));
+        }
+        return super.createCarManager(serviceName, binder);
+    }
+}
diff --git a/carsystemtest-lib/src/com/android/car/VehicleHalEmulator.java b/carsystemtest-lib/src/com/android/car/VehicleHalEmulator.java
new file mode 100644
index 0000000..25dc9b5
--- /dev/null
+++ b/carsystemtest-lib/src/com/android/car/VehicleHalEmulator.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.support.car.Car;
+import android.support.car.CarNotConnectedException;
+
+import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePermissionModel;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
+import com.android.car.vehiclenetwork.VehiclePropValueUtil;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+
+/**
+ * This is for mocking vehicle HAL and testing system's internal behavior.
+ * By default, emulated vehicle HAL will have all properties defined with default values
+ * returned for get call. For interested properties, each test can replace default behavior with
+ * {@link #addProperty(VehiclePropConfig, VehicleHalPropertyHandler)} or
+ * {@link #addStaticProperty(VehiclePropConfig, VehiclePropValue)}.
+ * To test a case where specific property should not be present, test can call
+ * {@link #removeProperty(int)}.
+ *
+ * Adding / removing properties should be done before calling {@link #start()} as the call will
+ * start emulating with properties added / removed up to now.
+ * @hide
+ */
+public class VehicleHalEmulator {
+
+    /**
+     * Interface for handler of each property.
+     */
+    public interface VehicleHalPropertyHandler {
+        void onPropertySet(VehiclePropValue value);
+        VehiclePropValue onPropertyGet(int property);
+        void onPropertySubscribe(int property, int sampleRate);
+        void onPropertyUnsubscribe(int property);
+    }
+
+    private final HashMap<Integer, VehicleHalProperty> mProperties =
+            new HashMap<Integer, VehicleHalProperty>();
+
+    private final CarTestManager mCarTestManager;
+    private final HalMock mMock = new HalMock();
+    private boolean mDefaultPropertiesPopulated = false;
+    private boolean mStarted = false;
+
+    /**
+     * Constructor. Car instance passed should be already connected to car service.
+     * @param car
+     */
+    public VehicleHalEmulator(Car car) {
+        try {
+            mCarTestManager = (CarTestManager) car.getCarManager(CarSystemTest.TEST_SERVICE);
+        } catch (CarNotConnectedException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * Add property to mocked vehicle hal.
+     * @param config
+     * @param handler
+     */
+    public synchronized void addProperty(VehiclePropConfig config,
+            VehicleHalPropertyHandler handler) {
+        populateDefaultPropertiesIfNecessary();
+        VehicleHalProperty halProp = new VehicleHalProperty(config, handler);
+        mProperties.put(config.getProp(), halProp);
+    }
+
+    /**
+     * Add static property to mocked vehicle hal.
+     * @param config
+     * @param value
+     */
+    public synchronized void addStaticProperty(VehiclePropConfig config, VehiclePropValue value) {
+        populateDefaultPropertiesIfNecessary();
+        DefaultPropertyHandler handler = new DefaultPropertyHandler(config, value);
+        VehicleHalProperty halProp = new VehicleHalProperty(config, handler);
+        mProperties.put(config.getProp(), halProp);
+    }
+
+    /**
+     * Remove this property from vehicle HAL properties. Emulated vehicle HAL will not have this
+     * property. This is useful to test the case where specific property is not present.
+     * @param property
+     */
+    public synchronized void removeProperty(int property) {
+        populateDefaultPropertiesIfNecessary();
+        mProperties.remove(property);
+    }
+
+    /**
+     * Start emulation. All necessary properties should have been added / removed before this.
+     */
+    public void start() {
+        mCarTestManager.startMocking(mMock);
+        synchronized (this) {
+            mStarted = true;
+        }
+    }
+
+    /** Whether emulation is started or not. */
+    public synchronized boolean isStarted() {
+        return mStarted;
+    }
+
+    /**
+     * Stop emulation. should be done before finishing test.
+     */
+    public void stop() {
+        mCarTestManager.stopMocking();
+        synchronized (this) {
+            mStarted = false;
+        }
+    }
+
+    public void injectEvent(VehiclePropValue value) {
+        mCarTestManager.injectEvent(value);
+    }
+
+    public static void assertPropertyForGet(VehiclePropConfig config, int property) {
+        assertProperty(config, property);
+        if ((config.getAccess() & VehiclePropAccess.VEHICLE_PROP_ACCESS_READ) == 0) {
+            throw new IllegalArgumentException("cannot set write-only property 0x" +
+                    Integer.toHexString(config.getProp()));
+        }
+    }
+
+    public static void assertPropertyForSet(VehiclePropConfig config, VehiclePropValue value) {
+        assertProperty(config, value.getProp());
+        if ((config.getAccess() & VehiclePropAccess.VEHICLE_PROP_ACCESS_WRITE) == 0) {
+            throw new IllegalArgumentException("cannot set read-only property 0x" +
+                    Integer.toHexString(config.getProp()));
+        }
+    }
+
+    public static void assertPropertyForSubscribe(VehiclePropConfig config, int property,
+            float sampleRate) {
+        assertPropertyForGet(config, property);
+        if (config.getChangeMode() == VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC) {
+            throw new IllegalStateException("cannot subscribe static property 0x" +
+                    Integer.toHexString(config.getProp()));
+        }
+    }
+
+    public static void assertProperty(VehiclePropConfig config, int property) {
+        if (config.getProp() != property) {
+            throw new IllegalStateException("Wrong prop, expecting 0x" +
+                    Integer.toHexString(config.getProp()) + " while got 0x" +
+                    Integer.toHexString(property));
+        }
+    }
+
+    private synchronized void populateDefaultPropertiesIfNecessary() {
+        if (mDefaultPropertiesPopulated) {
+            return;
+        }
+        for (Field f : VehicleNetworkConsts.class.getDeclaredFields()) {
+            if (f.getType() == int.class) {
+                int property = 0;
+                try {
+                    property = f.getInt(null);
+                } catch (IllegalAccessException e) {
+                    continue;
+                }
+                int valueType = VehicleNetworkConsts.getVehicleValueType(property);
+                if (valueType == VehicleValueType.VEHICLE_VALUE_TYPE_SHOUD_NOT_USE) {
+                    // invalid property or not a property
+                    continue;
+                }
+                int changeMode = VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC;
+                int[] changeModes = VehicleNetworkConsts.getVehicleChangeMode(property);
+                if (changeModes != null) {
+                    changeMode = changeModes[0];
+                }
+                int access = VehicleNetworkConsts.getVehicleAccess(property);
+                if (access == 0) { // invalid
+                    continue;
+                }
+                VehiclePropConfig config = VehiclePropConfig.newBuilder().
+                        setProp(property).
+                        setAccess(access).
+                        setChangeMode(changeMode).
+                        setValueType(valueType).
+                        setPermissionModel(
+                                VehiclePermissionModel.VEHICLE_PERMISSION_NO_RESTRICTION).
+                        setConfigFlags(0).
+                        setSampleRateMax(0).
+                        setSampleRateMin(0).
+                        build();
+                VehiclePropValue initialValue = VehiclePropValueUtil.createDummyValue(property,
+                        valueType);
+                DefaultPropertyHandler handler = new DefaultPropertyHandler(config, initialValue);
+                VehicleHalProperty halProp = new VehicleHalProperty(config, handler);
+                mProperties.put(property, halProp);
+            }
+        }
+        mDefaultPropertiesPopulated = true;
+    }
+
+    private synchronized VehiclePropConfigs handleListProperties() {
+        VehiclePropConfigs.Builder builder = VehiclePropConfigs.newBuilder();
+        for (VehicleHalProperty halProp : mProperties.values()) {
+            builder.addConfigs(halProp.config);
+        }
+        return builder.build();
+    }
+
+    private synchronized void handlePropertySet(VehiclePropValue value) {
+        getHalPropertyLocked(value.getProp()).handler.onPropertySet(value);
+    }
+
+    private synchronized VehiclePropValue handlePropertyGet(int property) {
+        return getHalPropertyLocked(property).handler.onPropertyGet(property);
+    }
+
+    private synchronized void handlePropertySubscribe(int property, int sampleRate) {
+        getHalPropertyLocked(property).handler.onPropertySubscribe(property, sampleRate);
+    }
+
+    private synchronized void handlePropertyUnsubscribe(int property) {
+        getHalPropertyLocked(property).handler.onPropertyUnsubscribe(property);
+    }
+
+    private VehicleHalProperty getHalPropertyLocked(int property) {
+        VehicleHalProperty halProp = mProperties.get(property);
+        if (halProp == null) {
+            throw new IllegalArgumentException();
+        }
+        return halProp;
+    }
+
+    private static class VehicleHalProperty {
+        public final VehiclePropConfig config;
+        public final VehicleHalPropertyHandler handler;
+
+        public VehicleHalProperty(VehiclePropConfig config, VehicleHalPropertyHandler handler) {
+            this.config = config;
+            this.handler = handler;
+        }
+    }
+
+    private static class DefaultPropertyHandler implements VehicleHalPropertyHandler {
+        private final VehiclePropConfig mConfig;
+        private VehiclePropValue mValue;
+        private boolean mSubscribed = false;
+
+        public DefaultPropertyHandler(VehiclePropConfig config, VehiclePropValue initialValue) {
+            mConfig = config;
+            mValue = initialValue;
+        }
+
+        @Override
+        public synchronized void onPropertySet(VehiclePropValue value) {
+            assertPropertyForSet(mConfig, value);
+            mValue = value;
+        }
+
+        @Override
+        public synchronized VehiclePropValue onPropertyGet(int property) {
+            assertPropertyForGet(mConfig, property);
+            return mValue;
+        }
+
+        @Override
+        public synchronized void onPropertySubscribe(int property, int sampleRate) {
+            assertPropertyForSubscribe(mConfig, property, sampleRate);
+            mSubscribed = true;
+        }
+
+        @Override
+        public synchronized void onPropertyUnsubscribe(int property) {
+            assertProperty(mConfig, property);
+            if (!mSubscribed) {
+                throw new IllegalArgumentException("unsubscibe for not subscribed property 0x" +
+                        Integer.toHexString(property));
+            }
+            mSubscribed = false;
+        }
+
+    }
+
+    private class HalMock implements VehicleNetworkHalMock {
+
+        @Override
+        public VehiclePropConfigs onListProperties() {
+            return handleListProperties();
+        }
+
+        @Override
+        public void onPropertySet(VehiclePropValue value) {
+            handlePropertySet(value);
+        }
+
+        @Override
+        public VehiclePropValue onPropertyGet(int property) {
+            return handlePropertyGet(property);
+        }
+
+        @Override
+        public void onPropertySubscribe(int property, int sampleRate) {
+            handlePropertySubscribe(property, sampleRate);
+        }
+
+        @Override
+        public void onPropertyUnsubscribe(int property) {
+            handlePropertyUnsubscribe(property);
+        }
+    }
+}
diff --git a/libvehiclenetwork/include/IVehicleNetwork.h b/libvehiclenetwork/include/IVehicleNetwork.h
index 5c5f84e..f577703 100644
--- a/libvehiclenetwork/include/IVehicleNetwork.h
+++ b/libvehiclenetwork/include/IVehicleNetwork.h
@@ -29,6 +29,7 @@
 #include <binder/Parcel.h>
 
 #include <VehicleNetworkDataTypes.h>
+#include <IVehicleNetworkHalMock.h>
 #include <IVehicleNetworkListener.h>
 
 namespace android {
@@ -50,6 +51,9 @@
     virtual status_t subscribe(const sp<IVehicleNetworkListener> &listener, int32_t property,
             float sampleRate) = 0;
     virtual void unsubscribe(const sp<IVehicleNetworkListener> &listener, int32_t property) = 0;
+    virtual status_t injectEvent(const vehicle_prop_value_t& value) = 0;
+    virtual status_t startMocking(const sp<IVehicleNetworkHalMock>& mock) = 0;
+    virtual void stopMocking(const sp<IVehicleNetworkHalMock>& mock) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libvehiclenetwork/include/IVehicleNetworkHalMock.h b/libvehiclenetwork/include/IVehicleNetworkHalMock.h
new file mode 100644
index 0000000..4311693
--- /dev/null
+++ b/libvehiclenetwork/include/IVehicleNetworkHalMock.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ANDROID_IVEHICLE_NETWORK_HAL_MOCK_H
+#define ANDROID_IVEHICLE_NETWORK_HAL_MOCK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+
+#include <VehicleNetworkDataTypes.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IVehicleNetworkHalMock : public IInterface
+{
+public:
+    static const char SERVICE_NAME[];
+    DECLARE_META_INTERFACE(VehicleNetworkHalMock);
+
+    virtual sp<VehiclePropertiesHolder> onListProperties() = 0;
+    virtual status_t onPropertySet(const vehicle_prop_value_t& value) = 0;
+    virtual status_t onPropertyGet(vehicle_prop_value_t* value) = 0;
+    virtual status_t onPropertySubscribe(int32_t property, float sampleRate) = 0;
+    virtual void onPropertyUnsubscribe(int32_t property) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnVehicleNetworkHalMock : public BnInterface<IVehicleNetworkHalMock>
+{
+    virtual status_t  onTransact(uint32_t code,
+                                 const Parcel& data,
+                                 Parcel* reply,
+                                 uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif /* ANDROID_IVEHICLE_NETWORK_HAL_MOCK_H */
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetwork.aidl b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetwork.aidl
index 1f5fec3..bfaf0d3 100644
--- a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetwork.aidl
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetwork.aidl
@@ -16,12 +16,12 @@
 
 package com.android.car.vehiclenetwork;
 
+import com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.IVehicleNetworkListener;
 import com.android.car.vehiclenetwork.VehiclePropConfigsParcelable;
 import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
 import com.android.car.vehiclenetwork.VehiclePropValuesParcelable;
 
-import com.android.car.vehiclenetwork.IVehicleNetworkListener;
-
 /**
   * Binder API to access vehicle network service.
   * @hide
@@ -34,5 +34,12 @@
     /** For error case, exception will be thrown. */
     void subscribe(in IVehicleNetworkListener listener, int property, float sampleRate)  = 3;
     void unsubscribe(in IVehicleNetworkListener listener, int property)                  = 4;
+    /** For testing only. inject events. */
+    void injectEvent(in VehiclePropValueParcelable value)                                = 5;
+    /** For testing only. Start in mocking mode. */
+    void startMocking(in IVehicleNetworkHalMock mock)                                    = 6;
+    /** Finish mocking mode. */
+    void stopMocking(in IVehicleNetworkHalMock mock)                                     = 7;
+
     //TODO add specialized set for byte array for efficiency
 }
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetworkHalMock.aidl b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetworkHalMock.aidl
new file mode 100644
index 0000000..d5187a8
--- /dev/null
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/IVehicleNetworkHalMock.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 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.vehiclenetwork;
+
+import com.android.car.vehiclenetwork.VehiclePropConfigsParcelable;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+
+/**
+ * Listener for vehicle HAL mock. This is used for internal testing only.
+ * @hide
+ */
+interface IVehicleNetworkHalMock {
+    VehiclePropConfigsParcelable onListProperties() = 0;
+    void onPropertySet(in VehiclePropValueParcelable value) = 1;
+    VehiclePropValueParcelable onPropertyGet(int property) = 2;
+    void onPropertySubscribe(int property, int sampleRate) = 3;
+    void onPropertyUnsubscribe(int property) = 4;
+}
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetwork.java b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetwork.java
index 7514c8c..b9cd870 100644
--- a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetwork.java
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetwork.java
@@ -27,6 +27,7 @@
 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValues;
+import com.android.internal.annotations.GuardedBy;
 
 import java.lang.ref.WeakReference;
 
@@ -35,10 +36,24 @@
  * not use this. All APIs will fail with security error if normal app tries this.
  */
 public class VehicleNetwork {
+    /**
+     * Listener for VNS events.
+     */
     public interface VehicleNetworkListener {
+        /**
+         * Notify HAL events. This requires subscribing the property
+         */
         void onVehicleNetworkEvents(VehiclePropValues values);
     }
 
+    public interface VehicleNetworkHalMock {
+        VehiclePropConfigs onListProperties();
+        void onPropertySet(VehiclePropValue value);
+        VehiclePropValue onPropertyGet(int property);
+        void onPropertySubscribe(int property, int sampleRate);
+        void onPropertyUnsubscribe(int property);
+    }
+
     private static final String TAG = VehicleNetwork.class.getSimpleName();
 
     private final IVehicleNetwork mService;
@@ -46,6 +61,10 @@
     private final IVehicleNetworkListenerImpl mVehicleNetworkListener;
     private final EventHandler mEventHandler;
 
+    @GuardedBy("this")
+    private VehicleNetworkHalMock mHalMock;
+    private IVehicleNetworkHalMock mHalMockImpl;
+
     public static VehicleNetwork createVehicleNetwork(VehicleNetworkListener listener,
             Looper looper) {
         IVehicleNetwork service = IVehicleNetwork.Stub.asInterface(ServiceManager.getService(
@@ -91,52 +110,28 @@
     }
 
     public void setIntProperty(int property, int value) {
-        VehiclePropValue v = VehiclePropValue.newBuilder().
-                setProp(property).
-                setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_INT32).
-                addInt32Values(value).
-                build();
+        VehiclePropValue v = VehiclePropValueUtil.createIntValue(property, value, 0);
         setProperty(v);
     }
 
     public void setIntVectorProperty(int property, int[] values) {
-        int len = values.length;
-        VehiclePropValue.Builder builder = VehiclePropValue.newBuilder().
-                setProp(property).
-                setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2 + len - 2);
-        for (int v : values) {
-            builder.addInt32Values(v);
-        }
-        setProperty(builder.build());
+        VehiclePropValue v = VehiclePropValueUtil.createIntVectorValue(property, values, 0);
+        setProperty(v);
     }
 
     public void setLongProperty(int property, long value) {
-        VehiclePropValue v = VehiclePropValue.newBuilder().
-                setProp(property).
-                setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_INT64).
-                setInt64Value(value).
-                build();
+        VehiclePropValue v = VehiclePropValueUtil.createLongValue(property, value, 0);
         setProperty(v);
     }
 
     public void setFloatProperty(int property, float value) {
-        VehiclePropValue v = VehiclePropValue.newBuilder().
-                setProp(property).
-                setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT).
-                addFloatValues(value).
-                build();
+        VehiclePropValue v = VehiclePropValueUtil.createFloatValue(property, value, 0);
         setProperty(v);
     }
 
     public void setFloatVectorProperty(int property, float[] values) {
-        int len = values.length;
-        VehiclePropValue.Builder builder = VehiclePropValue.newBuilder().
-                setProp(property).
-                setValueType(VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC2 + len - 2);
-        for (float v : values) {
-            builder.addFloatValues(v);
-        }
-        setProperty(builder.build());
+        VehiclePropValue v = VehiclePropValueUtil.createFloatVectorValue(property, values, 0);
+        setProperty(v);
     }
 
     public VehiclePropValue getProperty(int property) {
@@ -274,6 +269,63 @@
         }
     }
 
+    public synchronized void injectEvent(VehiclePropValue value) {
+        try {
+            mService.injectEvent(new VehiclePropValueParcelable(value));
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        }
+    }
+
+    public synchronized void startMocking(VehicleNetworkHalMock mock) {
+        mHalMock = mock;
+        mHalMockImpl = new IVehicleNetworkHalMockImpl(this);
+        try {
+            mService.startMocking(mHalMockImpl);
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        }
+    }
+
+    public synchronized void stopMocking() {
+        try {
+            mService.stopMocking(mHalMockImpl);
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        } finally {
+            mHalMock = null;
+            mHalMockImpl = null;
+        }
+    }
+
+    public synchronized void startMocking(IVehicleNetworkHalMock mock) {
+        mHalMock = null;
+        mHalMockImpl = mock;
+        try {
+            mService.startMocking(mHalMockImpl);
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        }
+    }
+
+    public synchronized void stopMocking(IVehicleNetworkHalMock mock) {
+        if (mock.asBinder() != mHalMockImpl.asBinder()) {
+            return;
+        }
+        try {
+            mService.stopMocking(mHalMockImpl);
+        } catch (RemoteException e) {
+            handleRemoteException(e);
+        } finally {
+            mHalMock = null;
+            mHalMockImpl = null;
+        }
+    }
+
+    private synchronized VehicleNetworkHalMock getHalMock() {
+        return mHalMock;
+    }
+
     private void handleRemoteException(RemoteException e) {
         throw new RuntimeException("Vehicle network service not working ", e);
     }
@@ -326,4 +378,59 @@
             }
         }
     }
+
+    private static class IVehicleNetworkHalMockImpl extends IVehicleNetworkHalMock.Stub {
+        private final WeakReference<VehicleNetwork> mVehicleNetwork;
+
+        private IVehicleNetworkHalMockImpl(VehicleNetwork vehicleNewotk) {
+            mVehicleNetwork = new WeakReference<VehicleNetwork>(vehicleNewotk);
+        }
+
+        @Override
+        public VehiclePropConfigsParcelable onListProperties() {
+            VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+            if (vehicleNetwork == null) {
+                return null;
+            }
+            VehiclePropConfigs configs = vehicleNetwork.getHalMock().onListProperties();
+            return new VehiclePropConfigsParcelable(configs);
+        }
+
+        @Override
+        public void onPropertySet(VehiclePropValueParcelable value) {
+            VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+            if (vehicleNetwork == null) {
+                return;
+            }
+            vehicleNetwork.getHalMock().onPropertySet(value.value);
+        }
+
+        @Override
+        public VehiclePropValueParcelable onPropertyGet(int property) {
+            VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+            if (vehicleNetwork == null) {
+                return null;
+            }
+            VehiclePropValue value = vehicleNetwork.getHalMock().onPropertyGet(property);
+            return new VehiclePropValueParcelable(value);
+        }
+
+        @Override
+        public void onPropertySubscribe(int property, int sampleRate) {
+            VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+            if (vehicleNetwork == null) {
+                return;
+            }
+            vehicleNetwork.getHalMock().onPropertySubscribe(property, sampleRate);
+        }
+
+        @Override
+        public void onPropertyUnsubscribe(int property) {
+            VehicleNetwork vehicleNetwork = mVehicleNetwork.get();
+            if (vehicleNetwork == null) {
+                return;
+            }
+            vehicleNetwork.getHalMock().onPropertyUnsubscribe(property);
+        }
+    }
 }
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetworkConsts.java b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetworkConsts.java
index 2938f00..529e04b 100644
--- a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetworkConsts.java
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehicleNetworkConsts.java
@@ -46,6 +46,7 @@
 public static final int VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP = 0x00000703;
 public static final int VEHICLE_PROPERTY_AUDIO_FOCUS = 0x00000900;
 public static final int VEHICLE_PROPERTY_AUDIO_VOLUME = 0x00000901;
+public static final int VEHICLE_PROPERTY_AP_POWER_STATE = 0x00000A00;
 public static final int VEHICLE_PROPERTY_CUSTOM_START = 0xf0000000;
 public static final int VEHICLE_PROPERTY_CUSTOM_END = 0xf7ffffff;
 public static final int VEHICLE_PROPERTY_INTERNAL_START = 0xf8000000;
@@ -78,6 +79,7 @@
 case VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP: return VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT;
 case VEHICLE_PROPERTY_AUDIO_FOCUS: return VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
 case VEHICLE_PROPERTY_AUDIO_VOLUME: return VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
+case VEHICLE_PROPERTY_AP_POWER_STATE: return VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
 case VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: return VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2;
 default: return VehicleValueType.VEHICLE_VALUE_TYPE_SHOUD_NOT_USE;
 }
@@ -109,12 +111,79 @@
 case VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP: return "VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP";
 case VEHICLE_PROPERTY_AUDIO_FOCUS: return "VEHICLE_PROPERTY_AUDIO_FOCUS";
 case VEHICLE_PROPERTY_AUDIO_VOLUME: return "VEHICLE_PROPERTY_AUDIO_VOLUME";
+case VEHICLE_PROPERTY_AP_POWER_STATE: return "VEHICLE_PROPERTY_AP_POWER_STATE";
 case VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: return "VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE";
 default: return "UNKNOWN_PROPERTY";
 }
 }
 
-public static class VehicleAudioFocusRequestType {
+public static int[] getVehicleChangeMode(int property) {
+switch (property) {
+case VEHICLE_PROPERTY_INFO_VIN: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_INFO_MAKE: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_INFO_MODEL: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_INFO_MODEL_YEAR: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_INFO_FUEL_CAPACITY: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC };
+case VEHICLE_PROPERTY_PERF_ODOMETER: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_PERF_VEHICLE_SPEED: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_ENGINE_COOLANT_TEMP: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_ENGINE_OIL_TEMP: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_ENGINE_RPM: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_GEAR_SELECTION: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_CURRENT_GEAR: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_PARKING_BRAKE_ON: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_DRIVING_STATUS: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_FUEL_LEVEL_LOW: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_NIGHT_MODE: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_HVAC_FAN_SPEED: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_HVAC_FAN_DIRECTION: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_HVAC_TEMPERATURE_CURRENT: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_HVAC_DEFROSTER: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_HVAC_AC_ON: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE , VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_CONTINUOUS };
+case VEHICLE_PROPERTY_AUDIO_FOCUS: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_AUDIO_VOLUME: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_AP_POWER_STATE: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+case VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: return new int[] { VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE };
+default: return null;
+}
+}
+
+public static int getVehicleAccess(int property) {
+switch (property) {
+case VEHICLE_PROPERTY_INFO_VIN: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_INFO_MAKE: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_INFO_MODEL: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_INFO_MODEL_YEAR: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_INFO_FUEL_CAPACITY: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_PERF_ODOMETER: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_PERF_VEHICLE_SPEED: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_ENGINE_COOLANT_TEMP: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_ENGINE_OIL_TEMP: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_ENGINE_RPM: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_GEAR_SELECTION: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_CURRENT_GEAR: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_PARKING_BRAKE_ON: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_DRIVING_STATUS: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_FUEL_LEVEL_LOW: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_NIGHT_MODE: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_HVAC_FAN_SPEED: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_FAN_DIRECTION: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_TEMPERATURE_CURRENT: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_TEMPERATURE_SET: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_DEFROSTER: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_HVAC_AC_ON: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_ENV_OUTSIDE_TEMP: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ;
+case VEHICLE_PROPERTY_AUDIO_FOCUS: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_AUDIO_VOLUME: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_AP_POWER_STATE: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+case VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: return VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE;
+default: return 0;
+}
+}
+
+public static class VehicleAudioFocusRequest {
 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN = 0x1;
 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT = 0x2;
 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3;
@@ -130,7 +199,7 @@
 }
 }
 
-public static class VehicleAudioFocusStateType {
+public static class VehicleAudioFocusState {
 public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN = 0x1;
 public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT = 0x2;
 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3;
@@ -150,21 +219,21 @@
 }
 }
 
-public static class VehicleAudioStreamFlagType {
-public static final int VEHICLE_AUDIO_STREAM_FLAG_DEFAULT = (0x1<<0);
-public static final int VEHICLE_AUDIO_STREAM_FLAG_MEDIA = (0x1<<1);
-public static final int VEHICLE_AUDIO_STREAM_FLAG_STREAM2 = (0x1<<2);
+public static class VehicleAudioStreamFlag {
+public static final int VEHICLE_AUDIO_STREAM_DEFAULT_FLAG = (0x1<<0);
+public static final int VEHICLE_AUDIO_STREAM_MEDIA_FLAG = (0x1<<1);
+public static final int VEHICLE_AUDIO_STREAM_STREAM2_FLAG = (0x1<<2);
 public static String enumToString(int v) {
 switch(v) {
-case VEHICLE_AUDIO_STREAM_FLAG_DEFAULT: return "VEHICLE_AUDIO_STREAM_FLAG_DEFAULT";
-case VEHICLE_AUDIO_STREAM_FLAG_MEDIA: return "VEHICLE_AUDIO_STREAM_FLAG_MEDIA";
-case VEHICLE_AUDIO_STREAM_FLAG_STREAM2: return "VEHICLE_AUDIO_STREAM_FLAG_STREAM2";
+case VEHICLE_AUDIO_STREAM_DEFAULT_FLAG: return "VEHICLE_AUDIO_STREAM_DEFAULT_FLAG";
+case VEHICLE_AUDIO_STREAM_MEDIA_FLAG: return "VEHICLE_AUDIO_STREAM_MEDIA_FLAG";
+case VEHICLE_AUDIO_STREAM_STREAM2_FLAG: return "VEHICLE_AUDIO_STREAM_STREAM2_FLAG";
 default: return "UNKNOWN";
 }
 }
 }
 
-public static class VehicleAudioStreamType {
+public static class VehicleAudioStream {
 public static final int VEHICLE_AUDIO_STREAM_DEFAULT = 0;
 public static final int VEHICLE_AUDIO_STREAM_MEDIA = 1;
 public static String enumToString(int v) {
@@ -176,6 +245,72 @@
 }
 }
 
+public static class VehicleApPowerStateConfigFlag {
+public static final int VEHICLE_AP_POWER_STATE_CONFIG_ENABLE_DEEP_SLEEP_FLAG = 0x1;
+public static final int VEHICLE_AP_POWER_STATE_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 0x2;
+public static String enumToString(int v) {
+switch(v) {
+case VEHICLE_AP_POWER_STATE_CONFIG_ENABLE_DEEP_SLEEP_FLAG: return "VEHICLE_AP_POWER_STATE_CONFIG_ENABLE_DEEP_SLEEP_FLAG";
+case VEHICLE_AP_POWER_STATE_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG: return "VEHICLE_AP_POWER_STATE_CONFIG_SUPPORT_TIMER_POWER_ON_FLAG";
+default: return "UNKNOWN";
+}
+}
+}
+
+public static class VehicleApPowerState {
+public static final int VEHICLE_AP_POWER_STATE_OFF = 0;
+public static final int VEHICLE_AP_POWER_STATE_DEEP_SLEEP = 1;
+public static final int VEHICLE_AP_POWER_STATE_ON_DISP_OFF = 2;
+public static final int VEHICLE_AP_POWER_STATE_ON_FULL = 3;
+public static final int VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE = 4;
+public static String enumToString(int v) {
+switch(v) {
+case VEHICLE_AP_POWER_STATE_OFF: return "VEHICLE_AP_POWER_STATE_OFF";
+case VEHICLE_AP_POWER_STATE_DEEP_SLEEP: return "VEHICLE_AP_POWER_STATE_DEEP_SLEEP";
+case VEHICLE_AP_POWER_STATE_ON_DISP_OFF: return "VEHICLE_AP_POWER_STATE_ON_DISP_OFF";
+case VEHICLE_AP_POWER_STATE_ON_FULL: return "VEHICLE_AP_POWER_STATE_ON_FULL";
+case VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE: return "VEHICLE_AP_POWER_STATE_SHUTDOWN_PREPARE";
+default: return "UNKNOWN";
+}
+}
+}
+
+public static class VehicleApPowerStateShutdownParam {
+public static final int VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_IMMEDIATELY = 1;
+public static final int VEHICLE_AP_POWER_SHUTDOWN_PARAM_CAN_SLEEP = 2;
+public static final int VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_ONLY = 3;
+public static String enumToString(int v) {
+switch(v) {
+case VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_IMMEDIATELY: return "VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_IMMEDIATELY";
+case VEHICLE_AP_POWER_SHUTDOWN_PARAM_CAN_SLEEP: return "VEHICLE_AP_POWER_SHUTDOWN_PARAM_CAN_SLEEP";
+case VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_ONLY: return "VEHICLE_AP_POWER_SHUTDOWN_PARAM_SHUTDOWN_ONLY";
+default: return "UNKNOWN";
+}
+}
+}
+
+public static class VehicleApPowerSetState {
+public static final int VEHICLE_AP_POWER_SET_BOOT_COMPLETE = 0x1;
+public static final int VEHICLE_AP_POWER_SET_DEEP_SLEEP_ENTRY = 0x2;
+public static final int VEHICLE_AP_POWER_SET_DEEP_SLEEP_EXIT = 0x3;
+public static final int VEHICLE_AP_POWER_SET_SHUTDOWN_POSTPONE = 0x4;
+public static final int VEHICLE_AP_POWER_SET_SHUTDOWN_READY = 0x5;
+public static final int VEHICLE_AP_POWER_SET_DISPLAY_OFF = 0x6;
+public static final int VEHICLE_AP_POWER_SET_DISPLAY_ON = 0x7;
+public static String enumToString(int v) {
+switch(v) {
+case VEHICLE_AP_POWER_SET_BOOT_COMPLETE: return "VEHICLE_AP_POWER_SET_BOOT_COMPLETE";
+case VEHICLE_AP_POWER_SET_DEEP_SLEEP_ENTRY: return "VEHICLE_AP_POWER_SET_DEEP_SLEEP_ENTRY";
+case VEHICLE_AP_POWER_SET_DEEP_SLEEP_EXIT: return "VEHICLE_AP_POWER_SET_DEEP_SLEEP_EXIT";
+case VEHICLE_AP_POWER_SET_SHUTDOWN_POSTPONE: return "VEHICLE_AP_POWER_SET_SHUTDOWN_POSTPONE";
+case VEHICLE_AP_POWER_SET_SHUTDOWN_READY: return "VEHICLE_AP_POWER_SET_SHUTDOWN_READY";
+case VEHICLE_AP_POWER_SET_DISPLAY_OFF: return "VEHICLE_AP_POWER_SET_DISPLAY_OFF";
+case VEHICLE_AP_POWER_SET_DISPLAY_ON: return "VEHICLE_AP_POWER_SET_DISPLAY_ON";
+default: return "UNKNOWN";
+}
+}
+}
+
 public static class VehicleValueType {
 public static final int VEHICLE_VALUE_TYPE_SHOUD_NOT_USE = 0x00;
 public static final int VEHICLE_VALUE_TYPE_STRING = 0x01;
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropConfigUtil.java b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropConfigUtil.java
new file mode 100644
index 0000000..4e7137f
--- /dev/null
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropConfigUtil.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 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.vehiclenetwork;
+
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePermissionModel;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
+
+/**
+ * Utility class to help creating VehiclePropConfig.
+ */
+public class VehiclePropConfigUtil {
+
+    public static VehiclePropConfig createStaticStringProperty(int property) {
+        return getBuilder(property,
+                VehiclePropAccess.VEHICLE_PROP_ACCESS_READ,
+                VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_STATIC,
+                VehicleValueType.VEHICLE_VALUE_TYPE_STRING,
+                VehiclePermissionModel.VEHICLE_PERMISSION_NO_RESTRICTION,
+                0, 0f, 0f).
+                build();
+    }
+
+    public static VehiclePropConfig.Builder getBuilder(int property, int access, int changeMode,
+            int type, int permissionModel, int configFlags, float sampleRateMax,
+            float sampleRateMin) {
+        return VehiclePropConfig.newBuilder().
+                setProp(property).
+                setAccess(access).
+                setChangeMode(changeMode).
+                setValueType(type).
+                setPermissionModel(permissionModel).
+                setConfigFlags(configFlags).
+                setSampleRateMax(sampleRateMax).
+                setSampleRateMin(sampleRateMin);
+    }
+}
diff --git a/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropValueUtil.java b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropValueUtil.java
new file mode 100644
index 0000000..2b72163
--- /dev/null
+++ b/libvehiclenetwork/java/src/com/android/car/vehiclenetwork/VehiclePropValueUtil.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2015 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.vehiclenetwork;
+
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
+import com.android.car.vehiclenetwork.VehicleNetworkProto.ZonedValue;
+import com.google.protobuf.ByteString;
+
+/**
+ * Utility class to help creating VehiclePropValue.
+ */
+public class VehiclePropValueUtil {
+
+    public static VehiclePropValue createIntValue(int property, int value, long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_INT32,timestamp).
+                addInt32Values(value).
+                build();
+    }
+
+    public static VehiclePropValue createIntVectorValue(int property, int[] values,
+            long timestamp) {
+        int len = values.length;
+        VehiclePropValue.Builder builder =createBuilder(property,
+                VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2 + len - 2,
+                timestamp);
+        for (int v : values) {
+            builder.addInt32Values(v);
+        }
+        return builder.build();
+    }
+
+    public static VehiclePropValue createFloatValue(int property, float value, long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT,timestamp).
+                addFloatValues(value).
+                build();
+    }
+
+    public static VehiclePropValue createFloatVectorValue(int property, float[] values,
+            long timestamp) {
+        int len = values.length;
+        VehiclePropValue.Builder builder =createBuilder(property,
+                VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC2 + len - 2,
+                timestamp);
+        for (float v : values) {
+            builder.addFloatValues(v);
+        }
+        return builder.build();
+    }
+
+    public static VehiclePropValue createLongValue(int property, long value, long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_INT64,timestamp).
+                setInt64Value(value).
+                build();
+    }
+
+    public static VehiclePropValue createStringValue(int property, String value, long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_STRING,timestamp).
+                setStringValue(value).
+                build();
+    }
+
+    public static VehiclePropValue createBooleanValue(int property, boolean value, long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_BOOLEAN,timestamp).
+                addInt32Values(value ? 1 : 0).
+                build();
+    }
+
+    public static VehiclePropValue createBytesValue(int property, byte[] value, long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_BYTES,timestamp).
+                setBytesValue(ByteString.copyFrom(value)).
+                build();
+    }
+
+    public static VehiclePropValue createZonedIntValue(int property, int zone, int value,
+            long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_INT32,timestamp).
+                setZonedValue(ZonedValue.newBuilder().setZoneOrWindow(zone).setInt32Value(value).
+                        build()).
+                build();
+    }
+
+    public static VehiclePropValue createZonedBooleanValue(int property, int zone, boolean value,
+            long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_BOOLEAN,timestamp).
+                setZonedValue(ZonedValue.newBuilder().setZoneOrWindow(zone).
+                        setInt32Value(value ? 1 : 0).build()).
+                build();
+    }
+
+    public static VehiclePropValue createZonedFloatValue(int property, int zone, float value,
+            long timestamp) {
+        return createBuilder(property, VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT,timestamp).
+                setZonedValue(ZonedValue.newBuilder().setZoneOrWindow(zone).setFloatValue(value).
+                        build()).
+                build();
+    }
+
+    public static VehiclePropValue createDummyValue(int property, int valueType) {
+        switch (valueType) {
+            case VehicleValueType.VEHICLE_VALUE_TYPE_STRING: {
+                return createStringValue(property, "dummy", 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_BYTES: {
+                return createBytesValue(property, new byte[1], 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_BOOLEAN: {
+                return createBooleanValue(property, false, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_INT32: {
+                return createZonedIntValue(property, 0, 0, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_FLOAT: {
+                return createZonedFloatValue(property, 0, 0, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_ZONED_BOOLEAN: {
+                return createZonedBooleanValue(property, 0, false, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_INT64: {
+                return createLongValue(property, 0, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT: {
+                return createFloatValue(property, 0, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC2: {
+                return createFloatVectorValue(property, new float[] {0, 0}, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC3: {
+                return createFloatVectorValue(property, new float[] {0, 0, 0}, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_FLOAT_VEC4: {
+                return createFloatVectorValue(property, new float[] {0, 0, 0, 0}, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_INT32: {
+                return createIntValue(property, 0, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2: {
+                return createIntVectorValue(property, new int[] {0, 0}, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC3: {
+                return createIntVectorValue(property, new int[] {0, 0, 0}, 0);
+            }
+            case VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4: {
+                return createIntVectorValue(property, new int[] {0, 0, 0, 0}, 0);
+            }
+        }
+        return null;
+    }
+
+    public static VehiclePropValue.Builder createBuilder(int property, int valueType,
+            long timestamp) {
+        return VehiclePropValue.newBuilder().
+                setProp(property).
+                setValueType(valueType).
+                setTimestamp(timestamp);
+    }
+}
diff --git a/libvehiclenetwork/native/IVehicleNetwork.cpp b/libvehiclenetwork/native/IVehicleNetwork.cpp
index a3b17a5..388715d 100644
--- a/libvehiclenetwork/native/IVehicleNetwork.cpp
+++ b/libvehiclenetwork/native/IVehicleNetwork.cpp
@@ -37,6 +37,9 @@
     GET_PROPERTY,
     SUBSCRIBE,
     UNSUBSCRIBE,
+    INJECT_EVENT,
+    START_MOCKING,
+    STOP_MOCKING,
 };
 
 // ----------------------------------------------------------------------------
@@ -163,6 +166,41 @@
             ALOGI("unsubscribing property %d failed %d", property, status);
         }
     }
+
+    virtual status_t injectEvent(const vehicle_prop_value_t& value) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+        data.writeInt32(1); // 0 means no value. For compatibility with aidl based code.
+        std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+        ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+        VehicleNetworkProtoUtil::toVehiclePropValue(value, *v.get());
+        int size = v->ByteSize();
+        WritableBlobHolder blob(new Parcel::WritableBlob());
+        ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+        data.writeInt32(size);
+        data.writeBlob(size, false, blob.blob);
+        v->SerializeToArray(blob.blob->data(), size);
+        status_t status = remote()->transact(INJECT_EVENT, data, &reply);
+        return status;
+    }
+
+    virtual status_t startMocking(const sp<IVehicleNetworkHalMock>& mock) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(mock));
+        status_t status = remote()->transact(START_MOCKING, data, &reply);
+        return status;
+    }
+
+    virtual void stopMocking(const sp<IVehicleNetworkHalMock>& mock) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IVehicleNetwork::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(mock));
+        status_t status = remote()->transact(STOP_MOCKING, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGI("stop mocking failed %d", status);
+        }
+    }
 };
 
 IMPLEMENT_META_INTERFACE(VehicleNetwork, IVehicleNetwork::SERVICE_NAME);
@@ -280,6 +318,51 @@
             BinderUtil::fillNoResultReply(reply);
             return NO_ERROR;
         } break;
+        case INJECT_EVENT: {
+            CHECK_INTERFACE(IVehicleNetwork, data, reply);
+            if (data.readInt32() == 0) { // java side allows passing null with this.
+                return BAD_VALUE;
+            }
+            ScopedVehiclePropValue value;
+            ReadableBlobHolder blob(new Parcel::ReadableBlob());
+            ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+            int32_t size = data.readInt32();
+            r = data.readBlob(size, blob.blob);
+            if (r != NO_ERROR) {
+                ALOGE("injectEvent:service, cannot read blob");
+                return r;
+            }
+            std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+            ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+            if (!v->ParseFromArray(blob.blob->data(), size)) {
+                ALOGE("injectEvent:service, cannot parse data");
+                return BAD_VALUE;
+            }
+            r = VehicleNetworkProtoUtil::fromVehiclePropValue(*v.get(), value.value);
+            if (r != NO_ERROR) {
+                ALOGE("injectEvent:service, cannot convert data");
+                return BAD_VALUE;
+            }
+            r = injectEvent(value.value);
+            BinderUtil::fillNoResultReply(reply);
+            return r;
+        } break;
+        case START_MOCKING: {
+            CHECK_INTERFACE(IVehicleNetwork, data, reply);
+            sp<IVehicleNetworkHalMock> mock =
+                    interface_cast<IVehicleNetworkHalMock>(data.readStrongBinder());
+            r = startMocking(mock);
+            BinderUtil::fillNoResultReply(reply);
+            return r;
+        } break;
+        case STOP_MOCKING: {
+            CHECK_INTERFACE(IVehicleNetwork, data, reply);
+            sp<IVehicleNetworkHalMock> mock =
+                    interface_cast<IVehicleNetworkHalMock>(data.readStrongBinder());
+            stopMocking(mock);
+            BinderUtil::fillNoResultReply(reply);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libvehiclenetwork/native/IVehicleNetworkHalMock.cpp b/libvehiclenetwork/native/IVehicleNetworkHalMock.cpp
new file mode 100644
index 0000000..8652f17
--- /dev/null
+++ b/libvehiclenetwork/native/IVehicleNetworkHalMock.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "VehicleNetwork"
+
+#include <memory>
+
+#include <binder/IPCThreadState.h>
+#include <private/android_filesystem_config.h>
+
+#include <utils/Log.h>
+
+#include <IVehicleNetwork.h>
+#include <IVehicleNetworkHalMock.h>
+#include <VehicleNetworkProto.pb.h>
+
+#include "BinderUtil.h"
+#include "VehicleNetworkProtoUtil.h"
+
+namespace android {
+
+enum {
+    ON_LIST_PROPERTIES = IBinder::FIRST_CALL_TRANSACTION,
+    ON_PROPERTY_SET,
+    ON_PROPERTY_GET,
+    ON_SUBSCRIBE,
+    ON_UNSUBSCRIBE,
+};
+
+// ----------------------------------------------------------------------------
+
+const char IVehicleNetworkHalMock::SERVICE_NAME[] =
+        "com.android.car.vehiclenetwork.IVehicleNetworkHalMock";
+
+// ----------------------------------------------------------------------------
+
+class BpVehicleNetworkHalMock : public BpInterface<IVehicleNetworkHalMock> {
+public:
+    BpVehicleNetworkHalMock(const sp<IBinder> & impl)
+        : BpInterface<IVehicleNetworkHalMock>(impl) {
+    }
+
+    virtual sp<VehiclePropertiesHolder> onListProperties() {
+        sp<VehiclePropertiesHolder> holder;
+        Parcel data, reply;
+        data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+        status_t status = remote()->transact(ON_LIST_PROPERTIES, data, &reply);
+        if (status == NO_ERROR) {
+            reply.readExceptionCode(); // for compatibility with java
+            if (reply.readInt32() == 0) { // no result
+                return holder;
+            }
+            ReadableBlobHolder blob(new Parcel::ReadableBlob());
+            if (blob.blob == NULL) {
+                ALOGE("listProperties, no memory");
+                return holder;
+            }
+            int32_t size = reply.readInt32();
+            status = reply.readBlob(size, blob.blob);
+            if (status != NO_ERROR) {
+                ALOGE("listProperties, cannot read blob %d", status);
+                return holder;
+            }
+            //TODO make this more memory efficient
+            std::unique_ptr<VehiclePropConfigs> configs(new VehiclePropConfigs());
+            if (configs.get() == NULL) {
+                return holder;
+            }
+            if(!configs->ParseFromArray(blob.blob->data(), size)) {
+                ALOGE("listProperties, cannot parse reply");
+                return holder;
+            }
+            holder = new VehiclePropertiesHolder();
+            ASSERT_OR_HANDLE_NO_MEMORY(holder.get(), return);
+            status = VehicleNetworkProtoUtil::fromVehiclePropConfigs(*configs.get(),
+                    holder->getList());
+            if (status != NO_ERROR) {
+                ALOGE("listProperties, cannot convert VehiclePropConfigs %d", status);
+                return holder;
+            }
+
+        }
+        return holder;
+    }
+
+    virtual status_t onPropertySet(const vehicle_prop_value_t& value) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+        data.writeInt32(1); // 0 means no value. For compatibility with aidl based code.
+        std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+        ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+        VehicleNetworkProtoUtil::toVehiclePropValue(value, *v.get());
+        int size = v->ByteSize();
+        WritableBlobHolder blob(new Parcel::WritableBlob());
+        ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+        data.writeInt32(size);
+        data.writeBlob(size, false, blob.blob);
+        v->SerializeToArray(blob.blob->data(), size);
+        status_t status = remote()->transact(ON_PROPERTY_SET, data, &reply);
+        return status;
+    }
+
+    virtual status_t onPropertyGet(vehicle_prop_value_t* value) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+        // only needs to send property itself.
+        data.writeInt32(value->prop);
+        status_t status = remote()->transact(ON_PROPERTY_GET, data, &reply);
+        if (status == NO_ERROR) {
+            reply.readExceptionCode(); // for compatibility with java
+            if (reply.readInt32() == 0) { // no result
+                return BAD_VALUE;
+            }
+            ReadableBlobHolder blob(new Parcel::ReadableBlob());
+            ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+            int32_t size = reply.readInt32();
+            status = reply.readBlob(size, blob.blob);
+            if (status != NO_ERROR) {
+                ALOGE("getProperty, cannot read blob");
+                return status;
+            }
+            std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+            ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+            if (!v->ParseFromArray(blob.blob->data(), size)) {
+                ALOGE("getProperty, cannot parse reply");
+                return BAD_VALUE;
+            }
+            status = VehicleNetworkProtoUtil::fromVehiclePropValue(*v.get(), *value);
+        }
+        return status;
+    }
+
+    virtual status_t onPropertySubscribe(int32_t property, float sampleRate) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+        data.writeInt32(property);
+        data.writeFloat(sampleRate);
+        status_t status = remote()->transact(ON_SUBSCRIBE, data, &reply);
+        return status;
+    }
+
+    virtual void onPropertyUnsubscribe(int32_t property) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IVehicleNetworkHalMock::getInterfaceDescriptor());
+        data.writeInt32(property);
+        status_t status = remote()->transact(ON_UNSUBSCRIBE, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGI("onPropertyUnsubscribe property %d failed %d", property, status);
+        }
+    }
+};
+
+IMPLEMENT_META_INTERFACE(VehicleNetworkHalMock, IVehicleNetworkHalMock::SERVICE_NAME);
+
+// ----------------------------------------------------------------------
+
+static bool isSystemUser() {
+    uid_t uid =  IPCThreadState::self()->getCallingUid();
+    switch (uid) {
+        // This list will be expanded. Only those UIDs are allowed to access vehicle network
+        // for now. There can be per property based UID check built-in as well.
+        case AID_ROOT:
+        case AID_SYSTEM:
+        case AID_AUDIO: {
+            return true;
+        } break;
+        default: {
+            ALOGE("non-system user tried access, uid %d", uid);
+        } break;
+    }
+    return false;
+}
+
+status_t BnVehicleNetworkHalMock::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags) {
+    if (!isSystemUser()) {
+        return PERMISSION_DENIED;
+    }
+    status_t r;
+    switch (code) {
+        case ON_LIST_PROPERTIES: {
+            CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+            sp<VehiclePropertiesHolder> holder = onListProperties();
+            if (holder.get() == NULL) { // given property not found
+                BinderUtil::fillObjectResultReply(reply, false /* isValid */);
+                return NO_ERROR;
+            }
+            std::unique_ptr<VehiclePropConfigs> configs(new VehiclePropConfigs());
+            ASSERT_OR_HANDLE_NO_MEMORY(configs.get(), return NO_MEMORY);
+            VehicleNetworkProtoUtil::toVehiclePropConfigs(holder->getList(), *configs.get());
+            int size = configs->ByteSize();
+            WritableBlobHolder blob(new Parcel::WritableBlob());
+            ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+            BinderUtil::fillObjectResultReply(reply, true);
+            reply->writeInt32(size);
+            reply->writeBlob(size, false, blob.blob);
+            configs->SerializeToArray(blob.blob->data(), size);
+            return NO_ERROR;
+        } break;
+        case ON_PROPERTY_SET: {
+            CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+            if (data.readInt32() == 0) { // java side allows passing null with this.
+                return BAD_VALUE;
+            }
+            ScopedVehiclePropValue value;
+            ReadableBlobHolder blob(new Parcel::ReadableBlob());
+            ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+            int32_t size = data.readInt32();
+            r = data.readBlob(size, blob.blob);
+            if (r != NO_ERROR) {
+                ALOGE("setProperty:service, cannot read blob");
+                return r;
+            }
+            std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+            ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+            if (!v->ParseFromArray(blob.blob->data(), size)) {
+                ALOGE("setProperty:service, cannot parse data");
+                return BAD_VALUE;
+            }
+            r = VehicleNetworkProtoUtil::fromVehiclePropValue(*v.get(), value.value);
+            if (r != NO_ERROR) {
+                ALOGE("setProperty:service, cannot convert data");
+                return BAD_VALUE;
+            }
+            r = onPropertySet(value.value);
+            BinderUtil::fillNoResultReply(reply);
+            return r;
+        } break;
+        case ON_PROPERTY_GET: {
+            CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+            ScopedVehiclePropValue value;
+            value.value.prop = data.readInt32();
+            r = onPropertyGet(&(value.value));
+            if (r == NO_ERROR) {
+                BinderUtil::fillObjectResultReply(reply, true);
+                std::unique_ptr<VehiclePropValue> v(new VehiclePropValue());
+                ASSERT_OR_HANDLE_NO_MEMORY(v.get(), return NO_MEMORY);
+                VehicleNetworkProtoUtil::toVehiclePropValue(value.value, *v.get());
+                int size = v->ByteSize();
+                WritableBlobHolder blob(new Parcel::WritableBlob());
+                ASSERT_OR_HANDLE_NO_MEMORY(blob.blob, return NO_MEMORY);
+                reply->writeInt32(size);
+                reply->writeBlob(size, false, blob.blob);
+                v->SerializeToArray(blob.blob->data(), size);
+            }
+            return r;
+        } break;
+        case ON_SUBSCRIBE: {
+            CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+            int32_t property = data.readInt32();
+            float sampleRate = data.readFloat();
+            r = onPropertySubscribe(property, sampleRate);
+            BinderUtil::fillNoResultReply(reply);
+            return r;
+        } break;
+        case ON_UNSUBSCRIBE: {
+            CHECK_INTERFACE(IVehicleNetworkHalMock, data, reply);
+            int32_t property = data.readInt32();
+            onPropertyUnsubscribe(property);
+            BinderUtil::fillNoResultReply(reply);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/libvehiclenetwork/native/VehicleNetworkProtoUtil.cpp b/libvehiclenetwork/native/VehicleNetworkProtoUtil.cpp
index 78b77a6..ee7447b 100644
--- a/libvehiclenetwork/native/VehicleNetworkProtoUtil.cpp
+++ b/libvehiclenetwork/native/VehicleNetworkProtoUtil.cpp
@@ -304,8 +304,9 @@
                 out.float_max_value = in.float_max();
                 out.float_min_value = in.float_min();
             } else {
-                ALOGE("no float max/min");
-                return BAD_VALUE;
+                ALOGW("no float max/min for property 0x%x", out.prop);
+                out.float_max_value = 0;
+                out.float_min_value = 0;
             }
         } break;
         case VEHICLE_VALUE_TYPE_INT64: {
@@ -313,8 +314,9 @@
                 out.int64_max_value = in.int64_max();
                 out.int64_min_value = in.int64_min();
             } else {
-                ALOGE("no int64 max/min");
-                return BAD_VALUE;
+                ALOGW("no int64 max/min for property 0x%x", out.prop);
+                out.int64_max_value = 0;
+                out.int64_min_value = 0;
             }
         } break;
         case VEHICLE_VALUE_TYPE_INT32:
@@ -323,8 +325,9 @@
                 out.int32_max_value = in.int32_max();
                 out.int32_min_value = in.int32_min();
             } else {
-                ALOGE("no int32 max/min");
-                return BAD_VALUE;
+                ALOGW("no int32 max/min for property 0x%x", out.prop);
+                out.int32_max_value = 0;
+                out.int32_min_value = 0;
             }
         } break;
     }
diff --git a/libvehiclenetwork/tool/vehiclehal_code_gen.py b/libvehiclenetwork/tool/vehiclehal_code_gen.py
index 72b9ab3..8f64e9b 100755
--- a/libvehiclenetwork/tool/vehiclehal_code_gen.py
+++ b/libvehiclenetwork/tool/vehiclehal_code_gen.py
@@ -117,7 +117,6 @@
 }
 }
 """
-
   #now implement getVehiclePropertyName
   print \
 """public static String getVehiclePropertyName(int property) {
@@ -130,6 +129,34 @@
 }
 }
 """
+  #now implement getVehicleChangeMode
+  print \
+"""public static int[] getVehicleChangeMode(int property) {
+switch (property) {"""
+  for p in props:
+    if p.changeMode != "":
+      modes = p.changeMode.split('|')
+      modesString = []
+      for m in modes:
+        modesString.append("VehiclePropChangeMode." + m)
+      print "case " + p.name + ": return new int[] { " + " , ".join(modesString) + " };"
+  print \
+"""default: return null;
+}
+}
+"""
+  #now implement getVehicleAccess
+  print \
+"""public static int getVehicleAccess(int property) {
+switch (property) {"""
+  for p in props:
+    if p.access != "":
+      print "case " + p.name + ": return VehiclePropAccess." + p.access + ";"
+  print \
+"""default: return 0;
+}
+}
+"""
 
 def printEnum(e):
   print "public static class " + toJavaStyleName(e.name) + " {"
@@ -189,7 +216,7 @@
         prop.access = words[i]
       elif words[i] == "@unit":
         i += 1
-        prop.changeMode = words[i]
+        prop.unit = words[i]
       elif words[i] == "@range_start" or words[i] == "@range_end":
         prop.startEnd = 1
       i += 1
diff --git a/service/Android.mk b/service/Android.mk
index 1967112..05734f2 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -31,7 +31,7 @@
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 LOCAL_PROGUARD_ENABLED := disabled
 
-LOCAL_STATIC_JAVA_LIBRARIES += libcarsupport libvehiclenetwork-java
+LOCAL_STATIC_JAVA_LIBRARIES += libvehiclenetwork-java libcarsystemtest
 
 include $(BUILD_PACKAGE)
 
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index c2ad04c..ff25866 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -53,6 +53,12 @@
         android:label="@string/car_permission_label_vendor_extension"
         android:description="@string/car_permission_desc_vendor_extension" />
 
+    <permission
+        android:name="android.support.car.permission.CAR_MOCK_VEHICLE_HAL"
+        android:protectionLevel="system|signature"
+        android:label="@string/car_permission_label_mock_vehicle_hal"
+        android:description="@string/car_permission_desc_mock_vehicle_hal" />
+
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index 17f5fb2..e5ba396 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -20,20 +20,24 @@
     <!-- Permission text: can access your car's information [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc">Access your car\'s information.</string>
     <!-- Permission text: can access your car's fuel level [CHAR LIMIT=NONE] -->
-    <string name="car_permission_label_fuel">car fuel level</string>
+    <string name="car_permission_label_fuel">Car fuel level</string>
     <!-- Permission text: can access your car's fuel level [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_fuel">Access your car\'s fuel level information.</string>
     <!-- Permission text: can access your car's mileage information [CHAR LIMIT=NONE] -->
-    <string name="car_permission_label_mileage">car mileage</string>
+    <string name="car_permission_label_mileage">Car mileage</string>
     <!-- Permission text: can access your car's mileage information [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_mileage">Access your car\'s mileage information.</string>
     <!-- Permission text: can access your car's speed [CHAR LIMIT=NONE] -->
-    <string name="car_permission_label_speed">car speed</string>
+    <string name="car_permission_label_speed">Car speed</string>
     <!-- Permission text: can access your car's speed [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_speed">Access your car\'s speed.</string>
     <!-- Permission text: apps can access car-manufacturer specific data [CHAR LIMIT=NONE] -->
-    <string name="car_permission_label_vendor_extension">car vendor channel</string>
+    <string name="car_permission_label_vendor_extension">Car vendor channel</string>
     <!-- Permission text: apps can access car-manufacturer specific data [CHAR LIMIT=NONE] -->
     <string name="car_permission_desc_vendor_extension">Access your car\'s vendor channel to
         exchange car-specific information.</string>
-</resources>
\ No newline at end of file
+    <string name="car_permission_label_mock_vehicle_hal">Emulate vehicle HAL</string>
+    <!-- Permission text: can emulate information from your car [CHAR LIMIT=NONE] -->
+    <string name="car_permission_desc_mock_vehicle_hal">Emulate your car\'s vehicle HAL for internal
+        testing purpose.</string>
+</resources>
diff --git a/service/src/com/android/car/CarAudioService.java b/service/src/com/android/car/CarAudioService.java
index e730ee8..881b2c5 100644
--- a/service/src/com/android/car/CarAudioService.java
+++ b/service/src/com/android/car/CarAudioService.java
@@ -177,6 +177,7 @@
     }
 
     private void doHandleSystemAudioFocusGrant(AudioFocusInfo afi, int requestResult) {
+        //TODO distinguish car service's own focus request from others
         if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
             mFocusInfos[0] = afi;
             sendCarAudioFocusRequestIfNecessary();
@@ -229,6 +230,16 @@
         }
     }
 
+    /**
+     * Focus listener to take focus away from android apps.
+     */
+    private class AndroidFocusListener implements AudioManager.OnAudioFocusChangeListener {
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            // nothing to do as system focus listener will get all necessary information.
+        }
+    }
+
     private class CarAudioChangeHandler extends Handler {
         private static final int MSG_FOCUS_CHANGE = 0;
         private static final int MSG_STREAM_STATE_CHANGE = 1;
diff --git a/service/src/com/android/car/CarLog.java b/service/src/com/android/car/CarLog.java
index fe24354..e6ddc9e 100644
--- a/service/src/com/android/car/CarLog.java
+++ b/service/src/com/android/car/CarLog.java
@@ -23,4 +23,5 @@
     public static final String TAG_HAL = "CAR.HAL";
     public static final String TAG_INFO = "CAR.INFO";
     public static final String TAG_AUDIO = "CAR.AUDIO";
+    public static final String TAG_TEST = "CAR.TEST";
 }
diff --git a/service/src/com/android/car/CarSensorService.java b/service/src/com/android/car/CarSensorService.java
index e230f25..cffb37e 100644
--- a/service/src/com/android/car/CarSensorService.java
+++ b/service/src/com/android/car/CarSensorService.java
@@ -71,14 +71,6 @@
 
         /** Sensor service is ready and all vehicle sensors are available. */
         public abstract void onSensorServiceReady();
-
-        /**
-         * Provide default sensor value. This value should be always provided after {@link #init()}
-         * call. Default value for safety related sensor should be giving safe state.
-         * @param sensorType
-         * @return
-         */
-        public abstract CarSensorEvent getDefaultValue(int sensorType);
     }
 
     /**
@@ -144,19 +136,20 @@
             mSupportedSensors = refreshSupportedSensorsLocked();
             if (mUseDefaultDrivingPolicy) {
                 mDrivingStatePolicy.init();
-                addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
-                        mDrivingStatePolicy.getDefaultValue(
-                                CarSensorManager.SENSOR_TYPE_DRIVING_STATUS));
                 mDrivingStatePolicy.registerSensorListener(this);
             }
+            // always populate default value
+            addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
+                    DrivingStatePolicy.getDefaultValue(
+                            CarSensorManager.SENSOR_TYPE_DRIVING_STATUS));
             if (mUseDefaultDayNightModePolicy) {
                 mDayNightModePolicy.init();
-                addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT,
-                        mDrivingStatePolicy.getDefaultValue(
-                                CarSensorManager.SENSOR_TYPE_NIGHT));
                 mDayNightModePolicy.registerSensorListener(this);
             }
-
+            // always populate default value
+            addNewSensorRecordLocked(CarSensorManager.SENSOR_TYPE_NIGHT,
+                    DayNightModePolicy.getDefaultValue(
+                            CarSensorManager.SENSOR_TYPE_NIGHT));
         } finally {
             mSensorLock.unlock();
         }
@@ -171,7 +164,9 @@
 
     @Override
     public void release() {
-        mHandlerThread.quit();
+        if (mHandlerThread != null) {
+            mHandlerThread.quit();
+        }
         tryHoldSensorLock();
         try {
             if (mUseDefaultDrivingPolicy) {
diff --git a/service/src/com/android/car/CarTestService.java b/service/src/com/android/car/CarTestService.java
new file mode 100644
index 0000000..26a1b7d
--- /dev/null
+++ b/service/src/com/android/car/CarTestService.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.car.hal.VehicleHal;
+import com.android.car.vehiclenetwork.IVehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetwork;
+import com.android.car.vehiclenetwork.VehiclePropValueParcelable;
+
+import java.io.PrintWriter;
+
+/**
+ * Service to allow testing / mocking vehicle HAL.
+ * This service uses Vehicle HAL APIs directly (one exception) as vehicle HAL mocking anyway
+ * requires accessing that level directly.
+ */
+public class CarTestService extends ICarTest.Stub implements CarServiceBase {
+    private static final int VERSION = 1;
+
+    private final Context mContext;
+    private final VehicleNetwork mVehicleNetwork;
+    private final ICarImpl mICarImpl;
+
+    public CarTestService(Context context, ICarImpl carImpl) {
+        mContext = context;
+        mICarImpl = carImpl;
+        mVehicleNetwork = VehicleHal.getInstance().getVehicleNetwork();
+    }
+
+    @Override
+    public void init() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void release() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public int getVersion() {
+        return VERSION;
+    }
+
+    @Override
+    public void injectEvent(VehiclePropValueParcelable value) {
+        ICarImpl.assertVehicleHalMockPermission(mContext);
+        mVehicleNetwork.injectEvent(value.value);
+    }
+
+    @Override
+    public void startMocking(IVehicleNetworkHalMock mock) {
+        ICarImpl.assertVehicleHalMockPermission(mContext);
+        mVehicleNetwork.startMocking(mock);
+        VehicleHal.getInstance().startMocking();
+        mICarImpl.startMocking();
+    }
+
+    @Override
+    public void stopMocking(IVehicleNetworkHalMock mock) {
+        ICarImpl.assertVehicleHalMockPermission(mContext);
+        mVehicleNetwork.stopMocking(mock);
+        VehicleHal.getInstance().stopMocking();
+        mICarImpl.stopMocking();
+    }
+}
diff --git a/service/src/com/android/car/DayNightModePolicy.java b/service/src/com/android/car/DayNightModePolicy.java
index 23f36d9..892c077 100644
--- a/service/src/com/android/car/DayNightModePolicy.java
+++ b/service/src/com/android/car/DayNightModePolicy.java
@@ -17,6 +17,7 @@
 package com.android.car;
 
 import android.content.Context;
+import android.os.SystemClock;
 import android.support.car.Car;
 import android.support.car.CarSensorEvent;
 import android.support.car.CarSensorManager;
@@ -47,10 +48,8 @@
         // TODO Auto-generated method stub
     }
 
-    @Override
-    public synchronized CarSensorEvent getDefaultValue(int sensorType) {
-        // TODO Auto-generated method stub
-        return null;
+    public static CarSensorEvent getDefaultValue(int sensorType) {
+        return createEvent(true /* isNight */);
     }
 
     @Override
@@ -89,6 +88,13 @@
         // TODO Auto-generated method stub
     }
 
+    private static CarSensorEvent createEvent(boolean isNight) {
+        CarSensorEvent event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_NIGHT,
+                SystemClock.elapsedRealtimeNanos(), 0, 1);
+        event.intValues[0] = isNight ? 1 : 0;
+        return event;
+    }
+
     @Override
     public synchronized void dump(PrintWriter writer) {
         // TODO Auto-generated method stub
diff --git a/service/src/com/android/car/DrivingStatePolicy.java b/service/src/com/android/car/DrivingStatePolicy.java
index e1eed18..11fad66 100644
--- a/service/src/com/android/car/DrivingStatePolicy.java
+++ b/service/src/com/android/car/DrivingStatePolicy.java
@@ -91,14 +91,13 @@
         // TODO Auto-generated method stub
     }
 
-    @Override
-    public synchronized CarSensorEvent getDefaultValue(int sensorType) {
+    public static CarSensorEvent getDefaultValue(int sensorType) {
         if (sensorType != CarSensorManager.SENSOR_TYPE_DRIVING_STATUS) {
-            Log.w(CarLog.TAG_SENSOR, "getCurrentValue to DrivingStatePolicy with sensorType:" +
+            Log.w(CarLog.TAG_SENSOR, "getDefaultValue to DrivingStatePolicy with sensorType:" +
                     sensorType);
             return null;
         }
-        return createEvent(mDringState);
+        return createEvent(CarSensorEvent.DRIVE_STATUS_FULLY_RESTRICTED);
     }
 
     @Override
@@ -202,7 +201,7 @@
         return gear == CarSensorEvent.GEAR_PARK;
     }
 
-    private CarSensorEvent createEvent(int drivingState) {
+    private static CarSensorEvent createEvent(int drivingState) {
         CarSensorEvent event = new CarSensorEvent(CarSensorManager.SENSOR_TYPE_DRIVING_STATUS,
                 SystemClock.elapsedRealtimeNanos(), 0, 1);
         event.intValues[0] = drivingState;
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index b02bce6..779a48f 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.IBinder;
 import android.support.car.Car;
 import android.support.car.ICar;
@@ -41,6 +42,9 @@
     private final CarSensorService mCarSensorService;
     private final CarInfoService mCarInfoService;
     private final CarAudioService mCarAudioService;
+    /** Test only service. Populate it only when necessary. */
+    @GuardedBy("this")
+    private CarTestService mCarTestService;
     private final CarServiceBase[] mAllServices;
 
     public synchronized static ICarImpl getInstance(Context serviceContext) {
@@ -86,6 +90,23 @@
         VehicleHal.releaseInstance();
     }
 
+    public void startMocking() {
+        reinitServices();
+    }
+
+    public void stopMocking() {
+        reinitServices();
+    }
+
+    private void reinitServices() {
+        for (int i = mAllServices.length - 1; i >= 0; i--) {
+            mAllServices[i].release();
+        }
+        for (CarServiceBase service: mAllServices) {
+            service.init();
+        }
+    }
+
     @Override
     public int getVersion() {
         return VERSION;
@@ -98,6 +119,15 @@
                 return mCarSensorService;
             case Car.INFO_SERVICE:
                 return mCarInfoService;
+            case CarSystemTest.TEST_SERVICE: {
+                assertVehicleHalMockPermission(mContext);
+                synchronized (this) {
+                    if (mCarTestService == null) {
+                        mCarTestService = new CarTestService(mContext, this);
+                    }
+                    return mCarTestService;
+                }
+            }
             default:
                 Log.w(CarLog.TAG_SERVICE, "getCarService for unknown service:" + serviceName);
                 return null;
@@ -130,10 +160,21 @@
         return false;
     }
 
+    public static void assertVehicleHalMockPermission(Context context) {
+        if (context.checkCallingOrSelfPermission(CarSystemTest.PERMISSION_MOCK_VEHICLE_HAL)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("requires CAR_MOCK_VEHICLE_HAL permission");
+        }
+    }
+
     void dump(PrintWriter writer) {
         writer.println("*Dump all services*");
         for (CarServiceBase service: mAllServices) {
             service.dump(writer);
         }
+        CarTestService testService = mCarTestService;
+        if (testService != null) {
+            testService.dump(writer);
+        }
     }
 }
diff --git a/service/src/com/android/car/hal/AudioHalService.java b/service/src/com/android/car/hal/AudioHalService.java
index 59fb6c8..e83cfe9 100644
--- a/service/src/com/android/car/hal/AudioHalService.java
+++ b/service/src/com/android/car/hal/AudioHalService.java
@@ -16,8 +16,8 @@
 package com.android.car.hal;
 
 import com.android.car.vehiclenetwork.VehicleNetworkConsts;
-import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequestType;
-import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusStateType;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequest;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState;
 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamState;
 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
@@ -29,33 +29,33 @@
 public class AudioHalService extends HalServiceBase {
 
     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN =
-            VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
+            VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT =
-            VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
+            VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK =
-            VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
+            VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE =
-            VehicleAudioFocusRequestType.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
+            VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
 
     public static String audioFocusRequestToString(int request) {
-        return VehicleAudioFocusRequestType.enumToString(request);
+        return VehicleAudioFocusRequest.enumToString(request);
     }
 
     public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE =
-            VehicleAudioFocusStateType.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE;
+            VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE;
 
     public static String audioFocusStateToString(int state) {
-        return VehicleAudioFocusStateType.enumToString(state);
+        return VehicleAudioFocusState.enumToString(state);
     }
 
     public static final int VEHICLE_AUDIO_STREAM_STATE_STOPPED =
@@ -115,10 +115,12 @@
                     VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS);
             mVehicleHal.unsubscribeProperty(this,
                     VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE);
+            mFocusSupported = false;
         }
         if (mVolumeSupported) {
             mVehicleHal.unsubscribeProperty(this,
                     VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME);
+            mVolumeSupported = false;
         }
     }
 
diff --git a/service/src/com/android/car/hal/SensorHalService.java b/service/src/com/android/car/hal/SensorHalService.java
index 4fb8398..e7fb8f4 100644
--- a/service/src/com/android/car/hal/SensorHalService.java
+++ b/service/src/com/android/car/hal/SensorHalService.java
@@ -38,7 +38,7 @@
  */
 public class SensorHalService extends SensorHalServiceBase {
 
-    private static final boolean DBG_EVENTS = true;
+    private static final boolean DBG_EVENTS = false;
 
     private static final int SENSOR_TYPE_INVALD = -1;
 
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index d41def1..4652324 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -147,6 +147,19 @@
         // keep the looper thread as should be kept for the whole life cycle.
     }
 
+    public void startMocking() {
+        reinitHals();
+    }
+
+    public void stopMocking() {
+        reinitHals();
+    }
+
+    private void reinitHals() {
+        release();
+        doInit();
+    }
+
     public SensorHalService getSensorHal() {
         return mSensorHal;
     }
@@ -159,18 +172,6 @@
         return mAudioHal;
     }
 
-    /**
-     * Start mocking HAL with given mock. Actual H/W will be stop functioning until mocking is
-     * stopped. The call will be blocked until all pending events are delivered to upper layer.
-     */
-    public void startHalMocking(HalMock mock) {
-        //TODO
-    }
-
-    public void stopHalMocking() {
-        //TODO
-    }
-
     private void assertServiceOwner(HalServiceBase service, int property) {
         if (service != mPropertyHandlers.get(property)) {
             throw new IllegalArgumentException("not owned");
diff --git a/tests/api_test/Android.mk b/tests/api_test/Android.mk
index cecc88e..1b2b728 100644
--- a/tests/api_test/Android.mk
+++ b/tests/api_test/Android.mk
@@ -22,11 +22,17 @@
 
 LOCAL_PACKAGE_NAME := CarApiTest
 
+# for system|priviledged permission.
+LOCAL_CERTIFICATE := platform
+
 LOCAL_MODULE_TAGS := tests
 
+# When built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
 LOCAL_PROGUARD_ENABLED := disabled
 
-LOCAL_STATIC_JAVA_LIBRARIES += libcarsupport
+LOCAL_STATIC_JAVA_LIBRARIES += libcarsystemtest
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
diff --git a/tests/api_test/AndroidManifest.xml b/tests/api_test/AndroidManifest.xml
index 41c158f..1ddc478 100644
--- a/tests/api_test/AndroidManifest.xml
+++ b/tests/api_test/AndroidManifest.xml
@@ -16,7 +16,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-        package="com.android.support.car.apitest" >
+        package="com.android.support.car.apitest"
+        android:sharedUserId="android.uid.system" >
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
             android:targetPackage="com.android.support.car.apitest"
diff --git a/tests/api_test/src/com/android/support/car/apitest/CarInfoManagerTest.java b/tests/api_test/src/com/android/support/car/apitest/CarInfoManagerTest.java
index 1321982..d14a1ed 100644
--- a/tests/api_test/src/com/android/support/car/apitest/CarInfoManagerTest.java
+++ b/tests/api_test/src/com/android/support/car/apitest/CarInfoManagerTest.java
@@ -24,69 +24,37 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import com.android.car.vehiclenetwork.VehicleNetworkConsts;
+import com.android.car.vehiclenetwork.VehiclePropConfigUtil;
+import com.android.car.vehiclenetwork.VehiclePropValueUtil;
+
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 
-public class CarInfoManagerTest extends AndroidTestCase {
-    private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
+public class CarInfoManagerTest extends MockedCarTestBase {
 
     private static final String TAG = CarInfoManagerTest.class.getSimpleName();
 
-    private final Semaphore mConnectionWait = new Semaphore(0);
+    private static final String MAKE_NAME = "ANDROID";
 
-    private Car mCar;
     private CarInfoManager mCarInfoManager;
 
-    private final ServiceConnectionListener mConnectionListener = new ServiceConnectionListener() {
-
-        @Override
-        public void onServiceSuspended(int cause) {
-            assertMainThread();
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            assertMainThread();
-        }
-
-        @Override
-        public void onServiceConnectionFailed(int cause) {
-            assertMainThread();
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            assertMainThread();
-            mConnectionWait.release();
-        }
-    };
-
-    private void assertMainThread() {
-        assertTrue(Looper.getMainLooper().isCurrentThread());
-    }
-    private void waitForConnection(long timeoutMs) throws InterruptedException {
-        mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
-    }
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mCar = new Car(getContext(), mConnectionListener, null);
-        mCar.connect();
-        waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
+        getVehicleHalEmulator().addStaticProperty(
+                VehiclePropConfigUtil.createStaticStringProperty(
+                        VehicleNetworkConsts.VEHICLE_PROPERTY_INFO_MAKE),
+                VehiclePropValueUtil.createStringValue(
+                        VehicleNetworkConsts.VEHICLE_PROPERTY_INFO_MAKE, MAKE_NAME, 0));
+        getVehicleHalEmulator().start();
         mCarInfoManager =
-                (CarInfoManager) mCar.getCarManager(Car.INFO_SERVICE);
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-        mCar.disconnect();
+                (CarInfoManager) getCarApi().getCarManager(Car.INFO_SERVICE);
     }
 
     public void testManufactuter() throws Exception {
         String name = mCarInfoManager.getString(CarInfoManager.KEY_MANUFACTURER);
-        assertNotNull(name);
+        assertEquals(MAKE_NAME, name);
         Log.i(TAG, CarInfoManager.KEY_MANUFACTURER + ":" + name);
         try {
             Float v = mCarInfoManager.getFloat(CarInfoManager.KEY_MANUFACTURER);
diff --git a/tests/api_test/src/com/android/support/car/apitest/CarTest.java b/tests/api_test/src/com/android/support/car/apitest/CarTest.java
index caf99a4..60f7ee6 100644
--- a/tests/api_test/src/com/android/support/car/apitest/CarTest.java
+++ b/tests/api_test/src/com/android/support/car/apitest/CarTest.java
@@ -60,6 +60,7 @@
     private void assertMainThread() {
         assertTrue(Looper.getMainLooper().isCurrentThread());
     }
+
     private void waitForConnection(long timeoutMs) throws InterruptedException {
         mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
     }
diff --git a/tests/api_test/src/com/android/support/car/apitest/MockedCarTestBase.java b/tests/api_test/src/com/android/support/car/apitest/MockedCarTestBase.java
new file mode 100644
index 0000000..db3d52d
--- /dev/null
+++ b/tests/api_test/src/com/android/support/car/apitest/MockedCarTestBase.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 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.support.car.apitest;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import com.android.car.VehicleHalEmulator;
+
+import android.content.ComponentName;
+import android.os.IBinder;
+import android.support.car.Car;
+import android.support.car.ServiceConnectionListener;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+/**
+ * Base class for testing with mocked vehicle HAL (=car).
+ * It is up to each app to start emulation by getVehicleHalEmulator().start() as there will be
+ * per test set up that should be done before starting.
+ */
+public class MockedCarTestBase extends AndroidTestCase {
+    private static final String TAG = MockedCarTestBase.class.getSimpleName();
+    private static final long DEFAULT_WAIT_TIMEOUT_MS = 3000;
+
+    private Car mCar;
+    private VehicleHalEmulator mVehicleHalEmulator;
+
+    private final Semaphore mConnectionWait = new Semaphore(0);
+
+    private final ServiceConnectionListener mConnectionListener = new ServiceConnectionListener() {
+
+        @Override
+        public void onServiceSuspended(int cause) {
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+
+        @Override
+        public void onServiceConnectionFailed(int cause) {
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            Log.i(TAG, "onServiceConnected, component" + name + " binder " + service);
+            mConnectionWait.release();
+        }
+    };
+
+    @Override
+    protected synchronized void setUp() throws Exception {
+        super.setUp();
+        mCar = new Car(getContext(), mConnectionListener, null);
+        mCar.connect();
+        assertTrue(waitForConnection(DEFAULT_WAIT_TIMEOUT_MS));
+        mVehicleHalEmulator = new VehicleHalEmulator(mCar);
+    }
+
+    @Override
+    protected synchronized void tearDown() throws Exception {
+        super.tearDown();
+        if (mVehicleHalEmulator.isStarted()) {
+            mVehicleHalEmulator.stop();
+        }
+        mCar.disconnect();
+    }
+
+    protected synchronized Car getCarApi() {
+        return mCar;
+    }
+
+    protected synchronized VehicleHalEmulator getVehicleHalEmulator() {
+        return mVehicleHalEmulator;
+    }
+
+    private boolean waitForConnection(long timeoutMs) throws InterruptedException {
+        return mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
+    }
+}
diff --git a/tests/car_activity_test_app/Android.mk b/tests/car_activity_test_app/Android.mk
index 9ee9186..27a377d 100644
--- a/tests/car_activity_test_app/Android.mk
+++ b/tests/car_activity_test_app/Android.mk
@@ -24,6 +24,9 @@
 
 LOCAL_MODULE_TAGS := tests
 
+# When built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
 LOCAL_PROGUARD_ENABLED := disabled
 
 LOCAL_STATIC_JAVA_LIBRARIES += libcarsupport
diff --git a/tests/libvehiclenetwork-java-test/Android.mk b/tests/libvehiclenetwork-java-test/Android.mk
index fb28c65..bde7dda 100644
--- a/tests/libvehiclenetwork-java-test/Android.mk
+++ b/tests/libvehiclenetwork-java-test/Android.mk
@@ -26,6 +26,9 @@
 
 LOCAL_MODULE_TAGS := tests
 
+# When built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
 LOCAL_PROGUARD_ENABLED := disabled
 
 LOCAL_STATIC_JAVA_LIBRARIES += libvehiclenetwork-java
diff --git a/vehicle_network_service/VehicleNetworkService.cpp b/vehicle_network_service/VehicleNetworkService.cpp
index b58c075..a4857ca 100644
--- a/vehicle_network_service/VehicleNetworkService.cpp
+++ b/vehicle_network_service/VehicleNetworkService.cpp
@@ -76,6 +76,14 @@
     mLooper->sendMessage(this, Message(HAL_ERROR));
 }
 
+void VehicleHalMessageHandler::handleMockStart() {
+    Mutex::Autolock autoLock(mLock);
+    mHalPropertyList[0].clear();
+    mHalPropertyList[1].clear();
+    sp<MessageHandler> self(this);
+    mLooper->removeMessages(self);
+}
+
 void VehicleHalMessageHandler::doHandleInit() {
     // nothing to do
 }
@@ -230,8 +238,8 @@
 }
 
 VehicleNetworkService::VehicleNetworkService()
-    : mModule(NULL) {
-    //TODO
+    : mModule(NULL),
+      mMockingEnabled(false) {
     sInstance = this;
 }
 
@@ -331,8 +339,9 @@
     mHandlerThread.quit();
 }
 
-vehicle_prop_config_t const * VehicleNetworkService::findConfig(int32_t property) {
-    for (auto& config : mProperties->getList()) {
+vehicle_prop_config_t const * VehicleNetworkService::findConfigLocked(int32_t property) {
+    for (auto& config : (mMockingEnabled ?
+            mPropertiesForMocking->getList() : mProperties->getList())) {
         if (config->prop == property) {
             return config;
         }
@@ -340,8 +349,8 @@
     return NULL;
 }
 
-bool VehicleNetworkService::isGettable(int32_t property) {
-    vehicle_prop_config_t const * config = findConfig(property);
+bool VehicleNetworkService::isGettableLocked(int32_t property) {
+    vehicle_prop_config_t const * config = findConfigLocked(property);
     if (config == NULL) {
         return false;
     }
@@ -352,8 +361,8 @@
     return true;
 }
 
-bool VehicleNetworkService::isSettable(int32_t property) {
-    vehicle_prop_config_t const * config = findConfig(property);
+bool VehicleNetworkService::isSettableLocked(int32_t property) {
+    vehicle_prop_config_t const * config = findConfigLocked(property);
     if (config == NULL) {
         return false;
     }
@@ -364,8 +373,8 @@
     return true;
 }
 
-bool VehicleNetworkService::isSubscribable(int32_t property) {
-    vehicle_prop_config_t const * config = findConfig(property);
+bool VehicleNetworkService::isSubscribableLocked(int32_t property) {
+    vehicle_prop_config_t const * config = findConfigLocked(property);
     if (config == NULL) {
         return false;
     }
@@ -383,10 +392,14 @@
 sp<VehiclePropertiesHolder> VehicleNetworkService::listProperties(int32_t property) {
     Mutex::Autolock autoLock(mLock);
     if (property == 0) {
-        return mProperties;
+        if (!mMockingEnabled) {
+            return mProperties;
+        } else {
+            return mPropertiesForMocking;
+        }
     } else {
         sp<VehiclePropertiesHolder> p;
-        const vehicle_prop_config_t* config = findConfig(property);
+        const vehicle_prop_config_t* config = findConfigLocked(property);
         if (config != NULL) {
             p = new VehiclePropertiesHolder(false /* deleteConfigsInDestructor */);
             p->getList().push_back(config);
@@ -397,9 +410,10 @@
 }
 
 status_t VehicleNetworkService::getProperty(vehicle_prop_value_t *data) {
+    bool inMocking = false;
     do { // for lock scoping
         Mutex::Autolock autoLock(mLock);
-        if (!isGettable(data->prop)) {
+        if (!isGettableLocked(data->prop)) {
             return BAD_VALUE;
         }
         if ((data->prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
@@ -410,24 +424,40 @@
             return NO_ERROR;
         }
         //TODO caching for static, on-change type?
+        if (mMockingEnabled) {
+            inMocking = true;
+        }
     } while (false);
     // set done outside lock to allow concurrent access
+    if (inMocking) {
+        mHalMock->onPropertyGet(data);
+        return NO_ERROR;
+    }
     return mDevice->get(mDevice, data);
 }
 
 status_t VehicleNetworkService::setProperty(const vehicle_prop_value_t& data) {
+    bool isInternalProperty = false;
+    bool inMocking = false;
     do { // for lock scoping
         Mutex::Autolock autoLock(mLock);
-        if (!isSettable(data.prop)) {
+        if (!isSettableLocked(data.prop)) {
             return BAD_VALUE;
         }
-    } while (false);
-    if ((data.prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
-                    (data.prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
-        do {
-            Mutex::Autolock autoLock(mLock);
+        if ((data.prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
+                            (data.prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
+            isInternalProperty = true;
             mCache.writeToCache(data);
-        } while (false);
+        }
+        if (mMockingEnabled) {
+            inMocking = true;
+        }
+    } while (false);
+    if (inMocking) {
+        mHalMock->onPropertySet(data);
+        return NO_ERROR;
+    }
+    if (isInternalProperty) {
         // for internal property, just publish it.
         onHalEvent(&data);
         return NO_ERROR;
@@ -439,125 +469,188 @@
 
 status_t VehicleNetworkService::subscribe(const sp<IVehicleNetworkListener> &listener, int32_t prop,
         float sampleRate) {
-    Mutex::Autolock autoLock(mLock);
-    if (!isSubscribable(prop)) {
-        return BAD_VALUE;
-    }
-    vehicle_prop_config_t const * config = findConfig(prop);
-    if (config->change_mode == VEHICLE_PROP_CHANGE_MODE_ON_CHANGE) {
-        if (sampleRate != 0) {
-            ALOGW("Sample rate set to non-zeo for on change type. Ignore it");
-            sampleRate = 0;
-        }
-    } else {
-        if (sampleRate > config->max_sample_rate) {
-            ALOGW("sample rate %f higher than max %f. limit to max", sampleRate,
-                    config->max_sample_rate);
-            sampleRate = config->max_sample_rate;
-        }
-        if (sampleRate < config->min_sample_rate) {
-            ALOGW("sample rate %f lower than min %f. limit to min", sampleRate,
-                                config->min_sample_rate);
-            sampleRate = config->min_sample_rate;
-        }
-    }
-    sp<IBinder> iBinder = IInterface::asBinder(listener);
-    ALOGD("subscribe, binder 0x%x prop 0x%x", iBinder.get(), prop);
-    sp<HalClient> client;
-    sp<HalClientSpVector> clientsForProperty;
-    bool createClient = false;
-    ssize_t index = mBinderToClientMap.indexOfKey(iBinder);
-    if (index < 0) {
-        createClient = true;
-    } else {
-        client = mBinderToClientMap.editValueAt(index);
-        index = mPropertyToClientsMap.indexOfKey(prop);
-        if (index >= 0) {
-            clientsForProperty = mPropertyToClientsMap.editValueAt(index);
-        }
-    }
-    if (clientsForProperty.get() == NULL) {
-        clientsForProperty = new HalClientSpVector();
-        ASSERT_OR_HANDLE_NO_MEMORY(clientsForProperty.get(), return NO_MEMORY);
-        mPropertyToClientsMap.add(prop, clientsForProperty);
-    }
-    if (createClient) {
-        client = new HalClient(listener);
-        ASSERT_OR_HANDLE_NO_MEMORY(client.get(), return NO_MEMORY);
-        iBinder->linkToDeath(this);
-        ALOGV("add binder 0x%x to map", iBinder.get());
-        mBinderToClientMap.add(iBinder, client);
-    }
-    clientsForProperty->add(client);
-
-    index = mSampleRates.indexOfKey(prop);
     bool shouldSubscribe = false;
-    if (index < 0) {
-        // first time subscription for this property
-        shouldSubscribe = true;
-    } else {
-        float currentSampleRate = mSampleRates.valueAt(index);
-        if (currentSampleRate < sampleRate) {
+    bool inMock = false;
+    do {
+        Mutex::Autolock autoLock(mLock);
+        if (!isSubscribableLocked(prop)) {
+            return BAD_VALUE;
+        }
+        vehicle_prop_config_t const * config = findConfigLocked(prop);
+        if (config->change_mode == VEHICLE_PROP_CHANGE_MODE_ON_CHANGE) {
+            if (sampleRate != 0) {
+                ALOGW("Sample rate set to non-zeo for on change type. Ignore it");
+                sampleRate = 0;
+            }
+        } else {
+            if (sampleRate > config->max_sample_rate) {
+                ALOGW("sample rate %f higher than max %f. limit to max", sampleRate,
+                        config->max_sample_rate);
+                sampleRate = config->max_sample_rate;
+            }
+            if (sampleRate < config->min_sample_rate) {
+                ALOGW("sample rate %f lower than min %f. limit to min", sampleRate,
+                                    config->min_sample_rate);
+                sampleRate = config->min_sample_rate;
+            }
+        }
+        sp<IBinder> iBinder = IInterface::asBinder(listener);
+        ALOGD("subscribe, binder 0x%x prop 0x%x", iBinder.get(), prop);
+        sp<HalClient> client;
+        sp<HalClientSpVector> clientsForProperty;
+        bool createClient = false;
+        ssize_t index = mBinderToClientMap.indexOfKey(iBinder);
+        if (index < 0) {
+            createClient = true;
+        } else {
+            client = mBinderToClientMap.editValueAt(index);
+            index = mPropertyToClientsMap.indexOfKey(prop);
+            if (index >= 0) {
+                clientsForProperty = mPropertyToClientsMap.editValueAt(index);
+            }
+        }
+        if (clientsForProperty.get() == NULL) {
+            clientsForProperty = new HalClientSpVector();
+            ASSERT_OR_HANDLE_NO_MEMORY(clientsForProperty.get(), return NO_MEMORY);
+            mPropertyToClientsMap.add(prop, clientsForProperty);
+        }
+        if (createClient) {
+            client = new HalClient(listener);
+            ASSERT_OR_HANDLE_NO_MEMORY(client.get(), return NO_MEMORY);
+            iBinder->linkToDeath(this);
+            ALOGV("add binder 0x%x to map", iBinder.get());
+            mBinderToClientMap.add(iBinder, client);
+        }
+        clientsForProperty->add(client);
+
+        index = mSampleRates.indexOfKey(prop);
+        if (index < 0) {
+            // first time subscription for this property
             shouldSubscribe = true;
+        } else {
+            float currentSampleRate = mSampleRates.valueAt(index);
+            if (currentSampleRate < sampleRate) {
+                shouldSubscribe = true;
+            }
         }
-    }
-    client->setSampleRate(prop, sampleRate);
+        client->setSampleRate(prop, sampleRate);
+        if (shouldSubscribe) {
+            inMock = mMockingEnabled;
+            mSampleRates.add(prop, sampleRate);
+            if ((prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
+                                (prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
+                ALOGD("subscribe to internal property, prop 0x%x", prop);
+                return NO_ERROR;
+            }
+        }
+    } while (false);
     if (shouldSubscribe) {
-        mSampleRates.add(prop, sampleRate);
-        if ((prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
-                            (prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
-            ALOGD("subscribe to internal property, prop 0x%x", prop);
-            return NO_ERROR;
+        if (inMock) {
+            return mHalMock->onPropertySubscribe(prop, sampleRate);
+        } else {
+            ALOGD("subscribe to HAL, prop 0x%x sample rate:%f", prop, sampleRate);
+            return mDevice->subscribe(mDevice, prop, sampleRate);
         }
-        ALOGD("subscribe to HAL, prop 0x%x sample rate:%f", prop, sampleRate);
-        return mDevice->subscribe(mDevice, prop, sampleRate);
-    } else {
-        return NO_ERROR;
     }
+    return NO_ERROR;
 }
 
 void VehicleNetworkService::unsubscribe(const sp<IVehicleNetworkListener> &listener, int32_t prop) {
-    Mutex::Autolock autoLock(mLock);
-    if (!isSubscribable(prop)) {
-        return;
-    }
-    sp<IBinder> iBinder = IInterface::asBinder(listener);
-    ALOGD("unsubscribe, binder 0x%x, prop 0x%x", iBinder.get(), prop);
-    ssize_t index = mBinderToClientMap.indexOfKey(iBinder);
-    if (index < 0) {
-        // client not found
-        ALOGD("unsubscribe client not found in binder map");
-        return;
-    }
-    sp<HalClient>& client = mBinderToClientMap.editValueAt(index);
-    index = mPropertyToClientsMap.indexOfKey(prop);
-    if (index < 0) {
-        // not found
-        ALOGD("unsubscribe client not found in prop map, prop:0x%x", prop);
-        return;
-    }
-    sp<HalClientSpVector> clientsForProperty = mPropertyToClientsMap.editValueAt(index);
-    //TODO share code with binderDied
-    clientsForProperty->remove(client);
-    if(!client->removePropertyAndCheckIfActive(prop)) {
-        // client is no longer necessary
-        mBinderToClientMap.removeItem(iBinder);
-        iBinder->unlinkToDeath(this);
-    }
-    //TODO reset sample rate. do not care for now.
-    if (clientsForProperty->size() == 0) {
-        if ((prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
-                (prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
-            ALOGD("unsubscribe to internal property, prop 0x%x", prop);
+    bool shouldUnsubscribe = false;
+    bool inMocking = false;
+    do {
+        Mutex::Autolock autoLock(mLock);
+        if (!isSubscribableLocked(prop)) {
+            return;
+        }
+        sp<IBinder> iBinder = IInterface::asBinder(listener);
+        ALOGD("unsubscribe, binder 0x%x, prop 0x%x", iBinder.get(), prop);
+        ssize_t index = mBinderToClientMap.indexOfKey(iBinder);
+        if (index < 0) {
+            // client not found
+            ALOGD("unsubscribe client not found in binder map");
+            return;
+        }
+        sp<HalClient>& client = mBinderToClientMap.editValueAt(index);
+        index = mPropertyToClientsMap.indexOfKey(prop);
+        if (index < 0) {
+            // not found
+            ALOGD("unsubscribe client not found in prop map, prop:0x%x", prop);
+            return;
+        }
+        sp<HalClientSpVector> clientsForProperty = mPropertyToClientsMap.editValueAt(index);
+        //TODO share code with binderDied
+        clientsForProperty->remove(client);
+        if(!client->removePropertyAndCheckIfActive(prop)) {
+            // client is no longer necessary
+            mBinderToClientMap.removeItem(iBinder);
+            iBinder->unlinkToDeath(this);
+        }
+        //TODO reset sample rate. do not care for now.
+        if (clientsForProperty->size() == 0) {
+            if ((prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
+                    (prop <= (int32_t)VEHICLE_PROPERTY_INTERNAL_END)) {
+                ALOGD("unsubscribe to internal property, prop 0x%x", prop);
+            } else if (mMockingEnabled) {
+                inMocking = true;
+            }
+            mPropertyToClientsMap.removeItem(prop);
+            mSampleRates.removeItem(prop);
+        }
+    } while (false);
+    if (shouldUnsubscribe) {
+        if (inMocking) {
+            mHalMock->onPropertyUnsubscribe(prop);
         } else {
             mDevice->unsubscribe(mDevice, prop);
         }
-        mPropertyToClientsMap.removeItem(prop);
-        mSampleRates.removeItem(prop);
     }
 }
 
-void VehicleNetworkService::onHalEvent(const vehicle_prop_value_t* eventData) {
+status_t VehicleNetworkService::injectEvent(const vehicle_prop_value_t& value) {
+    onHalEvent(&value);
+    return NO_ERROR;
+}
+
+status_t VehicleNetworkService::startMocking(const sp<IVehicleNetworkHalMock>& mock) {
+    Mutex::Autolock autoLock(mLock);
+    mHalMock = mock;
+    mMockingEnabled = true;
+    mHandler->handleMockStart();
+    // Mock implementation should make sure that its startMocking call is not blocking its
+    // onlistProperties call. Otherwise, this will lead into dead-lock.
+    mPropertiesForMocking = mock->onListProperties();
+    //TODO save all old states before dropping all clients
+    mBinderToClientMap.clear();
+    mPropertyToClientsMap.clear();
+    mSampleRates.clear();
+    //TODO handle binder death
+    return NO_ERROR;
+}
+
+void VehicleNetworkService::stopMocking(const sp<IVehicleNetworkHalMock>& mock) {
+    Mutex::Autolock autoLock(mLock);
+    if (mHalMock.get() == NULL) {
+        return;
+    }
+    if (IInterface::asBinder(mock) != IInterface::asBinder(mHalMock)) {
+        ALOGE("stopMocking, not the one started");
+        return;
+    }
+    mHalMock = NULL;
+    mMockingEnabled = false;
+    mPropertiesForMocking = NULL;
+    //TODO restore old states
+}
+
+void VehicleNetworkService::onHalEvent(const vehicle_prop_value_t* eventData, bool isInjection) {
+    if (!isInjection) {
+        Mutex::Autolock autoLock(mLock);
+        if (mMockingEnabled) {
+            // drop real HAL event if mocking is enabled
+            return;
+        }
+    }
     //TODO add memory pool
     vehicle_prop_value_t* copy = VehiclePropValueUtil::allocVehicleProp(*eventData);
     ASSERT_OR_HANDLE_NO_MEMORY(copy, return);
diff --git a/vehicle_network_service/VehicleNetworkService.h b/vehicle_network_service/VehicleNetworkService.h
index e696a95..b0c0a40 100644
--- a/vehicle_network_service/VehicleNetworkService.h
+++ b/vehicle_network_service/VehicleNetworkService.h
@@ -73,6 +73,7 @@
     void handleRelease();
     void handleHalEvent(vehicle_prop_value_t *eventData);
     void handleHalError(int errorCode);
+    void handleMockStart();
 
 private:
     void handleMessage(const Message& message);
@@ -215,7 +216,7 @@
     ~VehicleNetworkService();
     virtual status_t dump(int fd, const Vector<String16>& args);
     void release();
-    void onHalEvent(const vehicle_prop_value_t *eventData);
+    void onHalEvent(const vehicle_prop_value_t *eventData, bool isInjection = false);
     void onHalError(int errorCode);
     /**
      * Called by VehicleHalMessageHandler for batching events
@@ -227,6 +228,9 @@
     virtual status_t subscribe(const sp<IVehicleNetworkListener> &listener, int32_t property,
             float sampleRate);
     virtual void unsubscribe(const sp<IVehicleNetworkListener> &listener, int32_t property);
+    virtual status_t injectEvent(const vehicle_prop_value_t& value);
+    virtual status_t startMocking(const sp<IVehicleNetworkHalMock>& mock);
+    virtual void stopMocking(const sp<IVehicleNetworkHalMock>& mock);
     virtual void binderDied(const wp<IBinder>& who);
     bool isPropertySubsribed(int32_t property);
 private:
@@ -234,10 +238,10 @@
     virtual void onFirstRef();
     status_t loadHal();
     void closeHal();
-    vehicle_prop_config_t const * findConfig(int32_t property);
-    bool isGettable(int32_t property);
-    bool isSettable(int32_t property);
-    bool isSubscribable(int32_t property);
+    vehicle_prop_config_t const * findConfigLocked(int32_t property);
+    bool isGettableLocked(int32_t property);
+    bool isSettableLocked(int32_t property);
+    bool isSubscribableLocked(int32_t property);
     static int eventCallback(const vehicle_prop_value_t *eventData);
     static int errorCallback(int32_t errorCode);
 private:
@@ -252,6 +256,9 @@
     KeyedVector<int32_t, sp<HalClientSpVector> > mPropertyToClientsMap;
     KeyedVector<int32_t, float> mSampleRates;
     PropertyValueCache mCache;
+    bool mMockingEnabled;
+    sp<IVehicleNetworkHalMock> mHalMock;
+    sp<VehiclePropertiesHolder> mPropertiesForMocking;
 };
 
 };