OSDN Git Service

HdmiCecLocalDeviceTest
authorAmy <amyjojo@google.com>
Thu, 24 May 2018 21:36:25 +0000 (14:36 -0700)
committerAmy <amyjojo@google.com>
Fri, 25 May 2018 22:26:49 +0000 (15:26 -0700)
Test: atest com.android.server.hdmi
Change-Id: Ic051138202531871b6227d57ef35038d0971e9e5

services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
services/core/java/com/android/server/hdmi/HdmiControlService.java
services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java [new file with mode: 0644]

index 0cba76b..5681367 100755 (executable)
@@ -16,6 +16,7 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.input.InputManager;
 import android.os.Handler;
@@ -31,6 +32,7 @@ import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -249,11 +251,11 @@ abstract class HdmiCecLocalDevice {
             case Constants.MESSAGE_SET_MENU_LANGUAGE:
                 return handleSetMenuLanguage(message);
             case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS:
-                return handleGivePhysicalAddress();
+                return handleGivePhysicalAddress(null);
             case Constants.MESSAGE_GIVE_OSD_NAME:
                 return handleGiveOsdName(message);
             case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
-                return handleGiveDeviceVendorId();
+                return handleGiveDeviceVendorId(null);
             case Constants.MESSAGE_GET_CEC_VERSION:
                 return handleGetCecVersion(message);
             case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
@@ -325,23 +327,23 @@ abstract class HdmiCecLocalDevice {
     }
 
     @ServiceThreadOnly
-    protected boolean handleGivePhysicalAddress() {
+    protected boolean handleGivePhysicalAddress(@Nullable SendMessageCallback callback) {
         assertRunOnServiceThread();
 
         int physicalAddress = mService.getPhysicalAddress();
         HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                 mAddress, physicalAddress, mDeviceType);
-        mService.sendCecCommand(cecMessage);
+        mService.sendCecCommand(cecMessage, callback);
         return true;
     }
 
     @ServiceThreadOnly
-    protected boolean handleGiveDeviceVendorId() {
+    protected boolean handleGiveDeviceVendorId(@Nullable SendMessageCallback callback) {
         assertRunOnServiceThread();
         int vendorId = mService.getVendorId();
         HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
                 mAddress, vendorId);
-        mService.sendCecCommand(cecMessage);
+        mService.sendCecCommand(cecMessage, callback);
         return true;
     }
 
index 8c00be5..4ad51de 100644 (file)
@@ -22,7 +22,7 @@ import android.util.SparseArray;
 /**
  * A helper class to validates {@link HdmiCecMessage}.
  */
-public final class HdmiCecMessageValidator {
+public class HdmiCecMessageValidator {
     private static final String TAG = "HdmiCecMessageValidator";
 
     static final int OK = 0;
index ba6da05..a1753e5 100644 (file)
@@ -68,6 +68,7 @@ import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.SystemService;
@@ -290,6 +291,9 @@ public class HdmiControlService extends SystemService {
     @Nullable
     private PowerManager mPowerManager;
 
+    @Nullable
+    private Looper mIoLooper;
+
     // Last input port before switching to the MHL port. Should switch back to this port
     // when the mobile device sends the request one touch play with off.
     // Gets invalidated if we go to other port/input.
@@ -383,13 +387,18 @@ public class HdmiControlService extends SystemService {
 
     @Override
     public void onStart() {
-        mIoThread.start();
+        if (mIoLooper == null) {
+            mIoThread.start();
+            mIoLooper = mIoThread.getLooper();
+        }
         mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON;
         mProhibitMode = false;
         mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true);
         mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true);
 
-        mCecController = HdmiCecController.create(this);
+        if (mCecController == null) {
+            mCecController = HdmiCecController.create(this);
+        }
         if (mCecController != null) {
             if (mHdmiControlEnabled) {
                 initializeCec(INITIATED_BY_BOOT_UP);
@@ -406,7 +415,9 @@ public class HdmiControlService extends SystemService {
         mMhlDevices = Collections.emptyList();
 
         initPortInfo();
-        mMessageValidator = new HdmiCecMessageValidator(this);
+        if (mMessageValidator == null) {
+            mMessageValidator = new HdmiCecMessageValidator(this);
+        }
         publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
 
         if (mCecController != null) {
@@ -424,6 +435,11 @@ public class HdmiControlService extends SystemService {
         mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED);
     }
 
+    @VisibleForTesting
+    void setCecController(HdmiCecController cecController) {
+        mCecController = cecController;
+    }
+
     @Override
     public void onBootPhase(int phase) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
@@ -747,8 +763,19 @@ public class HdmiControlService extends SystemService {
      *
      * <p>Declared as package-private.
      */
+    @Nullable
     Looper getIoLooper() {
-        return mIoThread.getLooper();
+        return mIoLooper;
+    }
+
+    @VisibleForTesting
+    void setIoLooper(Looper ioLooper) {
+        mIoLooper = ioLooper;
+    }
+
+    @VisibleForTesting
+    void setMessageValidator(HdmiCecMessageValidator messageValidator) {
+        mMessageValidator = messageValidator;
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
new file mode 100644 (file)
index 0000000..78cb56b
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.hdmi;
+
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID;
+import static com.android.server.hdmi.Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.hardware.hdmi.HdmiPortInfo;
+import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
+import android.os.MessageQueue;
+import com.android.server.hdmi.HdmiCecController.NativeWrapper;
+import junit.framework.Assert;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/**
+ * Tests for {@link HdmiCecLocalDevice} class.
+ */
+public class HdmiCecLocalDeviceTest {
+
+    private static final class NativeWrapperImpl implements NativeWrapper {
+
+        @Override
+        public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
+            return 1L;
+        }
+
+        @Override
+        public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
+            byte[] body) {
+            return SendCecCommandFactory(srcAddress, dstAddress, body);
+        }
+
+        @Override
+        public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
+            return 0;
+        }
+
+        @Override
+        public void nativeClearLogicalAddress(long controllerPtr) {
+
+        }
+
+        @Override
+        public int nativeGetPhysicalAddress(long controllerPtr) {
+            return mPhysicalAddr;
+        }
+
+        @Override
+        public int nativeGetVersion(long controllerPtr) {
+            return 0;
+        }
+
+        @Override
+        public int nativeGetVendorId(long controllerPtr) {
+            return 0;
+        }
+
+        @Override
+        public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
+            return new HdmiPortInfo[0];
+        }
+
+        @Override
+        public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {
+
+        }
+
+        @Override
+        public void nativeSetLanguage(long controllerPtr, String language) {
+
+        }
+
+        @Override
+        public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {
+
+        }
+
+        @Override
+        public boolean nativeIsConnected(long controllerPtr, int port) {
+            return false;
+        }
+    }
+
+    private static int SendCecCommandFactory(int srcAddress, int dstAddress, byte[] body) {
+        switch(body[0] & 0xFF) {
+            /** {@link Constants#MESSAGE_GIVE_PHYSICAL_ADDRESS} */
+            case MESSAGE_REPORT_PHYSICAL_ADDRESS:
+            case MESSAGE_DEVICE_VENDOR_ID:
+                return srcAddress == mSrcAddr &&
+                    dstAddress == mDesAddr &&
+                    Arrays.equals(Arrays.copyOfRange(body, 1, body.length), param)? 0 : 1;
+            default:
+                return 1;
+        }
+    }
+
+    private class MyHdmiCecLocalDevice extends HdmiCecLocalDevice {
+
+
+        protected MyHdmiCecLocalDevice(HdmiControlService service, int deviceType) {
+            super(service, deviceType);
+        }
+
+        @Override
+        protected void onAddressAllocated(int logicalAddress, int reason) {
+
+        }
+
+        @Override
+        protected int getPreferredAddress() {
+            return 0;
+        }
+
+        @Override
+        protected void setPreferredAddress(int addr) {
+
+        }
+    }
+
+    private MyHdmiCecLocalDevice mHdmiLocalDevice;
+    private HdmiControlService mHdmiControlService;
+    private HdmiCecController mHdmiCecController;
+    private TestLooper mTestLooper = new TestLooper();
+    private static int mDesAddr = -1;
+    private static int mSrcAddr = -1;
+    private static int mPhysicalAddr = 2;
+    private int callbackResult;
+    private HdmiCecMessageValidator mMessageValidator;
+    private static byte[] param;
+
+    @Before
+    public void SetUp() {
+        mHdmiControlService = new HdmiControlService(null);
+        mHdmiControlService.setIoLooper(mTestLooper.getLooper());
+        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+            mHdmiControlService, new NativeWrapperImpl());
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiLocalDevice = new MyHdmiCecLocalDevice(
+            mHdmiControlService, DEVICE_TV);
+        mMessageValidator = new HdmiCecMessageValidator(mHdmiControlService){
+            @Override
+            int isValid(HdmiCecMessage message) {
+                return HdmiCecMessageValidator.OK;
+            }
+        };
+        mHdmiControlService.setMessageValidator(mMessageValidator);
+    }
+
+    @Test
+    public void dispatchMessage_desNotValid() {
+        HdmiCecMessage msg = new HdmiCecMessage(
+            ADDR_TV, ADDR_TV, Constants.MESSAGE_CEC_VERSION, HdmiCecMessage.EMPTY_PARAM);
+        boolean handleResult = mHdmiLocalDevice.dispatchMessage(msg);
+        assertFalse(handleResult);
+    }
+
+    @Test
+    public void handleGivePhysicalAddress_success() {
+        mSrcAddr = ADDR_UNREGISTERED;
+        mDesAddr = ADDR_BROADCAST;
+        param = new byte[] {
+            (byte) ((mPhysicalAddr >> 8) & 0xFF),
+            (byte) (mPhysicalAddr & 0xFF),
+            (byte) (DEVICE_TV & 0xFF)
+        };
+        callbackResult = -1;
+        boolean handleResult = mHdmiLocalDevice.handleGivePhysicalAddress(
+            (int finalResult) -> callbackResult = finalResult);
+        mTestLooper.dispatchAll();
+        /**
+         * Test if CecMessage is sent successfully
+         * SendMessageResult#SUCCESS is defined in HAL as 0
+         */
+        assertEquals(0, callbackResult);
+        assertTrue(handleResult);
+    }
+
+    @Test
+    public void handleGiveDeviceVendorId_success() {
+        mSrcAddr = ADDR_UNREGISTERED;
+        mDesAddr = ADDR_BROADCAST;
+        /** nativeGetVendorId returns 0 */
+        param = new byte[] {
+            (byte) ((0 >> 8) & 0xFF),
+            (byte) (0 & 0xFF),
+            (byte) (0 & 0xFF)
+        };
+        callbackResult = -1;
+        mHdmiLocalDevice.handleGiveDeviceVendorId(
+            (int finalResult) -> callbackResult = finalResult);
+        mTestLooper.dispatchAll();
+        assertEquals(0, callbackResult);
+    }
+}