问题描述:连接蓝牙鼠标后,关闭蓝牙,再重新开启蓝牙,会出现系统界面没有响应提示
分析tracelog:
"main" prio=5 tid=1 Blocked
group="main" sCount=1 dsCount=0 flags=1 obj=0x741943c8 self=0x7d154c2a00
sysTid=9311 nice=-10 cgrp=default sched=0/0 handle=0x7d9a4aa9a8
state=S schedstat=( 6930154951 867104714 7237 ) utm=596 stm=97 core=3 HZ=100
stack=0x7fd873f000-0x7fd8741000 stackSize=8MB
held mutexes=
at com.android.settingslib.bluetooth.CachedBluetoothDeviceManager.getCachedDevicesCopy(CachedBluetoothDeviceManager.java:-1)
waiting to lock <0x0957278e> (a com.android.settingslib.bluetooth.CachedBluetoothDeviceManager) held by thread 23
at com.android.systemui.statusbar.policy.BluetoothControllerImpl.getDevices(BluetoothControllerImpl.java:196)
at com.android.systemui.statusbar.policy.BluetoothControllerImpl.updateConnected(BluetoothControllerImpl.java:209)
at com.android.systemui.statusbar.policy.BluetoothControllerImpl.onDeviceAttributesChanged(BluetoothControllerImpl.java:267)
at com.android.settingslib.bluetooth.CachedBluetoothDevice.dispatchAttributesChanged(CachedBluetoothDevice.java:644)
locked <0x0dfd4baf> (a java.util.ArrayList)
at com.android.settingslib.bluetooth.CachedBluetoothDevice.refresh(CachedBluetoothDevice.java:451)
at com.android.settingslib.bluetooth.HidProfile$InputDeviceServiceListener.onServiceConnected(HidProfile.java:68)
at android.bluetooth.BluetoothInputDevice$2.onServiceConnected(BluetoothInputDevice.java:504)
at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1676)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1705)
at android.os.Handler.handleCallback(Handler.java:794)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.TinnoLoop(Looper.java:189)
at android.os.Looper.loop(Looper.java:270)
at android.app.ActivityThread.main(ActivityThread.java:6730)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
"SysUiBg" prio=5 tid=23 Blocked
group="main" sCount=1 dsCount=0 flags=1 obj=0x187017e0 self=0x7cfca3f400
sysTid=9342 nice=10 cgrp=default sched=0/0 handle=0x7cf6efa4f0
state=S schedstat=( 490875615 328350733 1413 ) utm=29 stm=20 core=5 HZ=100
stack=0x7cf6df8000-0x7cf6dfa000 stackSize=1037KB
held mutexes=
at com.android.settingslib.bluetooth.CachedBluetoothDevice.dispatchAttributesChanged(CachedBluetoothDevice.java:642)
waiting to lock <0x0dfd4baf> (a java.util.ArrayList) held by thread 1
at com.android.settingslib.bluetooth.CachedBluetoothDevice.onUuidChanged(CachedBluetoothDevice.java:575)
at com.android.settingslib.bluetooth.CachedBluetoothDeviceManager.onUuidChanged(CachedBluetoothDeviceManager.java:155)
locked <0x0957278e> (a com.android.settingslib.bluetooth.CachedBluetoothDeviceManager)
at com.android.settingslib.bluetooth.BluetoothEventManager$UuidChangedHandler.onReceive(BluetoothEventManager.java:366)
at com.android.settingslib.bluetooth.BluetoothEventManager$1.onReceive(BluetoothEventManager.java:148)
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$-android_app_LoadedApk$ReceiverDispatcher$Args_53020(LoadedApk.java:1337)
at android.app.-$Lambda$aS31cHIhRx41653CMnd4gZqshIQ.$m$7(unavailable:-1)
at android.app.-$Lambda$aS31cHIhRx41653CMnd4gZqshIQ.run(unavailable:-1)
at android.os.Handler.handleCallback(Handler.java:794)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.TinnoLoop(Looper.java:164)
at android.os.Looper.loop(Looper.java:270)
at android.os.HandlerThread.run(HandlerThread.java:65)
可以看到A线程waiting to lock <0x0957278e> 同时 locked <0x0dfd4baf> (a java.util.ArrayList)
B线程 waiting to lock <0x0dfd4baf> 同时 locked <0x0957278e>
是一个很明显的死锁问题
分析源码,简化代码逻辑如下:
A线程:
BluetoothEventManager$1.onReceive
frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
获得CachedBluetoothDeviceManager锁
CachedBluetoothDevice cachedDevice = findDevice(device);
if (cachedDevice != null) {
cachedDevice.onUuidChanged();
}
}
请求mCallbacks锁
frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
private void dispatchAttributesChanged() {
synchronized (mCallbacks) {
for (Callback callback : mCallbacks) {
callback.onDeviceAttributesChanged();
}
}
}
B线程:
先调用dispatchAttributesChanged()
获得mCallbacks锁
HidProfile$InputDeviceServiceListener.onServiceConnected->CachedBluetoothDevice.refresh->CachedBluetoothDevice.dispatchAttributesChanged->Systemui-> updateConnected()
/home/android/codes/qc8937/LA.UM.6.6/LINUX/android/vendor/myos/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
请求CachedBluetoothDeviceManager锁
CachedBluetoothDeviceManager.java
public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
return new ArrayList<CachedBluetoothDevice>(mCachedDevices);
}
用最简单的DEMO抽象这个死锁问题
package com.fantasy.android.demo.java;
public class DeadObjectTest {
private Object lockOne = new Object();
private Object lockTwo = new Object();
private void doA() {
synchronized (lockOne) {
try {
System.out.println(Thread.currentThread().getName() + " doA begin");
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " doA end");
doSame();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void doSame() {
synchronized (lockTwo) {
try {
System.out.println(Thread.currentThread().getName() + " doSame begin");
Thread.sleep(200);
System.out.println(Thread.currentThread().getName() + " doSame end ");
doB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void doB() {
synchronized (lockOne) {
try {
System.out.println(Thread.currentThread().getName() + " doB begin ");
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " doB end ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) {
DeadObjectTest test = new DeadObjectTest();
Thread a = new Thread(new Runnable() {
@Override
public void run() {
test.doA();
}
});
a.start();
Thread b = new Thread(new Runnable() {
@Override
public void run() {
test.doSame();
}
});
b.start();
}
}
执行 查看运行结果:
Thread-0 doA begin
Thread-1 doSame begin
Thread-0 doA end
Thread-1 doSame end
没有“process finished” , 死锁了。
解决方案一: 使AB同步
private void doA() {
synchronized (lockOne) {
try {
// 出让锁
lockOne.wait();
System.out.println(Thread.currentThread().getName() + " doA begin");
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " doA end");
doSame();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void doB() {
synchronized (lockOne) {
try {
System.out.println(Thread.currentThread().getName() + " doB begin ");
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " doB end ");
// 使A进入阻塞队列
lockOne.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
看运行结果:
Thread-1 doSame begin
Thread-1 doSame end
Thread-1 doB begin
Thread-1 doB end
Thread-0 doA begin
Thread-0 doA end
Thread-0 doSame begin
Thread-0 doSame end
Thread-0 doB begin
Thread-0 doB end
Process finished with exit code 0
看起来很完美的解决了。 但是这个解决方案 不适用于我们这个问题的情况
有很多方法用到CachedBluetoothDeviceManager这个锁,无法全部做到同步,业务逻辑上也不能全部同步。
解决方案二:给dispatchAttributesChagned()方法用RenentrantLock的tryLock判断能否获得锁
这个方案的问题是 如果拿不到锁,有另一个线程的调用就被放弃了。
private ReentrantLock mLock = new ReentrantLock();
private void doSame() {
if (mLock.tryLock()) {
synchronized (lockTwo) {
try {
System.out.println(Thread.currentThread().getName() + " doSame begin");
Thread.sleep(200);
System.out.println(Thread.currentThread().getName() + " doSame end ");
mLock.unlock();
doB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果可以看到Thread 0的 doSame调用没了,虽然解决了死锁。
Thread-0 doA begin
Thread-1 doSame begin
Thread-0 doA end
Thread-1 doSame end
Thread-1 doB begin
Thread-1 doB end
Process finished with exit code 0
好吧,头大,目前还没找到最完美的适合这个问题场景的解决方案,有没有大神不吝赐教?
网友评论