淺談Google認證失敗項分析

淺談Google認證失敗項分析

標籤:Google認證、GMS認證、XTS失敗項分析、Android、cts
做者:秋城 https://www.cnblogs.com/houser0323
java

1、概述

AndroidTV機頂盒項目的Google認證包含8項測試:CTS、GTS、STS、VTS、CTS-ON-GSI、TVTS、SmokeTest、CtsVerifier、BTS,詳細的規範要求見文檔:GTVS RequirementsATV Help#Android TV Certificationlinux

本文着重講述一個AndroidTV項目認證流程中的技術環節,即xts失敗項分析。儘管這些測試內容方法以及測試用例實現不一,但其分析解決流程都是相同的:確認失敗項、確認測試內容、修復android

ps:BTS本文不討論。c++

2、確認失敗項

一份測試報告提供出來,它的失敗項全都須要開發人員分析嗎?每每不是這樣。git

經驗來講這其中會有許多的環境相關項。好比未接camera、HDMI;未接入支持ipv6的wifi網絡或網絡環境太差;未恢復出廠retry等等。還有Google認爲能夠失敗的waiver項(通常是Google的測試用例bug致使)。shell

如下是幾個常常見到的環境相關項編程

armeabi-v7a CtsMediaTestCases
Test Result Details
android.media.cts.DecodeAccuracyTest#testSurfaceViewLargerHeightDecodeAccuracy[22] fail junit.framework.AssertionFailedError: With the best matched border crop (0.0, 0.0), greatest pixel difference is 167 at (60, 32) which is over the allowed difference 90
armeabi-v7a CtsNetTestCases
Test Result Details
android.net.cts.DnsTest#testDnsWorks fail junit.framework.AssertionFailedError: [RERUN] DNS could not resolve www.google.com. Check internet connection
armeabi-v7a CtsCameraTestCases
Test Result Details
android.hardware.camera2.cts.CameraManagerTest#testCameraManagerGetDeviceIdList fail junit.framework.AssertionFailedError: External camera is not connected on device with FEATURE_CAMERA_EXTERNAL
android.hardware.cts.CameraTest#testCameraExternalConnected fail junit.framework.AssertionFailedError: Devices with external camera support must have a camera connected for testing

如下是當前的一條cts-on-gsi測試wavier項,適用2020-10月system.img與VTS_9.0_R14工具。waiver項是動態更新的,Google收到各廠商反饋後,會在下個版本修復,因此要及時跟進同步。api

armeabi-v7a CtsOsTestCases
Test Result Details
android.os.cts.LocaleListTest#testRepeatedArguments fail junit.framework.AssertionFailedError: expected: but was:

基本上,像cts這樣測試套件自動化的測試,調整儘量ok的環境恢復出廠retry屢次至失敗項再也不減小時,能夠認爲是真正的失敗項了。就能夠發出報告與日誌安排對應模塊開發人員分析。安全

冒煙測試和ctsVerifier是手工測試,若測試不過,基本是有問題的,應直接介入分析。bash

3、分析前的一些背景知識

3.1 xts測試的工具、源碼及形式

自動化的幾個測試都是相似的,apk的形式安裝到Android設備中進行測試,sts有部分會推送二進制到設備執行,vts會執行一些命令來獲取底層信息。

測試名 工具獲取 源碼獲取 測試形式 測試目的
CTS cts測試套件,公開下載。Compatibility Test Suite Downloads AOSP 設備端以JUnit tests和apk的形式測試。Types of test cases包含單元測試與功能測試 Android平臺兼容性。CDD + Android SDK/NDK/APIs
STS sts測試套件,非公開。同安全補丁一塊兒發佈Security Test Suite 部分AOSP 設備端測試junit tests和主機端二進制推送值設備測試。Security Test Suite#Types of test cases 測試安全漏洞。每月和安全補丁一塊兒更新。Security patch compliance
VTS vts測試套件,非公開。Vendor Test Suite (VTS) and Generic System Image (GSI) AOSP 主要是執行shell命令Device shell commands 替換GSI後測試框架如下的部分。HAL、驅動與內核。Treble compliance
CTS-ON-GSI 同vts。 AOSP 同cts 替換GSI後測試一遍CTS。Treble compliance
GTS gts測試套件,非公開。Downloading and Running GTS 反編譯獲取 同cts 用於驗證GMS應用程序是否正確集成。Platform implementation for GTVS services
TVTS tvts測試套件,非公開。TV Test Suite 反編譯獲取 同cts 用於驗證GMS應用程序性能。Performance
CtsVerfier CtsVerfier測試工具包,公開下載Compatibility Test Suite Downloads AOSP 安裝CtsVerifier.apk後按條測,半自動 cts的補充測試,須要人工判斷。CDD + Android SDK/NDK/APIs
SmokeTest 表格,非公開。Smoke Test planYouTube and Play Movies Video Test PackYouTube and Play Movies Video Test Pack 按照表格指示逐條人工測試 驗證基本功能是否正常。Android TV functional;YouTube & Play Movies compatibility & performance

