**Car service has crashed. Client 导致应用黑屏的问题
前言
项目跑压测测出来一个点开APP后黑屏的问题,提了个单,附件两个G的日志,脑壳都大了。第一遍看app进入和退出的日志,在关键时间点搜索不到有效信息,一度抓狂。
找不出来问题就求助队友,我拉着组长帮忙看此问题,组长坐下,气定神闲,一顿操作猛如虎,然后说时间点附近进程号变了,然后指出了报错的关键信息:
10-28 17:49:38.105 3138 3138 W CAR.L : **Car service has crashed. Client(null) is not handling it. Client should use Car.createCar(..., CarServiceLifecycleListener, ...) to handle it properly. Check pritned callstack to check where other version of Car.createCar() was called. Killing the client process**
这日志就说的很清晰了,Car service crashe了然后导致我们客户端崩了,应该用
public static Car createCar(Context context, Handler handler, long waitTimeoutMs, CarServiceLifecycleListener statusChangeListener) {
}
上面这个方法才能避免被杀掉进程,巴拉巴拉之类的。
解决方法
问了负责此模块的同事过后,本来获取Car是用的如下方法:
public static Car createCar(Context context) {
}
替换成
public static Car createCar(Context context, Handler handler, long waitTimeoutMs, CarServiceLifecycleListener statusChangeListener) {
}
即可解决。
分析源码
到了这里,虽然解决了问题,但是我们知其然不知其所以然,所以我去看源码了,路径为:android12/packages/services/Car/car-lib/src/android/car/Car.java
先找到输出日志的地方:
private void killClient(@Nullable String clientInfo) {
1769 Log.w(TAG_CAR, "**Car service has crashed. Client(" + clientInfo + ") is not handling it."
1770 + " Client should use Car.createCar(..., CarServiceLifecycleListener, .."
1771 + ".) to handle it properly. Check pritned callstack to check where other "
1772 + "version of Car.createCar() was called. Killing the client process**",
1773 mConstructionStack);
1774 Process.killProcess(Process.myPid());
1775 }
然后调用killClient的方法是这里:
private void finishClient() {
1748 if (mContext == null) {
1749 throw new IllegalStateException("Car service has crashed, null Context");
1750 }
1751 if (mContext instanceof Activity) {
1752 Activity activity = (Activity) mContext;
1753 if (!activity.isFinishing()) {
1754 Log.w(TAG_CAR,
1755 "Car service crashed, client not handling it, finish Activity, created "
1756 + "from " + mConstructionStack);
1757 activity.finish();
1758 }
1759 return;
1760 } else if (mContext instanceof Service) {
1761 Service service = (Service) mContext;
1762 killClient(service.getPackageName() + "," + service.getClass().getSimpleName());
1763 } else {
1764 killClient(/* clientInfo= */ null);
1765 }
1766 }
然后是mServiceConnectionListener回调的onServiceDisconnected调用了finishClient
1089 @Override
1090 public void onServiceDisconnected(ComponentName name) {
1091 // Car service can pick up feature changes after restart.
1092 mFeatures.resetCache();
1093 synchronized (mLock) {
1094 if (mConnectionState == STATE_DISCONNECTED) {
1095 // can happen when client calls disconnect before onServiceDisconnected call.
1096 return;
1097 }
1098 handleCarDisconnectLocked();
1099 }
1100 if (mStatusChangeCallback != null) {
1101 mStatusChangeCallback.onLifecycleChanged(Car.this, false);
1102 } else if (mServiceConnectionListenerClient != null) {
1103 mServiceConnectionListenerClient.onServiceDisconnected(name);
1104 } else {
1105 // This client does not handle car service restart, so should be terminated.
1106 finishClient();
1107 }
1108 }
1109 };
这里就可以明白的看出来,为什么会杀掉我们应用的进程了,因为我们进程没有处理car service的异常情况,所以把我们杀掉了;
而系统建议我们使用的接口有一个CarServiceLifecycleListener的监听,CarServiceLifecycleListener的注释如下:
/**
936 * Callback to notify the Lifecycle of car service.
937 *
938 * <p>Access to car service should happen
939 * after {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} call with
940 * {@code ready} set {@code true}.</p>
941 *
942 * <p>When {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} is
943 * called with ready set to false, access to car service should stop until car service is ready
944 * again from {@link CarServiceLifecycleListener#onLifecycleChanged(Car, boolean)} call
945 * with {@code ready} set to {@code true}.</p>
946 */
public interface CarServiceLifecycleListener {
948 /**
949 * Car service has gone through status change.
950 *
951 * <p>This is always called in the main thread context.</p>
952 *
953 * @param car {@code Car} object that was originally associated with this lister from
954 * {@link #createCar(Context, Handler, long, Car.CarServiceLifecycleListener)}
955 * call.
956 * @param ready When {@code true, car service is ready and all accesses are ok.
957 * Otherwise car service has crashed or killed and will be restarted.
958 */
959 void onLifecycleChanged(@NonNull Car car, boolean ready);
960 }
写的很明白了,会监听car service的生命周期,所以不会杀掉我们的进程
最后的解决问题的写法如下:
private val mCar = Car.createCar(
MediaApplication.context,
null,
Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER
) { car, ready ->
if (ready) {
//这里进行需要的操作
}
}
问题解决。


764

被折叠的 条评论
为什么被折叠?



