ANR之死锁

125 阅读2分钟

实例1

"appscheduling.default" prio=5 tid=55 Blocked  
  | group="main" sCount=1 ucsCount=0 flags=1 obj=0x13a299c8 self=0xb4000072643f4400  
  | sysTid=861 nice=-2 cgrp=foreground sched=0/0 handle=0x7261e45cb0  
  | state=S schedstat=( 1810889629 5149663174 2648 ) utm=144 stm=36 core=4 HZ=100  
  | stack=0x7261d42000-0x7261d44000 stackSize=1039KB  
  | held mutexes=  
  at com.android.server.am.ActivityManagerService$LocalService.updateDeviceIdleTempAllowlist(ActivityManagerService.java:17900)  
  - waiting to lock <0x0a3ce9ac> (a com.android.server.am.ActivityManagerService) held by thread 209  
  at com.android.server.DeviceIdleController.updateTempWhitelistAppIdsLocked(DeviceIdleController.java:4642)  
  at com.android.server.DeviceIdleController.onAppRemovedFromTempWhitelistLocked(DeviceIdleController.java:3406)  
  at com.android.server.DeviceIdleController.checkTempAppWhitelistTimeout(DeviceIdleController.java:3389)  
  - locked <0x0f44a533> (a com.android.server.DeviceIdleController)  
    
  "binder:739_16" prio=5 tid=209 Blocked  
  | group="main" sCount=1 ucsCount=0 flags=1 obj=0x14417238 self=0xb4000071ea610800  
  | sysTid=2490 nice=-2 cgrp=foreground sched=0/0 handle=0x72496eccb0  
  | state=S schedstat=( 1169444676 11642784307 2992 ) utm=80 stm=36 core=4 HZ=100  
  | stack=0x72495f5000-0x72495f7000 stackSize=991KB  
  | held mutexes=  
  at com.android.server.DeviceIdleController.getUserPowerWhitelistInternal(DeviceIdleController.java:3095)  
  - waiting to lock <0x0f44a533> (a com.android.server.DeviceIdleController) held by thread 55  
  at com.android.server.DeviceIdleController.-$$Nest$mgetUserPowerWhitelistInternal(DeviceIdleController.java:0)  
  at com.android.server.DeviceIdleController$LocalService.getUserPowerWhiteList(DeviceIdleController.java:2387)  
  at com.android.server.am.ActivityManagerService.appDiedLocked(ActivityManagerService.java:3452)  
  at com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied(ActivityManagerService.java:1610)  
  - locked <0x0a3ce9ac> (a com.android.server.am.ActivityManagerService)  
  at android.os.IBinder$DeathRecipient.binderDied(IBinder.java:319)  
  at android.os.BinderProxy.sendDeathNotice(BinderProxy.java:704)
  • "appscheduling.default"和"binder:739_16"都处于Blocked状态;
  • 第8行:"waiting to lock <0x0a3ce9ac> (a com.android.server.am.ActivityManagerService) held by thread 209"表示当前线程"appscheduling.default"等待的锁<0x0a3ce9ac>被线程号为209的线程即"binder:739_16"持有
  • 第12行:"locked <0x0f44a533> (a com.android.server.DeviceIdleController)"表示当前线程"appscheduling.default"持有锁<0x0f44a533>
  • 第21行:"waiting to lock <0x0f44a533> (a com.android.server.DeviceIdleController) held by thread 55"表示当前线程"binder:739_16"等待的锁<0x0f44a533>被线程号55的线程即"binder:739_16"持有
  • 第26行:"locked <0x0a3ce9ac> (a com.android.server.am.ActivityManagerService)"表示当前线程"binder:739_16"持有锁<0x0a3ce9ac>

"binder:739_16"和"ppscheduling.default"形成死锁

线程持有锁等待锁
"binder:739_16"0x0a3ce9ac0x0f44a533
"ppscheduling.default"0x0f44a5330x0a3ce9ac

实例2


