Android车载应用之EvsCameraPreview源码分析(二)

325 阅读5分钟

0 引言

Android车载应用之EvsCameraPreview源码分析(一)中介绍了两个Activity,一个是CarEvsCameraActivity,另一个是CarEvsCameraPreviewActivity。CarEvsCameraActivity通过调用CarEvsManager的服务startActivity来打开CarEvsCameraPreviewActivity,从而显示出倒车影像。相关代码如下:

private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> {
        if (!ready) {
            return;
        }

        try {
            CarEvsManager evsManager = (CarEvsManager) car.getCarManager(
                    Car.CAR_EVS_SERVICE);
            if (evsManager.startActivity(CarEvsManager.SERVICE_TYPE_REARVIEW) != ERROR_NONE) {
                Log.e(TAG, "Failed to start a camera preview activity");
            }
        } finally {
            mCar = car;
            finish();
        }
    };

下面将详细分析CarEvsManager及其相关类。

1 Car类

在介绍CarManager之前,先介绍一下Car这个类。Car 是 Android 车载系统(Android Automotive)中的核心类之一,表示一个与车载硬件进行交互的接口。它提供了与汽车硬件、车辆信息、车载服务等的交互功能。通过 Car 类,可以访问车载系统的各种功能,如汽车的传感器数据、信息显示、媒体控制等。

一般都是通过Car.createCar函数来创建一个Car,代码如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Car.createCar(getApplicationContext(), /* handler = */ null, CAR_WAIT_TIMEOUT_MS,
                mCarServiceLifecycleListener);
    }

createCar的函数代码如下:

