add error and hal restart monitoring with other cleanup

- add separate thread dispatch in native VehicleNetwork api.
- fix deadlock in binderDied: do not access HAL with lock held.
- fix missing sp in HandlerThread usage.
- add error listening and hal restart monitoring to binder callback.
- clarified mocking behavior:
  clients listening for global error or HAL restart is not cleared by
  mocking but client subscribing properties are all cleared and should
  subscribe again.
- added native tests and Java tests to test mocking

bug: 24095928
(cherry picked from commit a116a2009ac8966b16cba1ab98d37ad8c537ab02)

Change-Id: I247c64dcb8722a678ed1c2e950a215a193a5e991
diff --git a/tests/libvehiclenetwork-java-test/src/com/android/car/vehiclenetwork/libtest/VehicleNetworkMockedTest.java b/tests/libvehiclenetwork-java-test/src/com/android/car/vehiclenetwork/libtest/VehicleNetworkMockedTest.java
new file mode 100644
index 0000000..b618584
--- /dev/null
+++ b/tests/libvehiclenetwork-java-test/src/com/android/car/vehiclenetwork/libtest/VehicleNetworkMockedTest.java
@@ -0,0 +1,258 @@
+/*
+ * 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.libtest;
+
+import android.os.HandlerThread;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.car.vehiclenetwork.VehicleNetwork;
+import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkHalMock;
+import com.android.car.vehiclenetwork.VehicleNetwork.VehicleNetworkListener;
+import com.android.car.vehiclenetwork.VehicleNetworkConsts;
+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.VehicleNetworkProto.VehiclePropValues;
+import com.android.car.vehiclenetwork.VehiclePropConfigUtil;
+import com.android.car.vehiclenetwork.VehiclePropValueUtil;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+public class VehicleNetworkMockedTest extends AndroidTestCase {
+    private static final String TAG = VehicleNetworkMockedTest.class.getSimpleName();
+
+    private static final long TIMEOUT_MS = 1000;
+
+    private static final int CUSTOM_PROPERTY_INT32 =
+            VehicleNetworkConsts.VEHICLE_PROPERTY_CUSTOM_START;
+
+    private final HandlerThread mHandlerThread = new HandlerThread(
+            VehicleNetworkTest.class.getSimpleName());
+    private VehicleNetwork mVehicleNetwork;
+    private EventListener mListener = new EventListener();
+    private final VehicleHalMock mVehicleHalMock = new VehicleHalMock();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mHandlerThread.start();
+        mVehicleNetwork = VehicleNetwork.createVehicleNetwork(mListener,
+                mHandlerThread.getLooper());
+        mVehicleHalMock.registerProperty(
+                VehiclePropConfigUtil.createProperty(
+                        CUSTOM_PROPERTY_INT32,
+                        VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE,
+                        VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+                        VehicleValueType.VEHICLE_VALUE_TYPE_INT32, 0x0),
+                new DefaultVehiclePropertyHandler(VehiclePropValueUtil.createIntValue(
+                        CUSTOM_PROPERTY_INT32, 0, 0)));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mHandlerThread.quit();
+        mVehicleNetwork.stopMocking();
+    }
+
+    public void testHalRestartListening() throws Exception {
+        mVehicleNetwork.startHalRestartMonitoring();
+        mVehicleNetwork.startMocking(mVehicleHalMock);
+        assertTrue(mListener.waitForHalRestartAndAssert(TIMEOUT_MS, true /*expectedInMocking*/));
+        mVehicleNetwork.stopMocking();
+        assertTrue(mListener.waitForHalRestartAndAssert(TIMEOUT_MS, false /*expectedInMocking*/));
+        mVehicleNetwork.stopHalRestartMonitoring();
+    }
+
+    public void testGlobalErrorListening() throws Exception {
+        mVehicleNetwork.startErrorListening();
+        mVehicleNetwork.startMocking(mVehicleHalMock);
+        final int ERROR_CODE = 0x1;
+        final int ERROR_OPERATION = 0x10;
+        mVehicleNetwork.injectHalError(ERROR_CODE, 0, ERROR_OPERATION);
+        assertTrue(mListener.waitForHalErrorAndAssert(TIMEOUT_MS, ERROR_CODE, 0, ERROR_OPERATION));
+        mVehicleNetwork.injectHalError(ERROR_CODE, CUSTOM_PROPERTY_INT32, ERROR_OPERATION);
+        assertTrue(mListener.waitForHalErrorAndAssert(TIMEOUT_MS,
+                ERROR_CODE, CUSTOM_PROPERTY_INT32, ERROR_OPERATION));
+        mVehicleNetwork.stopMocking();
+        mVehicleNetwork.stopErrorListening();
+    }
+
+    public void testPropertyErrorListening() throws Exception {
+        mVehicleNetwork.startMocking(mVehicleHalMock);
+        mVehicleNetwork.subscribe(CUSTOM_PROPERTY_INT32, 0);
+        final int ERROR_CODE = 0x1;
+        final int ERROR_OPERATION = 0x10;
+        mVehicleNetwork.injectHalError(ERROR_CODE, CUSTOM_PROPERTY_INT32, ERROR_OPERATION);
+        assertTrue(mListener.waitForHalErrorAndAssert(TIMEOUT_MS,
+                ERROR_CODE, CUSTOM_PROPERTY_INT32, ERROR_OPERATION));
+        mVehicleNetwork.unsubscribe(CUSTOM_PROPERTY_INT32);
+        mVehicleNetwork.stopMocking();
+    }
+
+    private class EventListener implements VehicleNetworkListener {
+        boolean mInMocking;
+        private final Semaphore mRestartWait = new Semaphore(0);
+
+        int mErrorCode;
+        int mErrorProperty;
+        int mErrorOperation;
+        private final Semaphore mErrorWait = new Semaphore(0);
+
+        @Override
+        public void onVehicleNetworkEvents(VehiclePropValues values) {
+            // TODO Auto-generated method stub
+        }
+
+        @Override
+        public void onHalError(int errorCode, int property, int operation) {
+            mErrorCode = errorCode;
+            mErrorProperty = property;
+            mErrorOperation = operation;
+            mErrorWait.release();
+        }
+
+        public boolean waitForHalErrorAndAssert(long timeoutMs, int expectedErrorCode,
+                int expectedErrorProperty, int expectedErrorOperation) throws Exception {
+            if (!mErrorWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
+                return false;
+            }
+            assertEquals(expectedErrorCode, mErrorCode);
+            assertEquals(expectedErrorProperty, mErrorProperty);
+            assertEquals(expectedErrorOperation, mErrorOperation);
+            return true;
+        }
+
+        @Override
+        public void onHalRestart(boolean inMocking) {
+            mInMocking = inMocking;
+            mRestartWait.release();
+        }
+
+        public boolean waitForHalRestartAndAssert(long timeoutMs, boolean expectedInMocking)
+                throws Exception {
+            if (!mRestartWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
+                return false;
+            }
+            assertEquals(expectedInMocking, mInMocking);
+            return true;
+        }
+    }
+
+    private interface VehiclePropertyHandler {
+        void onPropertySet(VehiclePropValue value);
+        VehiclePropValue onPropertyGet(VehiclePropValue property);
+        void onPropertySubscribe(int property, int sampleRate);
+        void onPropertyUnsubscribe(int property);
+    }
+
+    private class VehicleHalMock implements VehicleNetworkHalMock {
+        private LinkedList<VehiclePropConfig> mConfigs = new LinkedList<>();
+        private HashMap<Integer, VehiclePropertyHandler> mHandlers = new HashMap<>();
+
+        public synchronized void registerProperty(VehiclePropConfig config,
+                VehiclePropertyHandler handler) {
+            int property = config.getProp();
+            mConfigs.add(config);
+            mHandlers.put(property, handler);
+        }
+
+        @Override
+        public synchronized VehiclePropConfigs onListProperties() {
+            Log.i(TAG, "onListProperties, num properties:" + mConfigs.size());
+            VehiclePropConfigs configs =
+                    VehiclePropConfigs.newBuilder().addAllConfigs(mConfigs).build();
+            return configs;
+        }
+
+        @Override
+        public void onPropertySet(VehiclePropValue value) {
+            int property = value.getProp();
+            VehiclePropertyHandler handler = getPropertyHandler(property);
+            if (handler == null) {
+                fail("onPropertySet for unknown property " + Integer.toHexString(property));
+            }
+            handler.onPropertySet(value);
+        }
+
+        @Override
+        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
+            int property = value.getProp();
+            VehiclePropertyHandler handler = getPropertyHandler(property);
+            if (handler == null) {
+                fail("onPropertyGet for unknown property " + Integer.toHexString(property));
+            }
+            return handler.onPropertyGet(value);
+        }
+
+        @Override
+        public void onPropertySubscribe(int property, int sampleRate) {
+            VehiclePropertyHandler handler = getPropertyHandler(property);
+            if (handler == null) {
+                fail("onPropertySubscribe for unknown property " + Integer.toHexString(property));
+            }
+            handler.onPropertySubscribe(property, sampleRate);
+        }
+
+        @Override
+        public void onPropertyUnsubscribe(int property) {
+            VehiclePropertyHandler handler = getPropertyHandler(property);
+            if (handler == null) {
+                fail("onPropertyUnsubscribe for unknown property " + Integer.toHexString(property));
+            }
+            handler.onPropertyUnsubscribe(property);
+        }
+
+        public synchronized VehiclePropertyHandler getPropertyHandler(int property) {
+            return mHandlers.get(property);
+        }
+    }
+
+    private class DefaultVehiclePropertyHandler implements VehiclePropertyHandler {
+        private VehiclePropValue mValue;
+
+        DefaultVehiclePropertyHandler(VehiclePropValue initialValue) {
+            mValue = initialValue;
+        }
+
+        @Override
+        public void onPropertySet(VehiclePropValue value) {
+            // TODO Auto-generated method stub
+        }
+
+        @Override
+        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue property) {
+            return mValue;
+        }
+
+        @Override
+        public void onPropertySubscribe(int property, int sampleRate) {
+            // TODO Auto-generated method stub
+        }
+
+        @Override
+        public void onPropertyUnsubscribe(int property) {
+            // TODO Auto-generated method stub
+        }
+    }
+}
diff --git a/tests/libvehiclenetwork-java-test/src/com/android/car/vehiclenetwork/libtest/VehicleNetworkTest.java b/tests/libvehiclenetwork-java-test/src/com/android/car/vehiclenetwork/libtest/VehicleNetworkTest.java
index 7e99044..cd22da6 100644
--- a/tests/libvehiclenetwork-java-test/src/com/android/car/vehiclenetwork/libtest/VehicleNetworkTest.java
+++ b/tests/libvehiclenetwork-java-test/src/com/android/car/vehiclenetwork/libtest/VehicleNetworkTest.java
@@ -90,6 +90,9 @@
         Log.i(TAG, "got configs:" + configs.getConfigsCount());
         for (VehiclePropConfig config : configs.getConfigsList()) {
             if ((config.getAccess() & VehiclePropAccess.VEHICLE_PROP_ACCESS_READ) != 0) {
+                if (config.getProp() == VehicleNetworkConsts.VEHICLE_PROPERTY_RADIO_PRESET) {
+                    continue;
+                }
                 if (config.getProp() >= VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_START &&
                         config.getProp() <= VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_END) {
                     // internal property requires write to read
@@ -206,6 +209,16 @@
             }
         }
 
+        @Override
+        public void onHalError(int errorCode, int property, int operation) {
+            // TODO Auto-generated method stub
+        }
+
+        @Override
+        public void onHalRestart(boolean inMocking) {
+            // TODO Auto-generated method stub
+        }
+
         private synchronized boolean waitForEvent(Integer prop, long timeoutMs)
                 throws InterruptedException {
             long now = SystemClock.elapsedRealtime();
diff --git a/tests/libvehiclenetwork-native-test/Android.mk b/tests/libvehiclenetwork-native-test/Android.mk
index 9b6980a..6392a93 100644
--- a/tests/libvehiclenetwork-native-test/Android.mk
+++ b/tests/libvehiclenetwork-native-test/Android.mk
@@ -18,7 +18,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(patsubst ./%,%, $(shell cd $(LOCAL_PATH); \
-    find . -name "*.cpp" -and -not -name ".*"))
+    find . -name "*.cpp" -and -not -name ".*")) \
+    TestPropertyDef.c
 
 LOCAL_C_INCLUDES += \
     packages/services/Car/libvehiclenetwork/include