"main" prio=5 tid=1 Blocked

  | group="main" sCount=1 ucsCount=0 flags=1 obj=0x72a1f738 self=0xb4000076fbcfb6f0

  | sysTid=28235 nice=-20 cgrp=top-app sched=0/0 handle=0x791104c4f8

  | state=S schedstat=( 3890452885766 171240901531 3639259 ) utm=351045 stm=37999 core=7 HZ=100

  | stack=0x7fce606000-0x7fce608000 stackSize=8188KB

  | held mutexes=

  at com.android.launcher3.model.ModelDbController.createDbIfNotExists(unavailable:0)

  - waiting to lock <0x012ab2d9> (a com.android.launcher3.model.ModelDbController) held by thread 19

  at com.android.launcher3.model.ModelDbController.migrateGridIfNeeded(ModelDbController.java:307)

  at com.android.launcher.settings.LauncherLayoutUtil.forceMigrate(LauncherLayoutUtil.java:100)

  at com.android.launcher.settings.SettingsFragment.onAutoFillValueChange(SettingsFragment.java:372)

  at com.android.launcher.settings.SettingsFragment.-$$Nest$monAutoFillValueChange(unavailable:0)

  at com.android.launcher.settings.SettingsFragment$1.onPreferenceChange(SettingsFragment.java:293)


"launcher-loader" prio=5 tid=19 Waiting

  | group="main" sCount=1 ucsCount=0 flags=1 obj=0x12c3dd60 self=0xb4000076fbd3bc00

  | sysTid=28255 nice=10 cgrp=top-app sched=0/0 handle=0x7643b98cb0

  | state=S schedstat=( 750800081444 29927976968 246727 ) utm=70838 stm=4241 core=7 HZ=100

  | stack=0x7643a95000-0x7643a97000 stackSize=1039KB

  | held mutexes=

  at jdk.internal.misc.Unsafe.park(Native method)

  - waiting on an unknown object

  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)

  at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:447)

  at java.util.concurrent.FutureTask.get(FutureTask.java:190)

  at com.android.launcher3.uioverrides.QuickstepWidgetHolder.destroy(QuickstepWidgetHolder.java:184)

  at com.android.launcher3.model.ModelDbController.loadDefaultFavoritesIfNecessary(ModelDbController.java:449)

  - locked <0x012ab2d9> (a com.android.launcher3.model.ModelDbController)

  at com.android.launcher3.LauncherProvider.call(LauncherProvider.java:294)

  at android.content.ContentProvider.call(ContentProvider.java:2682)
  • 主线程"main"处于Blocked状态,"launcher-loader"处于Waiting状态
  • 第16行: "waiting to lock <0x012ab2d9> (a com.android.launcher3.model.ModelDbController) held by thread 19"表示主线程"main"等待的锁<0x012ab2d9>,被线程号为19的线程即"launcher-loader"持有
  • 第55行:"locked <0x012ab2d9> (a com.android.launcher3.model.ModelDbController)"表示当前线程"launcher-loader"持有锁<0x012ab2d9>
  • 第43行:"waiting on an unknown object"看出线程"launcher-loader"被FutureTask.get阻塞
src/com/android/launcher3/model/ModelDbController.java    
    @WorkerThread
    public synchronized void loadDefaultFavoritesIfNecessary() {
        createDbIfNotExists();
        if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()))) {

            LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder();
            try {
                AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHolder);
                if (loader == null) {
                    loader = AutoInstallsLayout.get(mContext, widgetHolder, mOpenHelper);
                }
                ...
            } finally {
                widgetHolder.destroy();// line 449
            }
        }
    }

    private synchronized void createDbIfNotExists() {
        if (mOpenHelper == null) {
            ...
            mDatabaseHelpers.put(mOpenHelper.getDatabaseName(), mOpenHelper); 
        }
    }

    public boolean migrateGridIfNeeded() {
        createDbIfNotExists();// line 307
        InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
        ...
    }

src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
    @Override
    public void destroy() {
        try {
            MAIN_EXECUTOR.submit(() -> sHolders.remove(this)).get();// line 184
        } catch (Exception e) {
            Log.e(TAG, "Failed to remove self from holder list", e);
        }
    }

主线程在调用ModelDbController.migrateGridIfNeeded会调用createDbIfNotExists方法,而createDbIfNotExists方法带synchronized关键字,需要等待持有成员锁的线程"launcher-loader"释放; 而"launcher-loader"线程在持锁过程中调用QuickstepWidgetHolder.destroy时,通过MAIN_EXECUTOR发一个任务给主线程处理,并且要阻塞等待这个任务处理完,此时主线程由于等待"launcher-loader"释放锁处于Blocked状态无法处理该任务,从而导致了主线程和线程"launcher-loader"形成死锁

线程持有锁等待锁
"main"0x012ab2d9
"launcher-loader"0x012ab2d9阻塞等待main线程处理任务
sequenceDiagram
main->>launcher-loader: 我等你释放锁
launcher-loader-)main: 我等你任务处理完才能释放锁