3.2 經過報告定位到測試源碼

3.2.1 device端的apk形式測試用例

大部分的測試用例均是該種形式,組織爲一個測試apk,推送到Android設備運行並返回測試結果。他們的源碼定位方式以下。

以第二節中camera項爲例查找對應tag的代碼。此處推薦兩個網站https://android.googlesource.comhttps://cs.android.com。通常是在cs.android上搜測試類名方法名,找到路徑後去googlesource查找對應tag的精確的代碼。

或者本身維護一個aosp的工程,隨時到子庫中切換至對應分支tag。

  • CtsCameraTestCases是模塊名,每每構建爲測試套件中的一個apk或jar包。見測試套件目錄:

    ./android-cts/testcases/CtsCameraTestCases.apk
    ./android-cts/testcases/CtsCameraTestCases.config```
  • android.hardware.camera2.cts.CameraManagerTest是測試用例包名加類名。見aosp工程:

    platform/cts/tests/camera/src/android/hardware/camera2/cts$```
  • testCameraManagerGetDeviceIdList是測試方法名

    CameraManagerTest.java
    140:    public void testCameraManagerGetDeviceIdList() throws Exception {```
  • 定位異常行。

    java寫的測試用例會有異常調用棧的打印。在對應測試結果與日誌目錄下倆文件,logs/2020.11.10_15.03.26/inv_xxx/host_log_xxx.txtresults/2020.11.10_15.03.26/test_result.xml

    <TestCase name="android.hardware.camera2.cts.CameraManagerTest">
          <Test result="pass" name="testCameraManagerGetCameraCharacteristics" />
          <Test result="fail" name="testCameraManagerGetDeviceIdList">
            <Failure message="junit.framework.AssertionFailedError: External camera is not connected on device with FEATURE_CAMERA_EXTERNAL&#13;">
              <StackTrace>junit.framework.AssertionFailedError: External camera is not connected on device with FEATURE_CAMERA_EXTERNAL
    	at junit.framework.Assert.fail(Assert.java:50)
    	at junit.framework.Assert.assertTrue(Assert.java:20)
    	at android.hardware.camera2.cts.CameraManagerTest.testCameraManagerGetDeviceIdList(CameraManagerTest.java:172)
    	at java.lang.reflect.Method.invoke(Native Method)
    	at junit.framework.TestCase.runTest(TestCase.java:168)
    	at junit.framework.TestCase.runBare(TestCase.java:134)
    	at junit.framework.TestResult$1.protect(TestResult.java:115)
    	at androidx.test.internal.runner.junit3.AndroidTestResult.runProtected(AndroidTestResult.java:73)
    	at junit.framework.TestResult.run(TestResult.java:118)
    	at androidx.test.internal.runner.junit3.AndroidTestResult.run(AndroidTestResult.java:51)
    	at junit.framework.TestCase.run(TestCase.java:124)
    	at androidx.test.internal.runner.junit3.NonLeakyTestSuite$NonLeakyTest.run(NonLeakyTestSuite.java:62)
    	at androidx.test.internal.runner.junit3.AndroidTestSuite$2.run(AndroidTestSuite.java:101)
    	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
    	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    	at java.lang.Thread.run(Thread.java:764)

關於GTS、TVTS咱們如何處置?因爲不開源,因此只能去測試套件下反編譯響應模塊的apk或jar來閱讀測試代碼。我通常是jadx-gui拖進去便可,有跳轉有行號。

3.2.2 host端的測試用例

典型的是部分vts測試用例。咱們看下面這條測試。

armeabi-v7a VtsKernelProcFileApi
Test Result Details
VtsKernelProcFileApi#testProcMemInfoTest fail Failed to parse! Failed to parse line MemTotal: 2056324 kB according to rule {:name}: {:lu}{:^kb}
  • 定位測試模塊

    :~/platform/test/vts-testcase/kernel/api/proc$```
    
    確認下模塊名**VtsKernelProcFileApi**
    
    ```test/vts-testcase/kernel/api/proc$ ag VtsKernelProcFileApi
    Android.bp
    18:    name: "VtsKernelProcFileApi",
    
    AndroidTest.xml
    26:        <option name="test-module-name" value="VtsKernelProcFileApi" />
    27:        <option name="test-case-path" value="vts/testcases/kernel/api/proc/VtsKernelProcFileApiTest" />
    
    VtsKernelProcFileApiTest.py
    123:class VtsKernelProcFileApiTest(base_test.BaseTestClass):
  • 定位測試方法

    ag ProcMemInfoTest
    ProcMemInfoTest.py
    35:class ProcMemInfoTest(KernelProcFileTestBase.KernelProcFileTestBase):`
    
    VtsKernelProcFileApiTest.py
    32:from vts.testcases.kernel.api.proc import ProcMemInfoTest
    63:    ProcMemInfoTest.ProcMemInfoTest(),
  • 定位crash異常代碼行

    test/vts-testcase/kernel/api/proc$ ag "Failed to parse line"
    KernelProcFileTestBase.py
    159:            raise SyntaxError("Failed to parse line %s according to rule %s" %

    和3.2.1中狀況不一樣,因爲測試用例不是device端,沒有crash調用棧,因此經過搜索來確認。

4、 幾個分析案例

如今,咱們有了報告和日誌、能夠100%復現的場景與設備,而且擁有了程序源碼。已經沒有什麼能阻擋咱們分析bug了。以後的流程與其餘Android的bug分析,或者說,和計算機編程領域的問題分析是徹底一致的。

接下來,咱們進行幾個xts失敗項的分析,如此來對xts分析有個感性的印象。

4.1 cts

Suite / Plan CTS / cts
Suite / Build 10_r5 / 6723298

armeabi-v7a CtsHardwareTestCases
Test Result Details
android.hardware.consumerir.cts.ConsumerIrTest#test_timing fail junit.framework.AssertionFailedError: Pattern length pattern:499995000, actual:1192958
at junit.framework.Assert.fail(Assert.java:50)
at junit.framework.Assert.assertTrue(Assert.java:20)
at android.hardware.consumerir.cts.ConsumerIrTest.test_timing(ConsumerIrTest.java:94)
  • 先說結論。

    這是Q版本上的一條失敗項,失敗的緣由是bsp需求開發佔用了響應的gpio,致使consumerIr這個紅外發射功能,驅動是沒有實現的。測試用例調用響應接口去發射紅外,而後指望一段時間有結果。實際花費時間要在指望值的0.5倍到1.5倍之間。因爲咱們驅動是空實現,因此直接異常返回致使用時很是短。測試失敗。

  • 解決方案。

    解決方案明顯的,有兩條路,咱們不須要紅外發射功能,因此能夠去掉,咱們採用這項;另外一條就是底層真正實現它了。

  • 分析詳細

    測試代碼:cts/tests/tests/hardware/src/android/hardware/consumerir/cts/ConsumerIrTest.java

    public void test_timing() {
            if (!mHasConsumerIr) {
                // Skip the test if consumer IR is not present.
                return;
            }
    
            ConsumerIrManager.CarrierFrequencyRange[] freqs = mCIR.getCarrierFrequencies();
            // Transmit two seconds for min and max for each frequency range
            int[] pattern = {11111, 22222, 33333, 44444, 55555, 66666, 77777, 88888, 99999};
            long totalXmitTimeNanos = 0; // get the length of the pattern
            for (int slice : pattern) {
                totalXmitTimeNanos += slice * 1000; // add the time in nanoseconds
            }
            double margin = 0.5; // max fraction xmit is allowed to be off timing
    
            for (ConsumerIrManager.CarrierFrequencyRange range : freqs) {
                // test min freq
                long currentTime = SystemClock.elapsedRealtimeNanos();
                mCIR.transmit(range.getMinFrequency(), pattern);
                long newTime = SystemClock.elapsedRealtimeNanos();
                String msg = String.format("Pattern length pattern:%d, actual:%d",
                        totalXmitTimeNanos, newTime - currentTime);
                assertTrue(msg, newTime - currentTime >= totalXmitTimeNanos * (1.0 - margin));
                assertTrue(msg, newTime - currentTime <= totalXmitTimeNanos * (1.0 + margin));
    
                // test max freq
                currentTime = SystemClock.elapsedRealtimeNanos();
                mCIR.transmit(range.getMaxFrequency(), pattern);
                newTime = SystemClock.elapsedRealtimeNanos();
                msg = String.format("Pattern length pattern:%d, actual:%d",
                        totalXmitTimeNanos, newTime - currentTime);
                assertTrue(msg, newTime - currentTime >= totalXmitTimeNanos * (1.0 - margin));
                assertTrue(msg, newTime - currentTime <= totalXmitTimeNanos * (1.0 + margin));//1
            }
        }

    如上是測試代碼,在註釋//1處斷言拋異常,說明實際時間過小了。到底爲何小呢?ConsumerIrManager#transmit。咱們往下跟這個方法。

    /**
         * Transmit an infrared pattern
         * <p>
         * This method is synchronous; when it returns the pattern has
         * been transmitted. Only patterns shorter than 2 seconds will
         * be transmitted.
         * </p>
         *
         * @param carrierFrequency The IR carrier frequency in Hertz.
         * @param pattern The alternating on/off pattern in microseconds to transmit.
         */
        public void transmit(int carrierFrequency, int[] pattern) {
            if (mService == null) {
                Log.w(TAG, "failed to transmit; no consumer ir service.");
                return;
            }
    
            try {
                mService.transmit(mPackageName, carrierFrequency, pattern);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

    字面意思,接收指定的頻率和模式來發射紅外。繼續去服務實現裏看

    frameworks/base/services/core/java/com/android/server/ConsumerIrService.java

    @Override
        public void transmit(String packageName, int carrierFrequency, int[] pattern) {
    ...
            // Right now there is no mechanism to ensure fair queing of IR requests
            synchronized (mHalLock) {
                int err = halTransmit(carrierFrequency, pattern);//1
    ...

    註釋//1這裏開始進入c層代碼,經過jni走進hal層而後溝通驅動裏的實現。

    frameworks/base/services/core/jni/com_android_server_ConsumerIrService.cpp

    #include <android/hardware/ir/1.0/IConsumerIr.h>
    #include <nativehelper/ScopedPrimitiveArray.h>
    
    using ::android::hardware::ir::V1_0::IConsumerIr;
    using ::android::hardware::ir::V1_0::ConsumerIrFreqRange;
    using ::android::hardware::hidl_vec;
    
    namespace android {
    
    static sp<IConsumerIr> mHal;
    
    static jboolean halOpen(JNIEnv* /* env */, jobject /* obj */) {
        // TODO(b/31632518)
        mHal = IConsumerIr::getService();
        return mHal != nullptr;
    }
    
    static jint halTransmit(JNIEnv *env, jobject /* obj */, jint carrierFrequency,
       jintArray pattern) {
        ScopedIntArrayRO cPattern(env, pattern);
        if (cPattern.get() == NULL) {
            return -EINVAL;
        }
        hidl_vec<int32_t> patternVec;
        patternVec.setToExternal(const_cast<int32_t*>(cPattern.get()), cPattern.size());
    
        bool success = mHal->transmit(carrierFrequency, patternVec);//1
        return success ? 0 : -1;
    }

    到這裏要去找hal的具體實現,須要瞭解hal層實現規則。能夠擴展學習下Android Treble架構解析

    穿越hal層,最終跟到hardware目錄下的驅動實現,結合日誌發現寫節點失敗了

    hardware/xxx/consumerir/consumerir.cpp

    static int consumerir_transmit(struct consumerir_device *dev __unused,
        int carrier_freq, const int pattern[], int pattern_len) {
    ...
        writeSys(IR_xxx_SEND, pPatterns, strlen(pPatterns));

    日誌:

    10-02 07:20:49.706  3273  3273 E ConsumerIrHal: writeSysFs, open /sys/devices/virtual/irblaster/xxx/send fail. No such file or directory

    從框架角度開看問題的話,至此能夠下結論了。原來失敗是由於驅動實現異常,節點不存在,根本沒去發射因此耗時很短。轉交了bsp去解決。後來bsp的動做是去掉了框架裏FEATURE_CONSUMER_IR。可是這也埋下了vts另外一個問題的伏筆。就是接下來的4.2小結。

4.2 vts

Suite / Plan VTS / vts
Suite / Build 10_r5 / 6719887

armeabi-v7a VtsTrebleFrameworkVintfTest
Test Result Details
VtsTrebleFrameworkVintfTest#SystemVendorTest.ServedHwbinderHalsAreInManifest_32bit fail test/vts-testcase/hal/treble/vintf/SystemVendorTest.cpp:131 Expected: (manifest_hwbinder_hals.find(name)) != (manifest_hwbinder_hals.end()), actual: 4-byte object <E8-17 F6-FF> vs 4-byte object <E8-17 F6-FF> android.hardware.ir@1.0::IConsumerIr/default is being served, but it is not in a manifest
  • 先說結論。

    4.1節提到的cts失敗項,去除feature時,僅將feature配置android.hardware.consumerir.xml

    vendor/etc/vintf/manifest.xml中hidl配置刪除。

    <hal format="hidl">
        <name>android.hardware.ir</name>
        <transport>hwbinder</transport>
        <version>1.0</version>
        <interface>
            <name>IConsumerIr</name>
            <instance>default</instance>
        </interface>
        <fqname>@1.0::IConsumerIr/default</fqname>
    </hal>

    沒有進一步刪除init.rc中的服務。如此致使雖沒有hal聲明,可是服務進程仍會開機啓動。

    該項測試即要求hal的聲明與啓動的服務保持一致:SystemVendorTest.ServedHwbinderHalsAreInManifest_32bit

    $ ps -e |grep ir
    system        3357     1   11020   3912 0                   0 S android.hardware.ir@1.0-service
    
    $ logcat |grep -i 3357
    01-01 00:00:10.747  3357  3357 I ConsumerIrHal: consumerir hal open success
    01-01 00:00:10.753  3357  3357 I ServiceManagement: Registered android.hardware.ir@1.0::IConsumerIr/default (start delay of 207ms)
    01-01 00:00:10.753  3357  3357 I ServiceManagement: Removing namespace from process name android.hardware.ir@1.0-service to ir@1.0-service.
    01-01 00:00:10.754  3357  3357 I android.hardware.ir@1.0-service: Registration complete for android.hardware.ir@1.0::IConsumerIr/default.
  • 解決方案

    送佛送到西,把ConsumerIr的HAL層及如下代碼所有送走。

    $ git diff
    diff --git a/products/xxx/xxx.mk b/products/xxx/xxx.mk
    index be77805..9cdab74 100644
    --- a/products/xxx/xxx.mk
    +++ b/products/xxx/xxx.mk
    @@ -237,16 +237,19 @@ endif
     #                      ConsumerIr
     #
     #########################################################################
    -PRODUCT_PACKAGES += \
    +#---20201107---
    +#delete ConsumerIr service for cts/vts
    +
    +#PRODUCT_PACKAGES += \
         consumerir.app
     #PRODUCT_COPY_FILES += \
     #    frameworks/native/data/etc/android.hardware.consumerir.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.consumerir.xml
     #consumerir hal
    -PRODUCT_PACKAGES += \
    -    android.hardware.ir@1.0-impl \
    -    android.hardware.ir@1.0-service
    +#PRODUCT_PACKAGES += \
    +#    android.hardware.ir@1.0-impl \
    +#    android.hardware.ir@1.0-service
  • 分析詳細

    測試代碼:test/vts-testcase/hal/treble/vintf/SystemVendorTest.cpp

    // This needs to be tested besides
    // SingleManifestTest.ServedHwbinderHalsAreInManifest because some HALs may
    // refuse to provide its PID, and the partition cannot be inferred.
    TEST_F(SystemVendorTest, ServedHwbinderHalsAreInManifest) {
      auto device_manifest = VintfObject::GetDeviceHalManifest();
      ASSERT_NE(device_manifest, nullptr) << "Failed to get device HAL manifest.";
      auto fwk_manifest = VintfObject::GetFrameworkHalManifest();
      ASSERT_NE(fwk_manifest, nullptr) << "Failed to get framework HAL manifest.";
    
      std::set<std::string> manifest_hwbinder_hals;
    
      insert(&manifest_hwbinder_hals, GetHwbinderHals(fwk_manifest));
      insert(&manifest_hwbinder_hals, GetHwbinderHals(device_manifest));
    
      Return<void> ret = default_manager_->list([&](const auto &list) {
        for (const auto &name : list) {
          // TODO(b/73774955): use standardized parsing code for fqinstancename
          if (std::string(name).find(IBase::descriptor) == 0) continue;
    
          EXPECT_NE(manifest_hwbinder_hals.find(name), manifest_hwbinder_hals.end())
              << name << " is being served, but it is not in a manifest.";//1
        }
      });
      EXPECT_TRUE(ret.isOk());
    }

    註釋//1處斷言拋異常,字面意思,hal實體服務啓動後在serviceManaegr裏已註冊,可是manifest.xml裏未做聲明。這段代碼涉及init進程啓動rc裏聲明的服務、serviceManager的服務註冊以及hidl服務的註冊。涉及的東西很經典,邏輯很清晰。

  • 還有一點

    有同窗看到這可能要問了。代碼我看了,爲何這麼麻煩,剛開始4.1那條只刪除feature不就沒這麼多事兒了?

    確實這是個很好的思路,第一點想到這裏,是很正確的方向。可是嘗試後發現,system_server進程會crash,由於啓動階段有代碼限制了這樣作。因此不能夠僅僅刪除feature。

    frameworks/base/services/java/com/android/server/SystemServer.java

    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
                if (!isWatch) {
                    t.traceBegin("StartConsumerIrService");
                    consumerIr = new ConsumerIrService(context);
                    ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
                    t.traceEnd();
                }

    frameworks/base/services/core/java/com/android/server/ConsumerIrService.java

    ConsumerIrService(Context context) {
            mContext = context;
            PowerManager pm = (PowerManager)context.getSystemService(
                    Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
            mWakeLock.setReferenceCounted(true);
    
            mHasNativeHal = halOpen();//1
            if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CONSUMER_IR)) {
                if (!mHasNativeHal) {
                    throw new RuntimeException("FEATURE_CONSUMER_IR present, but no IR HAL loaded!");
                }
            } else if (mHasNativeHal) {
                throw new RuntimeException("IR HAL present, but FEATURE_CONSUMER_IR is not set!");
            }
        }

    註釋//1以後的代碼作了雙向限制,保證hal與feature同在。不然system_server進程會一直crash,最終觸發Rescure party機制。

4.3 gts

Suite / Plan GTS / gts
Suite / Build 7.0_r3 / 6045416

armeabi-v7a GtsSecurityHostTestCases
Test Result Details
com.google.android.security.gts.SELinuxHostTest#testNoExemptionsForSocketsBetweenCoreAndVendorBan fail junit.framework.AssertionFailedError: Policy exempts domains from ban on socket communications between core and vendor: [hal_audio_default]
at junit.framework.Assert.fail(Assert.java:57)
at junit.framework.TestCase.fail(TestCase.java:227)
at com.google.android.security.gts.SELinuxHostTest.testNoExemptionsForSocketsBetweenCoreAndVendorBan(SELinuxHostTest.java:221)
  • 先說結論。

    google的waiver項。

  • 分析詳細。

    測試用例的邏輯:

    使用linux可執行程序:sepolicy-analyze,對機頂盒中的/sys/fs/selinux/policy文件進行解析,要求不能有返回值,命令是:
    sepolicy-analyze policy attribute socket_between_core_and_vendor_violators
    即:不容許有type(類型)與該attribute(屬性)「socket_between_core_and_vendor_violators」有關聯,字面意思:core與vendor的違規socket特權。

    分析測試代碼:反編譯後定位測試項
    ./com/google/android/security/gts/SELinuxHostTest.java

    public void testNoExemptionsForVendorExecutingCore() throws Exception {
            if (isFullTrebleDevice()) {
                Set<String> types = sepolicyAnalyzeGetTypesAssociatedWithAttribute("vendor_executes_system_violators");//1
                if (!types.isEmpty()) {
                    List<String> sortedTypes = new ArrayList(types);
                    Collections.sort(sortedTypes);
                    fail("Policy exempts vendor domains from ban on executing files in /system: " + sortedTypes);//
                }
            }
        }

    註釋//1:進去繼續確認測試邏輯:sepolicyAnalyzeGetTypesAssociatedWithAttribute()

    註釋//2:此處assert,緣由是容器types有東西,東西就是‘[hal_audio_default]’

    private Set<String> sepolicyAnalyzeGetTypesAssociatedWithAttribute(String attribute) throws Exception {
            BufferedReader in;
            Throwable th;
            Throwable th2;
            Set<String> types = new HashSet();
            ProcessBuilder pb = new ProcessBuilder(new String[]{this.mSepolicyAnalyze.getAbsolutePath(), this.mDevicePolicyFile.getAbsolutePath(), "attribute", attribute});//1
    ......
                in = new BufferedReader(new InputStreamReader(p.getInputStream()));
                th = null;
                while (true) {
                    try {
                        String type = in.readLine();
                        if (type != null) {
                            types.add(type.trim());//2 
                        }}} 
    ......
            return types;
    ......
        }

    註釋//1:經過ProcessBuilder開啓一個進程,用於執行linux命令:sepolicy-analyze policy attribute socket_between_core_and_vendor_violators

    註釋//2:獲取有效標準輸出,寫到結果容器中存儲

    如今基本邏輯就清楚了,只要這個命令執行有結果返回就是不被容許的,如今須要分析這個工具‘sepolicy-analyze’是幹嗎的?
    在Android工程源碼中搜索,咱們找到了這個host可執行程序的源碼
    system/sepolicy/tools/sepolicy-analyze/
    結合網絡資料以及閱讀源碼和README文檔,澄清測試的命令用途:解析policy文件返回與attribute相關聯的type值

    工程中搜索確認到底在哪裏使得他們關聯的,定位到文件

    ./system/sepolicy/vendor/hal_audio_default.te:1
    type hal_audio_default, domain, socket_between_core_and_vendor_violators;

    查證git log,咱們發現是以下的commit致使的,是google的auto-path,後續澄清爲waiver項。

    commit 1234567
    Author: xxxxxx
    Date:   Mon Feb 17 11:33:16 2020 +0800
    
        auto patch added:CecAudio
    
    diff --git a/vendor/hal_audio_default.te b/vendor/hal_audio_default.te
    index 0dc2170..9da0f1b 100644
    --- a/vendor/hal_audio_default.te
    +++ b/vendor/hal_audio_default.te
    @@ -1,4 +1,4 @@
    -type hal_audio_default, domain;
    +type hal_audio_default, domain, socket_between_core_and_vendor_violators; #此處添加的關聯,問題找到了根源  
     hal_server_domain(hal_audio_default, hal_audio)
  • 相關資料:

    system/sepolicy/tools/sepolicy-analyze/README

    ATTRIBUTE (attribute)
    sepolicy-analyze out/target/product//root/sepolicy attribute
    Displays the types associated with the specified attribute name.

    該權限詳細限制在如下代碼中有論述,Android TREBLE架構相關
    system/sepolicy/prebuilts/api/26.0/public/domain.te system/sepolicy/prebuilts/api/27.0/public/domain.te system/sepolicy/prebuilts/api/28.0/public/domain.te: system/sepolicy/public/domain.te

    # On full TREBLE devices, socket communications between core components and vendor components are
    # not permitted.
    full_treble_only(`
      # Most general rules first, more specific rules below.
    
      # Core domains are not permitted to initiate communications to vendor domain sockets.
      # We are not restricting the use of already established sockets because it is fine for a process
      # to obtain an already established socket via some public/official/stable API and then exchange
      # data with its peer over that socket. The wire format in this scenario is dicatated by the API
      # and thus does not break the core-vendor separation.

4.4 cts verifier

CtsVerifier 9.0-r11

失敗項:Bluetooth Test --> Bluetooth LE Secure Client Test --> 01 BlueTooth LE Client Test

verifier-fail

  • 先說結論。

    藍牙驅動修改引入,轉交bsp修復。

    該項測試流程概述:
    Client測試pass後作出先關閉mAdapter.disable()後打開mAdapter.enable()的動做,經梳理藍牙框流程發現,藍牙關閉後再次打開超時失敗,由此致使該測試Activity沒法收到廣播,沒法將按鈕設置爲可選。

  • 分析詳細。

    測試代碼
    1.測試Activity,提供ui無業務代碼
    cts/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleSecureClientStartActivity.java
    2.上面(1)的父類,測試結果處理
    cts/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestBaseActivity.java
    3.測試Service,真正的測試項執行
    cts/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java

    流程梳理
    1.啓動BleSecureClientStartActivity。該測試頁面只是一個activity-ui。主要的方法實現和流程動做都在父類Activity中,重點關注父類。
    2.調用父類BleClientTestBaseActivity的onCreate()完成:
    頁面顯示、設置底部pass-fail-button按鍵的監聽、設置pass-button爲disable不可選
    初始化頁面的測試項ListView
    回到子類繼續onCreate():顯示info提示信息的dialog、啓動BleClientService準備測試

    3.調用父類BleClientTestBaseActivity的onResume():
    註冊測試服務BleClientService的廣播監聽BroadcastReceiver mBroadcast

    4.開始測試
    這個測試是倆設備Server-Client配對測試,自動觸發,細節略,和Server端之間的藍牙通訊有關
    listview每一條測試結束都會有廣播發出,接收廣播後將mPassed作或運算,若是一切順利mPassed的運算結果是PASS_FLAG_ALL
    這表明測試項所有經過

    private static final int PASS_FLAG_ALL = 0x3FFFF;

    而後Client端將藍牙關閉mAdapter.disable()再打開mAdapter.enable(),打開成功狀況下Activity纔會將Pass-Button設置爲可選擇
    因爲驅動代碼出問題,遂enable()失敗,沒法設置按鈕可選

    關鍵日誌

    測試All-PASS

    04-21 16:52:05.901 D/BluetoothGatt( 6338): onClientConnectionState() - status=0 clientIf=6 device=7B:D0:42:AC:47:B6
    04-21 16:52:05.901 D/BleClientService( 6338): onConnectionStateChange: status= 0, newState= 0
    04-21 16:52:05.901 D/BluetoothGatt( 6338): close()
    04-21 16:52:05.901 D/BluetoothGatt( 6338): unregisterApp() - mClientIf=6
    04-21 16:52:05.915 D/BleClientTestBase( 6338): Processing com.android.cts.verifier.bluetooth.BLE_BLUETOOTH_DISCONNECTED
    04-21 16:52:05.921 D/BleClientTestBase( 6338): Passed Flags has changed from 0x0003FDFF to 0x0003FFFF. Delta=0x00000200
    04-21 16:52:05.921 D/BleClientTestBase( 6338): All Tests Passed.

    藍牙正常關閉

    04-21 16:52:06.931 D/AdapterProperties( 3406): Setting state to TURNING_OFF
    04-21 16:52:07.038 I/AdapterState( 3406): BLE_TURNING_OFF : entered 
    04-21 16:52:07.057 I/bt_btif_core( 3406): btif_disable_bluetooth finished

    藍牙開啓超時

    04-21 16:52:17.051 D/BluetoothManagerService( 3297): enable(com.android.cts.verifier):  mBluetooth =null mBinding = false mState = OFF
    04-21 16:52:17.288 D/BluetoothAdapterService( 7058): bleOnProcessStart()
    04-21 16:52:17.290 D/BluetoothManagerService( 3297): MESSAGE_BLUETOOTH_STATE_CHANGE: OFF > BLE_TURNING_ON
    04-21 16:52:17.290 D/BluetoothManagerService( 3297): Sending BLE State Change: OFF > BLE_TURNING_ON
    ......
    04-21 16:52:21.292 E/AdapterState( 7058): BLE_TURNING_ON : BLE_START_TIMEOUT
    04-21 16:52:21.293 I/AdapterState( 7058): BLE_TURNING_OFF : entered

5、經驗之談

失敗項到手,先確認他的來源。新工具引入?上個版本有嗎?最近有什麼修改?這些信息對縮小範圍很重要。

xts測試是不少且雜的,一我的去掌控全局我的感受會很吃力。因此有不熟悉的模塊問題,要分發給對應模塊同窗分析。例如媒體、網絡、驅動等等。

善用搜索引擎,獲取直接或者間接的答案與知識。

對比和二分法是你最後的依靠。若是你沒有頭緒或者進展緩慢,時間緊迫時就回退版本吧。衆所周知二分法的時間複雜度是O(lgn)。

修改驗證時,瞭解編譯框架會使你事半功倍。僅替換apk,so仍是某個文件。或者刷個img鏡像也比編譯OTA包快的多。

6、一些資料、工具

相關文章
相關標籤/搜索