**Car service has crashed. Client 导致应用黑屏的问题

**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) {
           //这里进行需要的操作
        }
    }

问题解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我怀里的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值