android闪光灯源码分析

目录

一、APP层源码分析

二,framework层代码分析

​​​​​​​[2.1 binder溯源](#2.1 binder溯源)


这几天撸了android11 aosp闪光灯源码,本着前人栽树后人乘凉的原则,有志于android系统开发的新同学们提供一盏明灯,照亮你们前行。

本人撸代码风格,喜欢从app撸到kernel,启航出发。

一、APP层源码分析

下拉状态栏,可见"手电筒"快捷开关,点击后开启手电筒,UI见下图,

这部分代码,在目录:frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java,点击按钮回调,

复制代码
    protected void handleClick() {
        if (ActivityManager.isUserAMonkey()) {
            return;
        }
        boolean newState = !mState.value;
        refreshState(newState);
        //点击"手电筒"核心核数
        mFlashlightController.setFlashlight(newState);
    }

通过 mFlashlightController.setFlashlight(newState)走到文件

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java,

复制代码
    public void setFlashlight(boolean enabled) {
        boolean pendingError = false;
        synchronized (this) {
            if (mCameraId == null) return;
            if (mFlashlightEnabled != enabled) {
                mFlashlightEnabled = enabled;
                try {
                    //核心调用
                    mCameraManager.setTorchMode(mCameraId, enabled);
                } catch (CameraAccessException e) {
                    Log.e(TAG, "Couldn't set torch mode", e);
                    mFlashlightEnabled = false;
                    pendingError = true;
                }
            }
        }
        dispatchModeChanged(mFlashlightEnabled);
        if (pendingError) {
            dispatchError();
        }
    }

通过mCameraManager.setTorchMode(mCameraId, enabled)走到frameworks/base/core/java/android/hardware/camera2/CameraManager.java,

复制代码
    public void setTorchMode(@NonNull String cameraId, boolean enabled)
            throws CameraAccessException {
        if (CameraManagerGlobal.sCameraServiceDisabled) {
            throw new IllegalArgumentException("No cameras available on device");
        }
          CameraManagerGlobal.get().setTorchMode(cameraId, enabled);
    }

CameraManagerGlobal.get().setTorchMode(cameraId, enabled)走到,

复制代码
        public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException {
            synchronized(mLock) {

                if (cameraId == null) {
                    throw new IllegalArgumentException("cameraId was null");
                }

                ICameraService cameraService = getCameraService();
                if (cameraService == null) {
                    throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                        "Camera service is currently unavailable");
                }

                try {
                    cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
                } catch(ServiceSpecificException e) {
                    throwAsPublicException(e);
                } catch (RemoteException e) {
                    throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                            "Camera service is currently unavailable");
                }
            }
        }
复制代码
        ICameraService cameraService = getCameraService();看到这句是不是很熟悉,android获取系统服务,跨进程调用。只是和我们app开发常用的 不同,这里直接拿到camera服务的proxy。对下面这行代码不理解的,可以学习下android binder机制,本质就是拿到camera服务的proxy
复制代码
ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);

原来操作"手电筒"的不是单独模块,而是通过camera模块来控制的,666。

二,framework层代码分析

2.1 binder溯源

由第一部分分析可知,"手电筒"通过cameraservice来操作,结合binder知识,可以在ICameraService.aidl接口定义中找到,

复制代码
void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);

aidl文件会自动生成java文件,再通过jni调用到cpp文件,最终在ICameraService.cpp中实现了client的调用,

复制代码
::android::binder::Status BpCameraService::setTorchMode(const ::android::String16& cameraId, bool enabled, const ::android::sp<::android::IBinder>& clientBinder) {
  ::android::Parcel _aidl_data;
  ::android::Parcel _aidl_reply;
  ::android::status_t _aidl_ret_status = ::android::OK;
  ::android::binder::Status _aidl_status;
  _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_data.writeString16(cameraId);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_data.writeBool(enabled);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_data.writeStrongBinder(clientBinder);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = remote()->transact(::android::IBinder::FIRST_CALL_TRANSACTION + 15 /* setTorchMode */, _aidl_data, &_aidl_reply);
  if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && ICameraService::getDefaultImpl())) {
     return ICameraService::getDefaultImpl()->setTorchMode(cameraId, enabled, clientBinder);
  }
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  if (!_aidl_status.isOk()) {
    return _aidl_status;
  }
  _aidl_error:
  _aidl_status.setFromStatusT(_aidl_ret_status);
  return _aidl_status;
}

通过remote()->transact()发起IPC请求,事务码FIRST_CALL_TRANSACTION + 15对应setTorchMode方法,数据通过_aidl_dataParcel传递,执行到CameraService.cpp文件,