diff --git a/tests/libvehiclenetwork-native-test/IVehicleNetworkMockedTest.cpp b/tests/libvehiclenetwork-native-test/IVehicleNetworkMockedTest.cpp
new file mode 100644
index 0000000..bae4e8a
--- /dev/null
+++ b/tests/libvehiclenetwork-native-test/IVehicleNetworkMockedTest.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/SystemClock.h>
+#include <IVehicleNetwork.h>
+
+#include "TestProperties.h"
+#include "VehicleHalMock.h"
+#include "IVehicleNetworkTestListener.h"
+
+namespace android {
+
+class IVehicleNetworkMockedTest : public testing::Test {
+public:
+    IVehicleNetworkMockedTest() {}
+
+    ~IVehicleNetworkMockedTest() {}
+
+    sp<IVehicleNetwork> connectToService() {
+        sp<IBinder> binder = defaultServiceManager()->getService(
+                String16(IVehicleNetwork::SERVICE_NAME));
+        if (binder != NULL) {
+            sp<IVehicleNetwork> vn(interface_cast<IVehicleNetwork>(binder));
+            return vn;
+        }
+        sp<IVehicleNetwork> dummy;
+        return dummy;
+    }
+
+protected:
+    virtual void SetUp() {
+        ProcessState::self()->startThreadPool();
+        mVN = connectToService();
+        ASSERT_TRUE(mVN.get() != NULL);
+        mHalMock = new VehicleHalMock();
+    }
+
+    virtual void TearDown() {
+        mVN->stopMocking(mHalMock);
+    }
+protected:
+    sp<VehicleHalMock> mHalMock;
+    sp<IVehicleNetwork> mVN;
+};
+
+const nsecs_t WAIT_TIMEOUT_NS = 1000000000;
+
+TEST_F(IVehicleNetworkMockedTest, connect) {
+    sp<IVehicleNetwork> vn = connectToService();
+    ASSERT_TRUE(vn.get() != NULL);
+}
+
+TEST_F(IVehicleNetworkMockedTest, listProperties) {
+    mVN->startMocking(mHalMock);
+    sp<VehiclePropertiesHolder> properties = mVN->listProperties();
+    ASSERT_TRUE(properties.get() != NULL);
+    ASSERT_TRUE(mHalMock->isTheSameProperties(properties));
+}
+
+TEST_F(IVehicleNetworkMockedTest, halRestart) {
+    sp<IVehicleNetworkTestListener> listener(new IVehicleNetworkTestListener());
+    int originalCount = listener->getHalRestartCount();
+    ASSERT_EQ(NO_ERROR, mVN->startHalRestartMonitoring(listener));
+    ASSERT_EQ(NO_ERROR, mVN->startMocking(mHalMock));
+    listener->waitForHalRestart(WAIT_TIMEOUT_NS);
+    ASSERT_EQ(originalCount + 1, listener->getHalRestartCount());
+    mVN->stopMocking(mHalMock);
+    listener->waitForHalRestart(WAIT_TIMEOUT_NS);
+    ASSERT_EQ(originalCount + 2, listener->getHalRestartCount());
+}
+
+TEST_F(IVehicleNetworkMockedTest, halGlobalError) {
+    sp<IVehicleNetworkTestListener> listener(new IVehicleNetworkTestListener());
+    ASSERT_EQ(NO_ERROR, mVN->startErrorListening(listener));
+    ASSERT_EQ(NO_ERROR, mVN->startMocking(mHalMock));
+    const int ERROR_CODE = -123;
+    const int OPERATION_CODE = 4567;
+    ASSERT_EQ(NO_ERROR, mVN->injectHalError(ERROR_CODE, 0, OPERATION_CODE));
+    listener->waitForHalError(WAIT_TIMEOUT_NS);
+    ASSERT_TRUE(listener->isErrorMatching(ERROR_CODE, 0, OPERATION_CODE));
+    mVN->stopErrorListening(listener);
+}
+
+TEST_F(IVehicleNetworkMockedTest, halPropertyError) {
+    sp<IVehicleNetworkTestListener> listener(new IVehicleNetworkTestListener());
+    ASSERT_EQ(NO_ERROR, mVN->startMocking(mHalMock));
+    ASSERT_EQ(NO_ERROR, mVN->subscribe(listener, TEST_PROPERTY_INT32, 0));
+    const int ERROR_CODE = -123;
+    const int OPERATION_CODE = 4567;
+    ASSERT_EQ(NO_ERROR, mVN->injectHalError(ERROR_CODE, TEST_PROPERTY_INT32, OPERATION_CODE));
+    listener->waitForHalError(WAIT_TIMEOUT_NS);
+    ASSERT_TRUE(listener->isErrorMatching(ERROR_CODE, TEST_PROPERTY_INT32, OPERATION_CODE));
+    mVN->unsubscribe(listener, TEST_PROPERTY_INT32);
+}
+
+}; // namespace android
diff --git a/tests/libvehiclenetwork-native-test/IVehicleNetwork_test.cpp b/tests/libvehiclenetwork-native-test/IVehicleNetworkTest.cpp
similarity index 76%
rename from tests/libvehiclenetwork-native-test/IVehicleNetwork_test.cpp
rename to tests/libvehiclenetwork-native-test/IVehicleNetworkTest.cpp
index 9015d8a..6463906 100644
--- a/tests/libvehiclenetwork-native-test/IVehicleNetwork_test.cpp
+++ b/tests/libvehiclenetwork-native-test/IVehicleNetworkTest.cpp
@@ -25,6 +25,8 @@
 #include <utils/SystemClock.h>
 #include <IVehicleNetwork.h>
 
