<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          人臉解鎖帶來的安卓系統(tǒng)崩潰之謎!

          共 21665字,需瀏覽 44分鐘

           ·

          2023-11-10 13:57

          問題背景

          用戶反饋開啟人臉解鎖后,偶現(xiàn)密碼解鎖、指紋解鎖、人臉解鎖均無法使用,系統(tǒng)卡死隨后出現(xiàn)安卓重啟。

          問題分析

          SWT之初步釋疑

          查看android SWT(Software Watchdog Timeout)日志,發(fā)現(xiàn)android.ui線程卡死。

          1
          Subject: Blocked in handler on ui thread (android.ui)

          查看android.ui堆棧,可以看到該線程一直在等鎖,鎖id為0x05158af1。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          30
          31
          32
          33
          34
          35
          36
          37
          38
          39
          40
          41
          42
          43
          44
          45
          46
          47
          48
          49
          50
          "android.ui" prio=5 tid=12 Blocked
          | group="main" sCount=1 ucsCount=0 flags=1 obj=0x17f405e8 self=0xb400007df01a8800
          | sysTid=2904 nice=-2 cgrp=top-app sched=0/0 handle=0x7de7bbbcb0
          | state=S schedstat=( 8623914505397 6889640642861 50368108 ) utm=519874 stm=342516 core=5 HZ=100
          | stack=0x7de7ab8000-0x7de7aba000 stackSize=1039KB
          | held mutexes=
          at com.android.server.locksettings.LockSettingsService.getCredentialTypeInternal(LockSettingsService.java:1341)
          - waiting to lock <0x05158af1> (a com.android.server.locksettings.SyntheticPasswordManager) held by thread 178
          at com.android.server.locksettings.LockSettingsService.getCredentialType(LockSettingsService.java:1328)
          at com.android.internal.widget.LockPatternUtils$1.apply(LockPatternUtils.java:946)
          at com.android.internal.widget.LockPatternUtils$1.apply(LockPatternUtils.java:942)
          at android.app.PropertyInvalidatedCache.recompute(PropertyInvalidatedCache.java:754)
          at android.app.PropertyInvalidatedCache.query(PropertyInvalidatedCache.java:971)
          at com.android.internal.widget.LockPatternUtils.getCredentialTypeForUser(LockPatternUtils.java:985)
          at com.android.internal.widget.LockPatternUtils.getKeyguardStoredPasswordQuality(LockPatternUtils.java:819)
          at com.flyme.server.policy.view.FlymeConfirmPasswordView.getPasswordType(FlymeConfirmPasswordView.java:238)
          at com.flyme.server.policy.view.FlymeConfirmPasswordView.refreshViews(FlymeConfirmPasswordView.java:118)
          at com.flyme.server.policy.view.FlymeConfirmPasswordView.initViews(FlymeConfirmPasswordView.java:114)
          at com.flyme.server.policy.view.FlymeConfirmPasswordView.<init>(FlymeConfirmPasswordView.java:81)
          at com.flyme.server.policy.view.FlymeConfirmPasswordView.<init>(FlymeConfirmPasswordView.java:75)
          at java.lang.reflect.Constructor.newInstance0(Native method)
          at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
          at android.view.LayoutInflater.createView(LayoutInflater.java:858)
          at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1010)
          at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:965)
          at android.view.LayoutInflater.rInflate(LayoutInflater.java:1127)
          at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)
          at android.view.LayoutInflater.rInflate(LayoutInflater.java:1130)
          at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1088)
          at android.view.LayoutInflater.inflate(LayoutInflater.java:686)
          - locked <0x0f6a962a> (a java.lang.Object[])
          at android.view.LayoutInflater.inflate(LayoutInflater.java:538)
          at android.view.LayoutInflater.inflate(LayoutInflater.java:485)
          at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:474)
          at android.app.Dialog.setContentView(Dialog.java:597)
          at com.flyme.server.policy.MzGlobalActions$MzGlobalActionsDialog.onCreate(MzGlobalActions.java:326)
          at android.app.Dialog.dispatchOnCreate(Dialog.java:436)
          at android.app.Dialog.show(Dialog.java:325)
          at com.flyme.server.policy.MzGlobalActions$MzGlobalActionsDialog.show(MzGlobalActions.java:824)
          at com.flyme.server.policy.MzGlobalActions.showGlobalActionsDialog(MzGlobalActions.java:177)
          at com.flyme.server.policy.MzGlobalActions.showGlobalActionsDialog(MzGlobalActions.java:134)
          at com.android.server.policy.PhoneWindowManager.mzShowGlobalActionsInternal(PhoneWindowManager.java:6358)
          at com.android.server.policy.PhoneWindowManager.showGlobalActionsInternal(PhoneWindowManager.java:1641)
          at com.android.server.policy.PhoneWindowManager$PolicyHandler.handleMessage(PhoneWindowManager.java:676)
          at android.os.Handler.dispatchMessage(Handler.java:106)
          at android.os.Looper.loopOnce(Looper.java:201)
          at android.os.Looper.loop(Looper.java:288)
          at android.os.HandlerThread.run(HandlerThread.java:67)
          at com.android.server.ServiceThread.run(ServiceThread.java:44)
          at com.android.server.UiThread.run(UiThread.java:45)

          在SWT日志中查找上述鎖id,可以找到如下線程持鎖未釋放。

          從堆棧上來看,locksettings在進行verifyChallenge調(diào)用時,binder對端沒有返回。
          locksettings的對端是gatekeeperd。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          "binder:2869_1C" prio=5 tid=178 Native
          | group="main" sCount=1 ucsCount=0 flags=1 obj=0x1821f850 self=0xb400007dc0652800
          | sysTid=18660 nice=0 cgrp=foreground sched=0/0 handle=0x7dc0fdbcb0
          | state=S schedstat=( 2488346381691 2190821996172 10125980 ) utm=144692 stm=104142 core=5 HZ=100
          | stack=0x7dc0ee4000-0x7dc0ee6000 stackSize=991KB
          | held mutexes=
          native: #00 pc 00000000000e06fc /apex/com.android.runtime/lib64/bionic/libc.so (__ioctl+12) (BuildId: c7a69636ad70437896f8f6cfecde9001)
          native: #01 pc 000000000009757c /apex/com.android.runtime/lib64/bionic/libc.so (ioctl+160) (BuildId: c7a69636ad70437896f8f6cfecde9001)
          native: #02 pc 000000000005c2a0 /system/lib64/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+284) (BuildId: b5f24c77eb4cb8038980e4e1f81dcfc0)
          native: #03 pc 000000000005d4fc /system/lib64/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+76) (BuildId: b5f24c77eb4cb8038980e4e1f81dcfc0)
          native: #04 pc 000000000005d238 /system/lib64/libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+224) (BuildId: b5f24c77eb4cb8038980e4e1f81dcfc0)
          native: #05 pc 0000000000054a44 /system/lib64/libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+192) (BuildId: b5f24c77eb4cb8038980e4e1f81dcfc0)
          native: #06 pc 0000000000176bf8 /system/lib64/libandroid_runtime.so (android_os_BinderProxy_transact(_JNIEnv*, _jobject*, int, _jobject*, _jobject*, int)+156) (BuildId: da5ff736bfee156debca012f9a4e67da)
          at android.os.BinderProxy.transactNative(Native method)
          at android.os.BinderProxy.transact(BinderProxy.java:584)
          at android.service.gatekeeper.IGateKeeperService$Stub$Proxy.verifyChallenge(IGateKeeperService.java:349)
          at com.android.server.locksettings.SyntheticPasswordManager.unwrapPasswordBasedSyntheticPassword(SyntheticPasswordManager.java:1091)
          at com.android.server.locksettings.LockSettingsService.spBasedDoVerifyCredential(LockSettingsService.java:2999)
          - locked <0x05158af1> (a com.android.server.locksettings.SyntheticPasswordManager)
          at com.android.server.locksettings.LockSettingsService.doVerifyCredential(LockSettingsService.java:2355)
          at com.android.server.locksettings.LockSettingsService.checkCredential(LockSettingsService.java:2269)
          at com.android.internal.widget.ILockSettings$Stub.onTransact(ILockSettings.java:649)
          at android.os.Binder.execTransactInternal(Binder.java:1285)
          at android.os.Binder.execTransact(Binder.java:1244)

          上述線程所在的進程pid為2869,線程tid為18660。

          在binderinfo中查找2869:18660,可以看到outgoing事務已經(jīng)送出,gatekeeperd的pid為2448,tid為2448。

          1
          2
          thread 18660: l 11 need_return 0 tr 0
          outgoing transaction 1265277307: 0000000000000000 from 2869:18660 to 2448:2448 code 3 flags 30 pri 0:120 r1

          在binderinfo中找到gatekeeperd的binder信息,可以看到gatekeeperd已經(jīng)收到incoming事務。

          1
          2
          3
          4
          5
          6
          7
          8
          proc 2448
          context binder
          thread 2448: l 02 need_return 0 tr 0
          incoming transaction 1265277307: 0000000000000000 from 2869:18660 to 2448:2448 code 3 flags 30 pri 0:120 r1 node 2469 size 252:0 data 0000000000000000
          node 2469: ub40000758600c1a0 cb400007586009188 pri 0:139 hs 1 hw 1 ls 1 lw 0 is 2 iw 2 tr 1 proc 2869 1121
          ref 2436: desc 0 node 1 s 1 w 1 d 0000000000000000
          ref 100653: desc 1 node 15289 s 1 w 1 d 0000000000000000
          buffer 57317755: 0000000000000000 size 252:0:0 active

          gatekeeper需要通過gatekeeper HAL(android.hardware.gatekeeper-service-qti)來實現(xiàn)功能。

          gatekeeper只有一個線程,主線程既負責處理binder請求,也負責發(fā)起hwbinder請求,因此gatekeeperd binder請求無返回,說明gatekeeper HAL hwbinder請求無返回。
          查看gatekeeperd的hwbinder上下文,可以看到outgoing事務已經(jīng)送出,對端pid為1336,tid為1336。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          proc 2448
          context hwbinder
          thread 2448: l 10 need_return 0 tr 0
          outgoing transaction 1265277317: 0000000000000000 from 2448:2448 to 1336:1336 code 2 flags 30 pri 0:120 r1
          transaction complete
          thread 6226: l 12 need_return 0 tr 0
          ref 2437: desc 0 node 3 s 1 w 1 d 0000000000000000
          ref 2447: desc 1 node 210 s 1 w 1 d 0000000000000000
          ref 100646: desc 2 node 1233 s 1 w 1 d 0000000000000000

          繼續(xù)查看gatekeeper HAL的binder信息,可以看到gatekeeper HAL已經(jīng)收到incoming事務。

          1
          2
          3
          4
          5
          6
          7
          proc 1336
          context hwbinder
          thread 1336: l 02 need_return 0 tr 0
          incoming transaction 1265277317: 0000000000000000 from 2448:2448 to 1336:1336 code 2 flags 30 pri 0:120 r1 node 210 size 220:32 data 0000000000000000
          node 210: ub4000072b120c340 cb4000072b12220a0 pri 0:120 hs 1 hw 1 ls 1 lw 0 is 2 iw 2 tr 1 proc 2448 1122
          ref 178: desc 0 node 3 s 1 w 1 d 0000000000000000
          buffer 57317765: 0000000000000000 size 220:32:160 active

          gatekeeper HAL是基于TEE相關的接口來實現(xiàn)功能的,因此需要查看該進程在用戶空間的堆棧,分析hwbinder無返回原因。

          比較遺憾的是,SWT日志中并沒有關于gatekeeper HAL在用戶空間的堆棧,但從psinfo日志也可以看到,gatekeeper HAL處理hwbinder的線程處于D狀態(tài)。
          Linux進程D狀態(tài)(TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態(tài)。
          線程在某個時刻處于D狀態(tài)并不能說明該線程就是異常的,但如果長時間處于D狀態(tài),那么很可能就是有問題的。

          1
          2
          3
          4
          5
          system        1336  1336     1 2243616   3572 process_invoke_req  0 D gatekeeper@1.0-
          system 1336 1349 1 2243616 3572 process_accept_req 0 S gatekeeper@1.0-
          system 1336 1350 1 2243616 3572 process_accept_req 0 S gatekeeper@1.0-
          system 1336 1351 1 2243616 3572 process_accept_req 0 S gatekeeper@1.0-
          system 1336 1352 1 2243616 3572 process_accept_req 0 S gatekeeper@1.0-

          從sysrq打印所有D狀態(tài)進程堆棧來看,該線程連續(xù)2秒都處于D狀態(tài),在gatekeeper HAL的業(yè)務上不可能有這么長時間,因此判定此線程異常。

          1
          2
          3
          [Tue May  9 14:58:24 2023] task:gatekeeper@1.0- state:D stack:11152 pid: 1336 ppid:     1 flags:0x04000008
          [Tue May 9 14:58:25 2023] task:gatekeeper@1.0- state:D stack:11152 pid: 1336 ppid: 1 flags:0x04000008
          [Tue May 9 14:58:26 2023] task:gatekeeper@1.0- state:D stack:11152 pid: 1336 ppid: 1 flags:0x04000008

          內(nèi)核態(tài)之真兇查找

          通過前面的分析,已知系統(tǒng)發(fā)生SWT是由于gatekeeper HAL處理hwbinder的線程陷入內(nèi)核態(tài)且長時間處于D狀態(tài)。
          結合sysrq打印所有D狀態(tài)進程堆棧信息,可以看到該線程在內(nèi)核中等鎖。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          [Tue May  9 14:58:24 2023] task:gatekeeper@1.0- state:D stack:11152 pid: 1336 ppid:     1 flags:0x04000008
          [Tue May 9 14:58:24 2023] Call trace:
          [Tue May 9 14:58:24 2023] __switch_to+0x240/0x490
          [Tue May 9 14:58:24 2023] __schedule+0x638/0xacc
          [Tue May 9 14:58:24 2023] schedule+0x110/0x204
          [Tue May 9 14:58:24 2023] schedule_preempt_disabled+0x2c/0x4c
          [Tue May 9 14:58:24 2023] __mutex_lock+0x328/0x824
          [Tue May 9 14:58:24 2023] __mutex_lock_slowpath+0x18/0x28
          [Tue May 9 14:58:24 2023] mutex_lock+0x48/0x118
          [Tue May 9 14:58:24 2023] process_invoke_req+0x1f0/0x80c [smcinvoke_dlkm]
          [Tue May 9 14:58:24 2023] smcinvoke_ioctl+0x80/0x404 [smcinvoke_dlkm]
          [Tue May 9 14:58:24 2023] __arm64_sys_ioctl+0x184/0x210
          [Tue May 9 14:58:24 2023] invoke_syscall+0x60/0x150
          [Tue May 9 14:58:24 2023] el0_svc_common+0xb8/0xf8
          [Tue May 9 14:58:24 2023] do_el0_svc+0x28/0xa0
          [Tue May 9 14:58:24 2023] el0_svc+0x24/0x84
          [Tue May 9 14:58:24 2023] el0t_64_sync_handler+0x88/0xec
          [Tue May 9 14:58:24 2023] el0t_64_sync+0x1b4/0x1b8

          process_invoke_req函數(shù)的地址為0x000000000000818c。

          1
          2
          nm smcinvoke_dlkm.ko | grep -w process_invoke_req
          000000000000818c t process_invoke_req

          因此process_invoke_req+0x1f0的地址為0x000000000000837c,對應的代碼位置如下。

          1
          2
          aarch64-linux-gnu-addr2line -e smcinvoke_dlkm.ko 0x000000000000837c
          vendor/qcom/opensource/securemsm-kernel/smcinvoke/smcinvoke.c:2320

          查看代碼,發(fā)現(xiàn)是smcinvoke驅動中的全局鎖g_smcinvoke_lock被持有未釋放。

          1
          mutex_lock(&g_smcinvoke_lock);

          查看sysrq打印所有CPU堆棧信息,在CPU7上確實有線程持鎖未釋放。

          但由于日志缺少足夠的信息,因此并無法知道此時運行在CPU7上的進程。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          29
          [Tue May  9 14:58:24 2023] sysrq: CPU7:
          [Tue May 9 14:58:24 2023] Call trace:
          [Tue May 9 14:58:24 2023] dump_backtrace.cfi_jt+0x0/0x8
          [Tue May 9 14:58:24 2023] showacpu+0xf8/0x1b4
          [Tue May 9 14:58:24 2023] flush_smp_call_function_queue+0x1f0/0x3a8
          [Tue May 9 14:58:24 2023] do_handle_IPI+0xe0/0x344
          [Tue May 9 14:58:24 2023] ipi_handler+0x20/0x34
          [Tue May 9 14:58:24 2023] handle_percpu_devid_irq+0xc0/0x374
          [Tue May 9 14:58:24 2023] handle_domain_irq+0xd0/0x154
          [Tue May 9 14:58:24 2023] gic_handle_irq.33729+0x54/0x2bc
          [Tue May 9 14:58:24 2023] call_on_irq_stack+0x40/0x70
          [Tue May 9 14:58:24 2023] do_interrupt_handler+0x44/0xa0
          [Tue May 9 14:58:24 2023] el1_interrupt+0x34/0x64
          [Tue May 9 14:58:24 2023] el1h_64_irq_handler+0x1c/0x2c
          [Tue May 9 14:58:24 2023] el1h_64_irq+0x7c/0x80
          [Tue May 9 14:58:24 2023] __arm_smccc_smc+0x14/0x40
          [Tue May 9 14:58:24 2023] __scm_smc_call+0x1b8/0x56c [qcom_scm]
          [Tue May 9 14:58:24 2023] qcom_scm_invoke_callback_response+0xa8/0x12c [qcom_scm]
          [Tue May 9 14:58:24 2023] invoke_cmd_handler+0x120/0x254 [smcinvoke_dlkm]
          [Tue May 9 14:58:24 2023] prepare_send_scm_msg+0x15c/0x450 [smcinvoke_dlkm]
          [Tue May 9 14:58:24 2023] process_invoke_req+0x294/0x80c [smcinvoke_dlkm]
          [Tue May 9 14:58:24 2023] smcinvoke_ioctl+0x80/0x404 [smcinvoke_dlkm]
          [Tue May 9 14:58:24 2023] __arm64_sys_ioctl+0x184/0x210
          [Tue May 9 14:58:24 2023] invoke_syscall+0x60/0x150
          [Tue May 9 14:58:24 2023] el0_svc_common+0xb8/0xf8
          [Tue May 9 14:58:24 2023] do_el0_svc+0x28/0xa0
          [Tue May 9 14:58:24 2023] el0_svc+0x24/0x84
          [Tue May 9 14:58:24 2023] el0t_64_sync_handler+0x88/0xec
          [Tue May 9 14:58:24 2023] el0t_64_sync+0x1b4/0x1b8

          考慮到此問題發(fā)生的場景與人臉識別有關,且日志也顯示人臉識別線程一直處于99%的CPU占用率狀態(tài),因此有理由懷疑運行在CPU7上的線程就是人臉識別的線程。

          FaceAysncQueue線程剛好負責人臉識別TEE的接口調(diào)用,因此它的嫌疑最大。

          1
          2
          06-11 11:34:26.491  2869 29516 E ActivityManager:   99% 2589/vendor.xingji.hardware.biometrics.face@1.0-service: 0% user + 99% kernel
          06-11 11:34:26.491 2869 29516 E ActivityManager: 99% 2639/FaceAysncQueue: 0% user + 99% kernel

          結合TEE人臉識別的日志,可以看到問題發(fā)生時,HAL調(diào)用人臉識別TA,人臉識別TA一直沒有返回。

          因此,人臉識別就是罪魁禍首。

          kdump之根因定位

          日志的信息比較有限,只能分析到上述的結論,萬幸的是,在其他復現(xiàn)問題的機器上抓到了kdump。
          雖然問題發(fā)生在TEE中,但只要有kdump和symbols,那么原理上就可以解析出對應的堆棧,最終解析堆棧如下。

          1
          2
          3
          4
          5
          6
          -000|Laplacian(asm)
          -001|oem_tee_image_quality_sharpness(asm)
          -002|oem_tee_quality(asm)
          -003|getFeature()
          -004|handle_cmd_get_feature()
          -005|tz_app_cmd_handler()

          考慮到問題本身不容易復現(xiàn),算法由供應商提供,添加日志定位問題周期長,因此需要更進一步的手段來定位問題。

          通過trace32進一步解析,獲取通用寄存器,TA加載地址等信息如下。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          Register:
          X0 = 0x75CF2AC0, X1 = 0x75CF2980, X2 = 0x00000000, X3 = 0x00000000,
          X4 = 0x00015888, X5 = 0x00010910, X6 = 0x00010911, X7 = 0x0000001F,
          X8 = 0xFFFFFFFE, X9 = 0x00000FED, X10 = 0x75CF2000, X11 = 0x7FFFFFFF,
          X12 = 0x00001FFF, X13 = 0xFFFFFFFE, X14 = 0x0000000F, X15 = 0x00000010,
          X16 = 0x00000001, X17 = 0x73656E73, X18 = 0x0000FFFF, X19 = 0x00000000,
          X20 = 0x75CF2980, X21 = 0x75CF2980, X22 = 0x75CF2AC0, X23 = 0x00000000,
          X24 = 0x00000000, X25 = 0x00000000, X26 = 0x75CF2AC0, X27 = 0x00000000,
          X28 = 0x00000000, X29 = 0x1F65ED90, X30 = 0x38586CA8, ELR = 0x385863A8,
          PC = 0x385863A8

          VA of stapp loading start: 0x38479000
          Entry of Laplacian :0x38586358

          問題點虛擬地址為0x385863A8,Laplacian函數(shù)虛擬地址為0x38586358。

          因此,問題點在Laplacian偏移offset=0x385863A8-0x38586358=0x50位置。
          Laplacian函數(shù)鏈接地址0x107a78,所以問題點的鏈接地址為0x107a78+0x50=0x107AC8。
          反匯編顯示,0x107AC8地址附近剛好是個循環(huán)。

          循環(huán)部分的匯編代碼如下。

          1
          2
          3
          4
          5
          CMP W11, #0
          CSEL W13, WZR, W8 LT
          SUB W11, W13, W11
          CMP W11, W25
          B.CS loc_107AC8

          CMP W11, #0,和立即數(shù)0做比較。CMP指令的實現(xiàn)SUB指令基本同等,區(qū)別是SUB指令需要將結果保存到寄存器,CMP指令丟棄計算結果。CMP指令和SUB指令執(zhí)行后都會更新CPSR寄存器的NZCV標志位。W11的值是0X7FFFFFFF,也就是0X7FFFFFFF-0x0=0X7FFFFFFF-0x0。結果大于0且沒有借位和溢出,所以結果是N=0,Z=0,C=1,V=0。

          CSEL W13, WZR, W8 LT,如果前一條比較指令是LT(小于)情況下(即N!=V),則W13=WZR,否則W13=W8。前面的CMP指令執(zhí)行后N==V,W8=0xFFFFFFFE,所以結果是W13=0xFFFFFFFE。

          SUB W11, W13, W11,W11=W13-W11,W11=0x7FFFFFFF,所以結果是W11=0xFFFFFFFE-0x7FFFFFFF=0x7FFFFFFF。

          CMP W11, W25,和W25的值做比較。W11=0x7FFFFFFF,W25=0x00000000,所以結果是N=0,Z=0,C=1,V=0。

          B.CS loc_107AC8,如果CPSR寄存器的C標志位置位,則跳轉到地址0x107AC8,繼續(xù)循環(huán)。上面的結果是C標志位置位的,所以循環(huán)繼續(xù),形成死循環(huán)。

          上面這段匯編代碼是一個循環(huán),跳出循環(huán)的條件是W11小于W25。W11只有兩個值,要么是1,要么是W8-1。W8的值為W25*2-2。當W25為0或1的時候,循環(huán)就會無法跳出。當W25的值大于1時,第一輪循環(huán)就會跳出不再繼續(xù)。而W25是函數(shù)傳入的第三個參數(shù),這個值剛好等于0。

          從函數(shù)的命名來看,這應該是一個拉普拉斯變換的實現(xiàn),函數(shù)有四個參數(shù)。猜測第一個參數(shù)是變換前的數(shù)據(jù),第二個參數(shù)是變換后的數(shù)據(jù),第三個和第四個參數(shù)是寬度和高度。

          從供應商獲取函數(shù)簽名,確實如上面的猜測一樣。

          也就是說,這里面存在兩個問題。一是沒有進行邊界檢查,導致代碼存在死循環(huán)的可能。二是如果邏輯走到這個函數(shù),這里的寬度是不能為0的。在寬度為0的時候,oem_tee_image_quality_sharpness不應該調(diào)用Laplacian函數(shù)。

          從日志來看,出現(xiàn)問題時應該是在沒有檢測到人臉或者從沒有檢測到人臉過渡到檢測到人臉(即出現(xiàn)問題時算法剛好判斷出有人臉)的環(huán)境下。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          face: tz_app_cmd_handler(674):enter handler 0x65373170 
          face: tz_app_cmd_handler(702):req size:40, rsp size:48
          face: tz_app_cmd_handler(711):TZ App cmd handler, cmd_id = 3
          face: getFeature(1222):[ TIME-COUNTER ] oem_tee_image_create , use time 0 ms
          face: getFeature(1224):***** image detect start *****
          face: getFeature(1227):begine oem_tee_detect
          face: oem_tee_detect(1848):detect no face.
          face: getFeature(1233):oem_tee_detect failed: 1
          face: tz_app_cmd_handler(1140):get image feature failed
          face: tz_app_cmd_handler(1193):exec cmd 3. 11ms
          face: tz_app_cmd_handler(674):enter handler 0x65373170
          face: tz_app_cmd_handler(702):req size:40, rsp size:48
          face: tz_app_cmd_handler(711):TZ App cmd handler, cmd_id = 3
          face: getFeature(1222):[ TIME-COUNTER ] oem_tee_image_create , use time 1 ms
          face: getFeature(1224):***** image detect start *****
          face: getFeature(1227):begine oem_tee_detect
          face: oem_tee_detect(1848):detect no face.
          face: getFeature(1233):oem_tee_detect failed: 1
          face: tz_app_cmd_handler(1140):get image feature failed
          face: tz_app_cmd_handler(1193):exec cmd 3. 11ms
          face: tz_app_cmd_handler(674):enter handler 0x65373170
          face: tz_app_cmd_handler(702):req size:40, rsp size:48
          face: tz_app_cmd_handler(711):TZ App cmd handler, cmd_id = 3
          face: getFeature(1222):[ TIME-COUNTER ] oem_tee_image_create , use time 0 md

          代碼的邏輯是oem_tee_image_create->oem_tee_detect->oem_tee_quality。
          結合問題堆棧來看,oem_tee_detect返回的結果是檢測到人臉。
          因此,壓測手法可以為抬手進行人臉識別,模擬人臉從無到有的過程。

          以上僅僅只是分析,需要有辦法對這個問題進行復現(xiàn)和修復驗證,上述壓測手法不一定能很快復現(xiàn)到問題。
          可以考慮使用問題出現(xiàn)時的人臉數(shù)據(jù)進行重現(xiàn),看問題能否穩(wěn)定復現(xiàn)。由于人臉識別沒有做數(shù)據(jù)保存,因此只能在kdump中查找數(shù)據(jù)。

          人臉識別REE與TEE通信時,會從dmabuf申請一片內(nèi)存作為共享內(nèi)存。因此使用crash工具加載kdump,通過vm命令找到人臉識別HAL進程打開的dmabuf地址,最后通過rd命令導出數(shù)據(jù)。
          根據(jù)代碼知道,人臉錄入時這片buffer大小為0x55000,人臉識別時這片buffer大小為0x71000。

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          crash> ps | grep face@1.0
          2606 1 2 ffffff88795d6940 IN 0.3 2474768 107460 face@1.0-servic
          2688 1 7 ffffff88823c0040 IN 0.3 2474768 107460 face@1.0-servic
          2690 1 0 ffffff88823c2a40 IN 0.3 2474768 107460 face@1.0-servic
          2693 1 5 ffffff88823c6940 IN 0.3 2474768 107460 face@1.0-servic
          2695 1 2 ffffff887b385440 IN 0.3 2474768 107460 face@1.0-servic
          crash> set 2606
          PID: 2606
          COMMAND: "[email protected]"
          TASK: ffffff88795d6940 [THREAD_INFO: ffffff88795d6940]
          CPU: 2
          STATE: TASK_INTERRUPTIBLE
          crash> vm | grep -w dmabuf
          ffffff804466ac68 74dce73000 74dcee4000 40444fb dmabuf
          ffffff8884b38f90 7563736000 7563737000 40444fb dmabuf
          crash> rd -r dmabuf.bin ffffff804466ac68 0x71000
          462848 bytes copied from 0xffffff804466ac68 to dmabuf.bin

          導出的數(shù)據(jù)為nv21 rawdata格式,需要將數(shù)據(jù)轉為jpeg。從實際dump出來的數(shù)據(jù)來看,并不符合預期。
          通過做實驗,為這片共享內(nèi)存?zhèn)魅胫付〝?shù)據(jù),再dump出來,發(fā)現(xiàn)正常情況下,傳入的數(shù)據(jù)與dump出來的數(shù)據(jù)也不一致。
          因此目前并無法通過dump dmabuf來拿到數(shù)據(jù),具體原因有待調(diào)查。

          既然無法從dmabuf dump出正確的數(shù)據(jù),那就嘗試傳入特定數(shù)據(jù),直接從kdump的二進制文件特定偏移位置找到數(shù)據(jù)。
          實驗發(fā)現(xiàn),在A項目上可以在DDRCS0_0.BIN的0x65300000位置(使用binwalk進行二進制查找上述特定數(shù)據(jù))dump出正確的人臉數(shù)據(jù),但是在出現(xiàn)問題的B項目上,得到的數(shù)據(jù)不符合預期。
          而B項目由于某些原因,沒法做實驗找到偏移的位置,因此只能采取其他辦法。

          人臉識別使用的圖片數(shù)據(jù)為nv21,實驗中發(fā)現(xiàn),nv21格式具有比較明顯的數(shù)據(jù)特征。

          因此嘗試使用如下命令進行特征查找。

          1
          2
          xxd DDRCS0_0.BIN > tee xxd.log
          grep -nr "\.w\.w\.w\.w\.w\.w\.w\.w" xxd.log

          查找出來的特征不算太多。

          使用ghex打開DDRCS0_0.BIN,在上述可能的特征前后進行查看,定位到一處比較可疑的內(nèi)存地址,偏移為0x78400000,物理地址為0x78400000+0x80000000。將數(shù)據(jù)dump出來后導入手機進行復現(xiàn),確認問題是可以穩(wěn)定復現(xiàn)的。

          查看導出的數(shù)據(jù),可以看到圖片中并沒有人臉,但算法誤判存在人臉特征,導致邏輯走到oem_tee_quality。

          Laplacian陷入死循環(huán)的原因是因為width參數(shù)為0,但根據(jù)供應商的描述,width參數(shù)的值是通過oem_tee_quality傳遞進去的。從再次復現(xiàn)打日志打印來看,oem_tee_quality傳遞的寬度為640,因此只能懷疑在oem_tee_quality或者oem_tee_image_quality_sharpness函數(shù)內(nèi)部,有異常邏輯會導致傳入Laplacian的width為0。

          最后的解決方案是供應商在更新算法庫的同時,為Laplacian加入邊界檢查邏輯,提升代碼健壯性。

          參考資料

          • NZCV,https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/NZCV--Condition-Flags

          • Conditional,https://developer.arm.com/documentation/dui0068/b/ARM-Instruction-Reference/Conditional-execution

          • CMP,https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/CMP--immediate---Compare--immediate---an-alias-of-SUBS--immediate--

          • CSEL,https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/CSEL--Conditional-Select-

          • B.cond,https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/B-cond--Branch-conditionally-

          瀏覽 2371
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产婷婷五月综合亚洲 | 天天干网站 | 色色色热热热 | 伊人夜夜躁AV伊人久久 | 成人一级黄片 |