TimeoutException问题排查
崩溃堆栈:
java.util.concurrent.TimeoutException: com.android.internal.os.BinderInternal$GcWatcher.finalize() timed out after 10 secondsat com.android.internal.os.BinderInternal$GcWatcher.finalize(BinderInternal.java:63)at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:289)at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:276)at java.lang.Daemons$Daemon.run(Daemons.java:137)at java.lang.Thread.run(Thread.java:919)
崩溃的设备上大量报错:
onBillingSetupFinished: 3 Google Play In-app Billing API version is less than 3
Billing service disconnected
检查方法
- 看网上的讨论,大多是模拟器场景会有问题,出错问题的设备基本上都有root
- 逆向查看了 https://mvnrepository.com/artifact/com.android.billingclient/billing/6.0.1 细节如下:
看起来这个sdk只是调用intent,跨进程调用 com.android.vending 的服务,不确定是不是 用户的 com.android.vending 服务版本有问题。
Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
intent.setPackage("com.android.vending");
List<ResolveInfo> queryIntentServices = this.zze.getPackageManager().queryIntentServices(intent, 0);this.zzh = new zzaf(this, billingClientStateListener, null);
if (this.zze.bindService(intent2, this.zzh, 1)) {com.google.android.gms.internal.play_billing.zzb.zzi("BillingClient", "Service was bonded successfully.");return;
} else {com.google.android.gms.internal.play_billing.zzb.zzj("BillingClient", "Connection to Billing service is blocked.");i = 39;
}
@Override // android.content.ServiceConnection
public final void onServiceDisconnected(ComponentName componentName) {com.google.android.gms.internal.play_billing.zzb.zzj("BillingClient", "Billing service disconnected.");BillingClientImpl.zzg(this.zza).zzc(zzgd.zzw());BillingClientImpl.zzD(this.zza, null);BillingClientImpl.zzp(this.zza, 0);synchronized (this.zzb) {try {BillingClientStateListener billingClientStateListener = this.zzd;if (billingClientStateListener != null) {billingClientStateListener.onBillingServiceDisconnected();}} catch (Throwable th) {throw th;}}
}
触发来源是 onServiceDisconnected。
这意味着,用户设备上的 com.android.vending 这个程序,正在不断经历启动、崩溃、重启。
我们这边因为支付功能,需要调用 Billing 去跨进程使用 vending 的服务,所以被波及了。
解决的思路有几个:
-
限频调用 billingClient.startConnection,避免大量密集调用 【前同事的缓解措施】
-
升级Billingsdk:注意到触发崩溃的是 com.android.vending 的服务 ,升级可能意义不大。【未使用】
-
增加heap,减少触发gc的概率 【观察有效】
-
参考滴滴的做法,忽略这个崩溃 江义旺:滴滴出行安卓端 finalize time out 的解决方案 【未使用】
忽略这个崩溃
下文的细节来自:江义旺:滴滴出行安卓端 finalize time out 的解决方案
- 手动修改 finalize() 方法超时时间
try {Class<?> c = Class.forName(“java.lang.Daemons”);Field maxField = c.getDeclaredField(“MAX_FINALIZE_NANOS”);maxField.setAccessible(true);maxField.set(null, Long.MAX_VALUE);
} catch (Exception e) {...
}
- 手动停掉 FinalizerWatchdogDaemon 线程
try {Class clazz = Class.forName("java.lang.Daemons$FinalizerWatchdogDaemon");Method method = clazz.getSuperclass().getDeclaredMethod("stop");method.setAccessible(true);Field field = clazz.getDeclaredField("INSTANCE");field.setAccessible(true);method.invoke(field.get(null));
} catch (Throwable e) {e.printStackTrace();
}
- 忽略这个崩溃,避免用户触发
final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {if (t.getName().equals("FinalizerWatchdogDaemon") && e instanceof TimeoutException) {//ignore it} else {defaultUncaughtExceptionHandler.uncaughtException(t, e);}}
});