標籤:Google認證、GMS認證、XTS失敗項分析、Android、cts
做者:秋城 https://www.cnblogs.com/houser0323
java
AndroidTV機頂盒項目的Google認證包含8項測試:CTS、GTS、STS、VTS、CTS-ON-GSI、TVTS、SmokeTest、CtsVerifier、BTS,詳細的規範要求見文檔:GTVS Requirements、ATV Help#Android TV Certification。linux
本文着重講述一個AndroidTV項目認證流程中的技術環節,即xts失敗項分析。儘管這些測試內容方法以及測試用例實現不一,但其分析解決流程都是相同的:確認失敗項、確認測試內容、修復。android
ps:BTS本文不討論。c++
一份測試報告提供出來,它的失敗項全都須要開發人員分析嗎?每每不是這樣。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:
|
基本上,像cts這樣測試套件自動化的測試,調整儘量ok的環境恢復出廠retry屢次至失敗項再也不減小時,能夠認爲是真正的失敗項了。就能夠發出報告與日誌安排對應模塊開發人員分析。安全
冒煙測試和ctsVerifier是手工測試,若測試不過,基本是有問題的,應直接介入分析。bash
自動化的幾個測試都是相似的,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 plan、YouTube and Play Movies Video Test Pack、YouTube and Play Movies Video Test Pack | 按照表格指示逐條人工測試 | 驗證基本功能是否正常。Android TV functional;YouTube & Play Movies compatibility & performance |
大部分的測試用例均是該種形式,組織爲一個測試apk,推送到Android設備運行並返回測試結果。他們的源碼定位方式以下。
以第二節中camera項爲例查找對應tag的代碼。此處推薦兩個網站https://android.googlesource.com
與https://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.txt
與results/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 "> <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拖進去便可,有跳轉有行號。
典型的是部分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調用棧,因此經過搜索來確認。
如今,咱們有了報告和日誌、能夠100%復現的場景與設備,而且擁有了程序源碼。已經沒有什麼能阻擋咱們分析bug了。以後的流程與其餘Android的bug分析,或者說,和計算機編程領域的問題分析是徹底一致的。
接下來,咱們進行幾個xts失敗項的分析,如此來對xts分析有個感性的印象。
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小結。
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機制。
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.
CtsVerifier 9.0-r11
失敗項:Bluetooth Test --> Bluetooth LE Secure Client Test --> 01 BlueTooth LE Client Test
先說結論。
藍牙驅動修改引入,轉交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
失敗項到手,先確認他的來源。新工具引入?上個版本有嗎?最近有什麼修改?這些信息對縮小範圍很重要。
xts測試是不少且雜的,一我的去掌控全局我的感受會很吃力。因此有不熟悉的模塊問題,要分發給對應模塊同窗分析。例如媒體、網絡、驅動等等。
善用搜索引擎,獲取直接或者間接的答案與知識。
對比和二分法是你最後的依靠。若是你沒有頭緒或者進展緩慢,時間緊迫時就回退版本吧。衆所周知二分法的時間複雜度是O(lgn)。
修改驗證時,瞭解編譯框架會使你事半功倍。僅替換apk,so仍是某個文件。或者刷個img鏡像也比編譯OTA包快的多。