public static Car createCar(@NonNull Context context,
            @Nullable Handler handler, long waitTimeoutMs,
            @NonNull CarServiceLifecycleListener statusChangeListener) {
        assertNonNullContext(context);
        Objects.requireNonNull(statusChangeListener);
        Car car = null;
        IBinder service = null;
        boolean started = false;
        int retryCount = 0;
        long maxRetryCount = 0;
        if (waitTimeoutMs > 0) {
            maxRetryCount = waitTimeoutMs / CAR_SERVICE_BINDER_POLLING_INTERVAL_MS;
            // at least wait once if it is positive value.
            if (maxRetryCount == 0) {
                maxRetryCount = 1;
            }
        }
        boolean isMainThread = Looper.myLooper() == Looper.getMainLooper();
        while (true) {
            // 获取到car service服务
            service = ServiceManagerHelper.getService(CAR_SERVICE_BINDER_SERVICE_NAME);
            if (car == null) {
                // 创建一个新的Car
                car = new Car(context, ICar.Stub.asInterface(service), null, statusChangeListener,
                        handler);
            }
            if (service != null) {
                if (!started) {  // specialization for most common case : car service already ready
                    car.dispatchCarReadyToMainThread(isMainThread);
                    // Needs this for CarServiceLifecycleListener. Note that ServiceConnection
                    // will skip the callback as valid mService is set already.
                    car.startCarService();
                    return car;
                }
                // service available after starting.
                break;
            }
            if (!started) {
                car.startCarService();
                started = true;
            }
            retryCount++;
            if (waitTimeoutMs < 0 && retryCount >= CAR_SERVICE_BINDER_POLLING_MAX_RETRY
                    && retryCount % CAR_SERVICE_BINDER_POLLING_MAX_RETRY == 0) {
                // Log warning if car service is not alive even for waiting forever case.
                Log.w(TAG_CAR, "car_service not ready, waited for car service (ms):"
                                + retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS,
                        new RuntimeException());
            } else if (waitTimeoutMs >= 0 && retryCount > maxRetryCount) {
                if (waitTimeoutMs > 0) {
                    Log.w(TAG_CAR, "car_service not ready, waited for car service (ms):"
                                    + waitTimeoutMs,
                            new RuntimeException());
                }
                return car;
            }

            try {
                Thread.sleep(CAR_SERVICE_BINDER_POLLING_INTERVAL_MS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                Log.w(TAG_CAR, "interrupted", new RuntimeException());
                return car;
            }
        }
        // Can be accessed from mServiceConnectionListener in main thread.
        synchronized (car.mLock) {
            Log.w(TAG_CAR,
                    "waited for car_service (ms):"
                            + retryCount * CAR_SERVICE_BINDER_POLLING_INTERVAL_MS,
                    new RuntimeException());
            // ServiceConnection has handled everything.
            if (car.mService != null) {
                return car;
            }
            // mService check in ServiceConnection prevents calling
            // onLifecycleChanged. So onLifecycleChanged should be called explicitly
            // but do it outside lock.
            car.mService = ICar.Stub.asInterface(service);
            car.mConnectionState = STATE_CONNECTED;
        }
        car.dispatchCarReadyToMainThread(isMainThread);
        return car;
    }

createCar函数的工作主要就是通过ServiceManagerHelper获取到car service服务,然后创建一个Car类,其内部持有car service代理,也就是可以调用car service服务。

2 CarEvsManager类

CarEvsManager顾名思义就是用来管理Evs相关功能的类,引言中的代码告诉我们通过car.getCarManager(Car.CAR_EVS_SERVICE)方法来获取CarEvsManager。下面是getCarManager函数的代码:

public Object getCarManager(String serviceName) {
        CarManagerBase manager;
        synchronized (mLock) {
            if (mService == null) {
                Log.w(TAG_CAR, "getCarManager not working while car service not ready");
                return null;
            }
            // 首先在mServiceMap中寻找,如果没有则创建
            manager = mServiceMap.get(serviceName);
            if (manager == null) {
                try {
                    // 获取Car.CAR_EVS_SERVICE服务的IBinder
                    IBinder binder = mService.getCarService(serviceName);
                    if (binder == null) {
                        Log.w(TAG_CAR, "getCarManager could not get binder for service:"
                                + serviceName);
                        return null;
                    }
                    // 创建对应的manager
                    manager = createCarManagerLocked(serviceName, binder);
                    if (manager == null) {
                        Log.w(TAG_CAR, "getCarManager could not create manager for service:"
                                        + serviceName);
                        return null;
                    }
                    mServiceMap.put(serviceName, manager);
                } catch (RemoteException e) {
                    handleRemoteExceptionFromCarService(e);
                }
            }
        }
        return manager;
    }

上面的代码主要就是获取Car.CAR_EVS_SERVICE服务的IBinder,然后通过它来创建对应的CarEvsManager。下面是createCarManagerLocked函数的部分代码:

case CAR_EVS_SERVICE:
            manager = new CarEvsManager(this, binder);
            break;

CarEvsManager的构造函数如下:

public CarEvsManager(Car car, IBinder service) {
        super(car);

        // Gets CarEvsService
        mService = ICarEvsService.Stub.asInterface(service);
    }

可以了解到CarEvsManager就是一个内部持有Car.CAR_EVS_SERVICE服务的类。通过它来调用关于Evs的相关服务和方法。至此,创建CarEvsManager的过程就分析完毕了。

3 startActivity过程分析

Car和CarEvsManager创建完毕后,就是调用startActivity方法来打开CarEvsCameraPreviewActivity了。进入startActivity代码中:

public @CarEvsError int startActivity(@CarEvsServiceType int type) {
        try {
            return mService.startActivity(type);
        } catch (RemoteException err) {
            handleRemoteExceptionFromCarService(err);
        }

        return ERROR_UNAVAILABLE;
    }

从上面的代码中可以看到,是通过Binder服务来开启Activity的。因此得找到ICarEvsService服务的实现代码,找到在packages/services/Car/service/src/com/android/car/evs/CarEvsService.java中。

public @CarEvsError int startActivity(int type) {
        CarServiceUtils.assertPermission(mContext, Car.PERMISSION_REQUEST_CAR_EVS_ACTIVITY);

        return mStateEngine.execute(REQUEST_PRIORITY_NORMAL, SERVICE_STATE_REQUESTED, type);
    }

继续调用mStateEngine的execute方法:

public @CarEvsError int execute(int priority, int destination, int service) {
            return execute(priority, destination, service, null, null);
        }

还是执行execute方法:

public @CarEvsError int execute(int priority, int destination, int service, IBinder token,
                ICarEvsStreamCallback callback) {

            int serviceType;
            int newState;
            int result = ERROR_NONE;
            synchronized (mLock) {
                // TODO(b/188970686): Reduce this lock duration.
                if (mState == destination && priority < mLastRequestPriority &&
                        destination != SERVICE_STATE_REQUESTED) {
                    // Nothing to do
                    return ERROR_NONE;
                }

                int previousState = mState;
                Slogf.i(TAG_EVS, "Transition requested: %s -> %s", stateToString(previousState),
                        stateToString(destination));

                switch (destination) {
                    case SERVICE_STATE_UNAVAILABLE:
                        result = handleTransitionToUnavailableLocked();
                        break;

                    case SERVICE_STATE_INACTIVE:
                        result = handleTransitionToInactiveLocked(priority, service, callback);
                        break;

                    case SERVICE_STATE_REQUESTED:
                        result = handleTransitionToRequestedLocked(priority, service);
                        break;

                    case SERVICE_STATE_ACTIVE:
                        result = handleTransitionToActiveLocked(priority, service, token, callback);
                        break;

                    default:
                        throw new IllegalStateException(
                                "CarEvsService is in the unknown state, " + previousState);
                }

                serviceType = mServiceType;
                newState = mState;
            }

            if (result == ERROR_NONE) {
                Slogf.i(TAG_EVS, "Transition completed: %s", stateToString(destination));
                // Broadcasts current state
                broadcastStateTransition(serviceType, newState);
            } else {
                Slogf.e(TAG_EVS, "Transition failed: error = %d", result);
            }

            return result;
        }

因为我们前面的destination为SERVICE_STATE_REQUESTED,所以执行对应的case,handleTransitionToRequestedLocked方法的代码如下:

private @CarEvsError int handleTransitionToRequestedLocked(int priority, int service) {
            switch (mState) {
                case SERVICE_STATE_UNAVAILABLE:
                    // Attempts to connect to the native EVS service and transits to the
                    // REQUESTED state if it succeeds.
                    if (!mHalWrapper.connectToHalServiceIfNecessary()) {
                        return ERROR_UNAVAILABLE;
                    }
                    break;

                case SERVICE_STATE_INACTIVE:
                    // Nothing to do
                    break;

                case SERVICE_STATE_REQUESTED:
                    if (priority < mLastRequestPriority) {
                        // A current service request has a lower priority than a previous
                        // service request.
                        Slogf.e(TAG_EVS, "CarEvsService is busy with a higher priority client.");
                        return ERROR_BUSY;
                    }

                    // Reset a timer for this new request
                    mHandler.removeCallbacks(mActivityRequestTimeoutRunnable);
                    break;

                case SERVICE_STATE_ACTIVE:
                    if (priority < mLastRequestPriority) {
                        // We decline a request because CarEvsService is busy with a higher priority
                        // client.
                        return ERROR_BUSY;
                    } else if (priority == mLastRequestPriority) {
                        // We do not need to transit to the REQUESTED state because CarEvsService
                        // was transited to the ACTIVE state by a request that has the same priority
                        // with current request.
                        return ERROR_NONE;
                    } else {
                        // Stop stream on all lower priority clients.
                        processStreamEvent(STREAM_EVENT_STREAM_STOPPED);
                    }
                    break;

                default:
                    throw new IllegalStateException("CarEvsService is in the unknown state.");
            }

            // Arms the timer for the high-priority request
            if (priority == REQUEST_PRIORITY_HIGH) {
                mHandler.postDelayed(
                        mActivityRequestTimeoutRunnable, STREAM_START_REQUEST_TIMEOUT_MS);
            }

            mState = SERVICE_STATE_REQUESTED;
            mServiceType = service;
            mLastRequestPriority = priority;

            if (mEvsCameraActivity != null) {
                Intent evsIntent = new Intent(Intent.ACTION_MAIN)
                        .setComponent(mEvsCameraActivity)
                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
                        .addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
                        .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                if (priority == REQUEST_PRIORITY_HIGH) {
                    mSessionToken = new Binder();
                    Bundle bundle = new Bundle();
                    bundle.putBinder(CarEvsManager.EXTRA_SESSION_TOKEN, mSessionToken);
                    evsIntent.replaceExtras(bundle);
                }
                mContext.startActivity(evsIntent);
            }
            return ERROR_NONE;
        }

这里只关注重点代码就好:

    mState = SERVICE_STATE_REQUESTED;
    mServiceType = service;
    mLastRequestPriority = priority;

    if (mEvsCameraActivity != null) {
        Intent evsIntent = new Intent(Intent.ACTION_MAIN)
                .setComponent(mEvsCameraActivity)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
                .addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
                .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        if (priority == REQUEST_PRIORITY_HIGH) {
            mSessionToken = new Binder();
            Bundle bundle = new Bundle();
            bundle.putBinder(CarEvsManager.EXTRA_SESSION_TOKEN, mSessionToken);
            evsIntent.replaceExtras(bundle);
        }
        mContext.startActivity(evsIntent);
    }

这段代码创建了一个Intent,该Intent设置组件为mEvsCameraActivity。最后通过mContext.startActivity(evsIntent)来打开这个Activity。mEvsCameraActivity对应的Activity其实就是CarEvsCameraPreviewActivity。

mEvsCameraActivity的初始化在CarEvsService的构造函数中:

    public CarEvsService(Context context, Context builtinContext, EvsHalService halService,
            CarPropertyService propertyService) {
        mContext = context;
        mPropertyService = propertyService;
        mEvsHalService = halService;

        mHalWrapper = createHalWrapper(builtinContext, this);

        String activityName = mContext.getResources().getString(R.string.config_evsCameraActivity);
        if (!activityName.isEmpty()) {
            mEvsCameraActivity = ComponentName.unflattenFromString(activityName);
        } else {
            mEvsCameraActivity = null;
        }
        if (DBG) Slogf.d(TAG_EVS, "evsCameraActivity=" + mEvsCameraActivity);
        mDisplayManager = context.getSystemService(DisplayManager.class);
        mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
    }

上面的代码中通过mContext.getResources().getString(R.string.config_evsCameraActivity)来获取到mEvsCameraActivity的名称。通过搜索config_evsCameraActivity找到activityName为com.google.android.car.evs/com.google.android.car.evs.CarEvsCameraPreviewActivity

这和我们前面的分析也就对应上了。如果我们想要修改Evs应用,可以直接修改CarEvsCameraPreviewActivity类,或者建立一个自己的Activity,然后让其指向自定义的activity(device/google/cuttlefish/shared/auto/rro_overlay/CarServiceOverlay/res/values/config.xml)。