复制代码
Status CameraService::setTorchMode(const String16& cameraId, bool enabled,
        const sp<IBinder>& clientBinder) {
    Mutex::Autolock lock(mServiceLock);

    ATRACE_CALL();
    if (enabled && clientBinder == nullptr) {
        ALOGE("%s: torch client binder is NULL", __FUNCTION__);
        return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
                "Torch client Binder is null");
    }

    String8 id = String8(cameraId.string());
    int uid = CameraThreadState::getCallingUid();

    if (shouldRejectSystemCameraConnection(id)) {
        return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "Unable to set torch mode"
                " for system only device %s: ", id.string());
    }
    // verify id is valid.
    auto state = getCameraState(id);
    if (state == nullptr) {
        ALOGE("%s: camera id is invalid %s", __FUNCTION__, id.string());
        return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                "Camera ID \"%s\" is a not valid camera ID", id.string());
    }

    StatusInternal cameraStatus = state->getStatus();
    if (cameraStatus != StatusInternal::PRESENT &&
            cameraStatus != StatusInternal::NOT_AVAILABLE) {
        ALOGE("%s: camera id is invalid %s, status %d", __FUNCTION__, id.string(), (int)cameraStatus);
        return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                "Camera ID \"%s\" is a not valid camera ID", id.string());
    }

    {
        Mutex::Autolock al(mTorchStatusMutex);
        TorchModeStatus status;
        status_t err = getTorchStatusLocked(id, &status);
        if (err != OK) {
            if (err == NAME_NOT_FOUND) {
                return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
                        "Camera \"%s\" does not have a flash unit", id.string());
            }
            ALOGE("%s: getting current torch status failed for camera %s",
                    __FUNCTION__, id.string());
            return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                    "Error updating torch status for camera \"%s\": %s (%d)", id.string(),
                    strerror(-err), err);
        }

        if (status == TorchModeStatus::NOT_AVAILABLE) {
            if (cameraStatus == StatusInternal::NOT_AVAILABLE) {
                ALOGE("%s: torch mode of camera %s is not available because "
                        "camera is in use", __FUNCTION__, id.string());
                return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
                        "Torch for camera \"%s\" is not available due to an existing camera user",
                        id.string());
            } else {
                ALOGE("%s: torch mode of camera %s is not available due to "
                        "insufficient resources", __FUNCTION__, id.string());
                return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
                        "Torch for camera \"%s\" is not available due to insufficient resources",
                        id.string());
            }
        }
    }

    {
        // Update UID map - this is used in the torch status changed callbacks, so must be done
        // before setTorchMode
        Mutex::Autolock al(mTorchUidMapMutex);
        if (mTorchUidMap.find(id) == mTorchUidMap.end()) {
            mTorchUidMap[id].first = uid;
            mTorchUidMap[id].second = uid;
        } else {
            // Set the pending UID
            mTorchUidMap[id].first = uid;
        }
    }

    status_t err = mFlashlight->setTorchMode(id, enabled);

    if (err != OK) {
        int32_t errorCode;
        String8 msg;
        switch (err) {
            case -ENOSYS:
                msg = String8::format("Camera \"%s\" has no flashlight",
                    id.string());
                errorCode = ERROR_ILLEGAL_ARGUMENT;
                break;
            default:
                msg = String8::format(
                    "Setting torch mode of camera \"%s\" to %d failed: %s (%d)",
                    id.string(), enabled, strerror(-err), err);
                errorCode = ERROR_INVALID_OPERATION;
        }
        ALOGE("%s: %s", __FUNCTION__, msg.string());
        return STATUS_ERROR(errorCode, msg.string());
    }

    {
        // update the link to client's death
        Mutex::Autolock al(mTorchClientMapMutex);
        ssize_t index = mTorchClientMap.indexOfKey(id);
        if (enabled) {
            if (index == NAME_NOT_FOUND) {
                mTorchClientMap.add(id, clientBinder);
            } else {
                mTorchClientMap.valueAt(index)->unlinkToDeath(this);
                mTorchClientMap.replaceValueAt(index, clientBinder);
            }
            clientBinder->linkToDeath(this);
        } else if (index != NAME_NOT_FOUND) {
            mTorchClientMap.valueAt(index)->unlinkToDeath(this);
        }
    }

    int clientPid = CameraThreadState::getCallingPid();
    const char *id_cstr = id.c_str();
    const char *torchState = enabled ? "on" : "off";
    ALOGI("Torch for camera id %s turned %s for client PID %d", id_cstr, torchState, clientPid);
    logTorchEvent(id_cstr, torchState , clientPid);
    return Status::ok();
}

其中,关键句status_t err = mFlashlight->setTorchMode(id, enabled);再由hal层交互可知,‌

最终通过CameraProviderManager查询HAL实现的setTorchMode()接口来控制device。

复制代码
status_t CameraProviderManager::setTorchMode(const std::string &id, bool enabled) {
    std::lock_guard<std::mutex> lock(mInterfaceMutex);

    auto deviceInfo = findDeviceInfoLocked(id);
    if (deviceInfo == nullptr) return NAME_NOT_FOUND;

    // Pass the camera ID to start interface so that it will save it to the map of ICameraProviders
    // that are currently in use.
    sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
    if (parentProvider == nullptr) {
        return DEAD_OBJECT;
    }
    const sp<provider::V2_4::ICameraProvider> interface = parentProvider->startProviderInterface();
    if (interface == nullptr) {
        return DEAD_OBJECT;
    }
    saveRef(DeviceMode::TORCH, deviceInfo->mId, interface);

    return deviceInfo->setTorchMode(enabled);
}

最终,通过deviceInfo->setTorchMode(enabled)来实现对硬件的操作。