+#include "IVehicleNetworkTestListener.h"
+
 namespace android {
 
 class IVehicleNetworkTest : public testing::Test {
@@ -57,68 +59,6 @@
     sp<IVehicleNetwork> mDefaultVN;
 };
 
-class IVehicleNetworkTestTestListener : public BnVehicleNetworkListener {
-public:
-    virtual status_t onEvents(sp<VehiclePropValueListHolder>& events) {
-        String8 msg("events ");
-        Mutex::Autolock autolock(mLock);
-        for (auto& e : events->getList()) {
-            ssize_t index = mEventCounts.indexOfKey(e->prop);
-            if (index < 0) {
-                mEventCounts.add(e->prop, 1); // 1st event
-                msg.appendFormat("0x%x:%d ", e->prop, 1);
-            } else {
-                int count = mEventCounts.valueAt(index);
-                count++;
-                mEventCounts.replaceValueAt(index, count);
-                msg.appendFormat("0x%x:%d ", e->prop, count);
-            }
-        }
-        msg.append("\n");
-        std::cout<<msg.string();
-        mCondition.signal();
-        return NO_ERROR;
-    }
-
-    void waitForEvents(nsecs_t reltime) {
-        Mutex::Autolock autolock(mLock);
-        mCondition.waitRelative(mLock, reltime);
-    }
-
-    bool waitForEvent(int32_t property, nsecs_t reltime) {
-        Mutex::Autolock autolock(mLock);
-        int startCount = getEventCountLocked(property);
-        int currentCount = startCount;
-        int64_t now = android::elapsedRealtimeNano();
-        int64_t endTime = now + reltime;
-        while ((startCount == currentCount) && (now < endTime)) {
-            mCondition.waitRelative(mLock, endTime - now);
-            currentCount = getEventCountLocked(property);
-            now = android::elapsedRealtimeNano();
-        }
-        return (startCount != currentCount);
-    }
-
-    int getEventCount(int32_t property) {
-        Mutex::Autolock autolock(mLock);
-        return getEventCountLocked(property);
-    }
-
-private:
-    int getEventCountLocked(int32_t property) {
-        ssize_t index = mEventCounts.indexOfKey(property);
-        if (index < 0) {
-            return 0;
-        } else {
-            return mEventCounts.valueAt(index);
-        }
-    }
-private:
-    Mutex mLock;
-    Condition mCondition;
-    KeyedVector<int32_t, int> mEventCounts;
-};
-
 TEST_F(IVehicleNetworkTest, connect) {
     sp<IVehicleNetwork> vn = connectToService();
     ASSERT_TRUE(vn.get() != NULL);
@@ -156,6 +96,9 @@
     int32_t numConfigs = properties->getList().size();
     ASSERT_TRUE(numConfigs > 0);
     for (auto& config : properties->getList()) {
+        if (config->prop == VEHICLE_PROPERTY_RADIO_PRESET) {
+            continue;
+        }
         String8 msg = String8::format("getting prop 0x%x\n", config->prop);
         std::cout<<msg.string();
         if ((config->prop >= (int32_t)VEHICLE_PROPERTY_INTERNAL_START) &&
@@ -188,6 +131,9 @@
     int32_t numConfigs = properties->getList().size();
     ASSERT_TRUE(numConfigs > 0);
     for (auto& config : properties->getList()) {
+        if (config->prop == VEHICLE_PROPERTY_RADIO_PRESET) {
+            continue;
+        }
         String8 msg = String8::format("setting prop 0x%x\n", config->prop);
         std::cout<<msg.string();
         ScopedVehiclePropValue value;
@@ -208,7 +154,7 @@
     ASSERT_TRUE(properties.get() != NULL);
     int32_t numConfigs = properties->getList().size();
     ASSERT_TRUE(numConfigs > 0);
-    sp<IVehicleNetworkTestTestListener> listener(new IVehicleNetworkTestTestListener());
+    sp<IVehicleNetworkTestListener> listener(new IVehicleNetworkTestListener());
     for (auto& config : properties->getList()) {
         String8 msg = String8::format("subscribing property 0x%x\n", config->prop);
         std::cout<<msg.string();
diff --git a/tests/libvehiclenetwork-native-test/IVehicleNetworkTestListener.h b/tests/libvehiclenetwork-native-test/IVehicleNetworkTestListener.h
new file mode 100644
index 0000000..d96e504
--- /dev/null
+++ b/tests/libvehiclenetwork-native-test/IVehicleNetworkTestListener.h
@@ -0,0 +1,135 @@
+/*
+ * 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_VEHICLE_TEST_LISTER_H
+#define ANDROID_VEHICLE_TEST_LISTER_H
+
+#include <IVehicleNetworkListener.h>
+
+namespace android {
+
+class IVehicleNetworkTestListener : public BnVehicleNetworkListener {
+public:
+    IVehicleNetworkTestListener() :
+        mHalRestartCount(0) {};
+
+    virtual void onEvents(sp<VehiclePropValueListHolder>& events) {
+        String8 msg("events ");
+        Mutex::Autolock autolock(mLock);
+        for (auto& e : events->getList()) {
+            ssize_t index = mEventCounts.indexOfKey(e->prop);
+            if (index < 0) {
+                mEventCounts.add(e->prop, 1); // 1st event
+                msg.appendFormat("0x%x:%d ", e->prop, 1);
+            } else {
+                int count = mEventCounts.valueAt(index);
+                count++;
+                mEventCounts.replaceValueAt(index, count);
+                msg.appendFormat("0x%x:%d ", e->prop, count);
+            }
+        }
+        msg.append("\n");
+        std::cout<<msg.string();
+        mCondition.signal();
+    }
+
+    virtual void onHalError(int32_t errorCode, int32_t property, int32_t operation) {
+        Mutex::Autolock autolock(mHalErrorLock);
+        mErrorCode = errorCode;
+        mProperty = property;
+        mOperation = operation;
+        mHalErrorCondition.signal();
+    }
+
+    virtual void onHalRestart(bool inMocking) {
+        Mutex::Autolock autolock(mHalRestartLock);
+        mHalRestartCount++;
+        mHalRestartCondition.signal();
+    }
+
+    void waitForEvents(nsecs_t reltime) {
+        Mutex::Autolock autolock(mLock);
+        mCondition.waitRelative(mLock, reltime);
+    }
+
+    bool waitForEvent(int32_t property, nsecs_t reltime) {
+        Mutex::Autolock autolock(mLock);
+        int startCount = getEventCountLocked(property);
+        int currentCount = startCount;
+        int64_t now = android::elapsedRealtimeNano();
+        int64_t endTime = now + reltime;
+        while ((startCount == currentCount) && (now < endTime)) {
+            mCondition.waitRelative(mLock, endTime - now);
+            currentCount = getEventCountLocked(property);
+            now = android::elapsedRealtimeNano();
+        }
+        return (startCount != currentCount);
+    }
+
+    int getEventCount(int32_t property) {
+        Mutex::Autolock autolock(mLock);
+        return getEventCountLocked(property);
+    }
+
+    int getHalRestartCount() {
+        Mutex::Autolock autolock(mHalRestartLock);
+        return mHalRestartCount;
+    }
+
+    void waitForHalRestart(nsecs_t reltime) {
+        Mutex::Autolock autolock(mHalRestartLock);
+        mHalRestartCondition.waitRelative(mHalRestartLock, reltime);
+    }
+
+    void waitForHalError(nsecs_t reltime) {
+        Mutex::Autolock autolock(mHalErrorLock);
+        mHalErrorCondition.waitRelative(mHalErrorLock, reltime);
+    }
+
+    bool isErrorMatching(int32_t errorCode, int32_t property, int32_t operation) {
+        Mutex::Autolock autolock(mHalErrorLock);
+        return mErrorCode == errorCode && mProperty == property && mOperation == operation;
+    }
+
+private:
+    int getEventCountLocked(int32_t property) {
+        ssize_t index = mEventCounts.indexOfKey(property);
+        if (index < 0) {
+            return 0;
+        } else {
+            return mEventCounts.valueAt(index);
+        }
+    }
+
+
+private:
+    Mutex mLock;
+    Condition mCondition;
+    KeyedVector<int32_t, int> mEventCounts;
+
+    Mutex mHalRestartLock;
+    Condition mHalRestartCondition;
+    int mHalRestartCount;
+
+    Mutex mHalErrorLock;
+    Condition mHalErrorCondition;
+    int32_t mErrorCode;
+    int32_t mProperty;
+    int32_t mOperation;
+};
+
+}; // namespace android
+#endif // ANDROID_VEHICLE_TEST_LISTER_H
diff --git a/tests/libvehiclenetwork-native-test/TestProperties.h b/tests/libvehiclenetwork-native-test/TestProperties.h
new file mode 100644
index 0000000..05366fc
--- /dev/null
+++ b/tests/libvehiclenetwork-native-test/TestProperties.h
@@ -0,0 +1,41 @@
+/*
+ * 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_VECHILE_TEST_PROPERTIES_H
+#define ANDROID_VECHILE_TEST_PROPERTIES_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <hardware/hardware.h>
+#include <hardware/vehicle.h>
+
+#define TEST_PROPERTY_STRING (VEHICLE_PROPERTY_CUSTOM_START + 1)
+#define TEST_PROPERTY_BYTES (VEHICLE_PROPERTY_CUSTOM_START + 2)
+#define TEST_PROPERTY_BOOLEAN (VEHICLE_PROPERTY_CUSTOM_START + 3)
+#define TEST_PROPERTY_ZONED_INT32 (VEHICLE_PROPERTY_CUSTOM_START + 4)
+#define TEST_PROPERTY_ZONED_FLOAT (VEHICLE_PROPERTY_CUSTOM_START + 5)
+#define TEST_PROPERTY_ZONED_BOOLEAN (VEHICLE_PROPERTY_CUSTOM_START + 6)
+#define TEST_PROPERTY_INT64 (VEHICLE_PROPERTY_CUSTOM_START + 7)
+#define TEST_PROPERTY_FLOAT (VEHICLE_PROPERTY_CUSTOM_START + 8)
+#define TEST_PROPERTY_FLOAT_VEC2 (VEHICLE_PROPERTY_CUSTOM_START + 9)
+#define TEST_PROPERTY_FLOAT_VEC3 (VEHICLE_PROPERTY_CUSTOM_START + 10)
+#define TEST_PROPERTY_FLOAT_VEC4 (VEHICLE_PROPERTY_CUSTOM_START + 11)
+#define TEST_PROPERTY_INT32 (VEHICLE_PROPERTY_CUSTOM_START + 12)
+#define TEST_PROPERTY_INT32_VEC2 (VEHICLE_PROPERTY_CUSTOM_START + 13)
+#define TEST_PROPERTY_INT32_VEC3 (VEHICLE_PROPERTY_CUSTOM_START + 14)
+#define TEST_PROPERTY_INT32_VEC4 (VEHICLE_PROPERTY_CUSTOM_START + 15)
+
+#endif /* ANDROID_VECHILE_TEST_PROPERTIES_H */
diff --git a/tests/libvehiclenetwork-native-test/TestPropertyDef.c b/tests/libvehiclenetwork-native-test/TestPropertyDef.c
new file mode 100644
index 0000000..5eacd17
--- /dev/null
+++ b/tests/libvehiclenetwork-native-test/TestPropertyDef.c
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "TestProperties.h"
+
+static vehicle_prop_config_t TEST_PROPERTIES[] = {
+    {
+        .prop = TEST_PROPERTY_STRING,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_STRING,
+        .config_flags = 0x1234, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_BYTES,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_BYTES,
+        .config_flags = 0x12345, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_BOOLEAN,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_BOOLEAN,
+        .config_flags = 0x123456, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_ZONED_INT32,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_ZONED_INT32,
+        .config_flags = 0x1234567, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_ZONED_FLOAT,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_ZONED_FLOAT,
+        .config_flags = 0x12345678, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_ZONED_BOOLEAN,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_ZONED_BOOLEAN,
+        .config_flags = 0x10, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_INT64,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_INT64,
+        .config_flags = 0x11, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_FLOAT,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_FLOAT,
+        .config_flags = 0x12, // just random
+        .float_min_value = 0.1f,
+        .float_max_value = 10.0f,
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_FLOAT_VEC2,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_FLOAT_VEC2,
+        .config_flags = 0x13, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_FLOAT_VEC3,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_FLOAT_VEC3,
+        .config_flags = 0x14, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_FLOAT_VEC4,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_FLOAT_VEC4,
+        .config_flags = 0x15, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_INT32,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_INT32,
+        .config_flags = 0x16, // just random
+        .int32_min_value = 10,
+        .int32_max_value = 100,
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_INT32_VEC2,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_INT32_VEC2,
+        .config_flags = 0x17, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_INT32_VEC3,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_INT32_VEC3,
+        .config_flags = 0x18, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+    {
+        .prop = TEST_PROPERTY_INT32_VEC4,
+        .access = VEHICLE_PROP_ACCESS_READ_WRITE,
+        .change_mode = VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
+        .value_type = VEHICLE_VALUE_TYPE_INT32_VEC4,
+        .config_flags = 0x0, // just random
+        .min_sample_rate = 0,
+        .max_sample_rate = 0,
+        .hal_data = NULL,
+    },
+};
+
+vehicle_prop_config_t const * getTestProperties() {
+    return TEST_PROPERTIES;
+}
+
+int getNumTestProperties() {
+    return sizeof(TEST_PROPERTIES) / sizeof(vehicle_prop_config_t);
+}
+
diff --git a/tests/libvehiclenetwork-native-test/VehicleHalMock.h b/tests/libvehiclenetwork-native-test/VehicleHalMock.h
new file mode 100644
index 0000000..6544fbb
--- /dev/null
+++ b/tests/libvehiclenetwork-native-test/VehicleHalMock.h
@@ -0,0 +1,84 @@
+/*
+ * 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_VEHICLE_HAL_MOCK_H
+#define ANDROID_VEHICLE_HAL_MOCK_H
+
+#include <IVehicleNetworkHalMock.h>
+
+extern "C" {
+vehicle_prop_config_t const * getTestProperties();
+int getNumTestProperties();
+};
+
+namespace android {
+
+class VehicleHalMock : public BnVehicleNetworkHalMock {
+public:
+    VehicleHalMock() {
+        mProperties = new VehiclePropertiesHolder(false /* deleteConfigsInDestructor */);
+        vehicle_prop_config_t const * properties = getTestProperties();
+        for (int i = 0; i < getNumTestProperties(); i++) {
+            mProperties->getList().push_back(properties + i);
+        }
+    };
+
+    virtual sp<VehiclePropertiesHolder> onListProperties() {
+        return mProperties;
+    };
+
+    virtual status_t onPropertySet(const vehicle_prop_value_t& value) {
+        //TODO
+        return NO_ERROR;
+    };
+
+    virtual status_t onPropertyGet(vehicle_prop_value_t* value) {
+        //TODO
+        return NO_ERROR;
+    };
+
+    virtual status_t onPropertySubscribe(int32_t property, float sampleRate) {
+        //TODO
+        return NO_ERROR;
+    };
+
+    virtual void onPropertyUnsubscribe(int32_t property) {
+        //TODO
+    };
+
+    bool isTheSameProperties(sp<VehiclePropertiesHolder>& list) {
+        if (mProperties->getList().size() != list->getList().size()) {
+            return false;
+        }
+        auto l = mProperties->getList().begin();
+        auto r = list->getList().begin();
+        while (l != mProperties->getList().end() && r != list->getList().end()) {
+            if (!VehiclePropertiesUtil::isTheSame(**l, **r)) {
+                return false;
+            }
+            l++;
+            r++;
+        }
+        return true;
+    }
+
+private:
+    sp<VehiclePropertiesHolder> mProperties;
+
+};
+
+}; // namespace android
+#endif /* ANDROID_VEHICLE_HAL_MOCK_H */
diff --git a/tests/libvehiclenetwork-native-test/VehicleNetwork_test.cpp b/tests/libvehiclenetwork-native-test/VehicleNetworkTest.cpp
similarity index 95%
rename from tests/libvehiclenetwork-native-test/VehicleNetwork_test.cpp
rename to tests/libvehiclenetwork-native-test/VehicleNetworkTest.cpp
index 018ce9c..25f80f2 100644
--- a/tests/libvehiclenetwork-native-test/VehicleNetwork_test.cpp
+++ b/tests/libvehiclenetwork-native-test/VehicleNetworkTest.cpp
@@ -61,6 +61,14 @@
         mCondition.signal();
     }
 
+    virtual void onHalError(int32_t errorCode, int32_t property, int32_t operation) {
+        //TODO
+    }
+
+    virtual void onHalRestart(bool inMocking) {
+        //TODO cannot test this in native world without plumbing mocking
+    }
+
     void waitForEvents(nsecs_t reltime) {
         Mutex::Autolock autolock(mLock);
         mCondition.waitRelative(mLock, reltime);
@@ -172,6 +180,9 @@
     int32_t numConfigs = properties->getList().size();
     ASSERT_TRUE(numConfigs > 0);
     for (auto& config : properties->getList()) {
+        if (config->prop == VEHICLE_PROPERTY_RADIO_PRESET) {
+            continue;
+        }
         String8 msg = String8::format("getting prop 0x%x\n", config->prop);
         std::cout<<msg.string();
         ScopedVehiclePropValue value;
@@ -195,6 +206,9 @@
     int32_t numConfigs = properties->getList().size();
     ASSERT_TRUE(numConfigs > 0);
     for (auto& config : properties->getList()) {
+        if (config->prop == VEHICLE_PROPERTY_RADIO_PRESET) {
+            continue;
+        }
         String8 msg = String8::format("setting prop 0x%x\n", config->prop);
         std::cout<<msg.string();
         ScopedVehiclePropValue value;