Advanced AOSP Subsystems
4 min read

Camera Service

Overview

The CameraService is a critical C++ system daemon in Android, responsible for managing access to camera hardware. Located in frameworks/av/services/camera/libcameraservice/, it acts as the centralized arbitrator between multiple client applications (using Camera2 API or NDK) and the underlying hardware abstraction layers (Camera HALs). It ensures security, manages priority-based eviction, and maintains the complex state machine required for robust camera operation.

Architecture and Arbitration

In a modern Android environment, multiple applications might attempt to access the camera simultaneously (e.g., a background service, a foreground social media app, and a system feature like face unlock).

The Eviction Model

CameraService implements a strict priority and eviction policy. Because most camera hardware cannot be shared concurrently across different processes, the service must decide who gets access.

When a client requests a camera via connectDevice(), CameraService:

  1. Evaluates the client's priority based on its process state (foreground vs. background) and importance score (oom_adj).
  2. Checks if the requested device is already open.
  3. If the new client has a strictly higher priority, it forcefully disconnects the existing client, triggering an onDisconnected callback in the evicted application.
// Snippet illustrating priority evaluation in CameraService
status_t CameraService::handleEvictionsLocked(
        const String8& cameraId,
        int clientPid,
        apiLevel effectiveApiLevel,
        const sp<IBinder>& remoteCallback,
        const String8& clientPackageName,
        int clientOomScore,
        /*out*/
        sp<BasicClient>* clientToEvict) {
    
    // Evaluate if incoming client has higher priority than current owner
    if (incomingClientScore > currentOwnerScore) {
        ALOGW("Evicting client %s (pid %d) due to higher priority request from %s",
              currentOwnerName.string(), currentOwnerPid, clientPackageName.string());
        *clientToEvict = currentOwner;
        return OK;
    }
    return -EBUSY; // Device in use by a higher or equal priority client
}

CameraDeviceClient

When a successful connection is established, CameraService creates a CameraDeviceClient instance for that specific connection.

Role of CameraDeviceClient

The CameraDeviceClient implements the hardware::camera2::ICameraDeviceUser AIDL interface. It serves as the proxy through which the Java CameraDevice communicates with the native service.

Key responsibilities include:

  • Request Marshalling: Validating and translating Java CaptureRequest objects into native camera_metadata_t structures.
  • Stream Configuration: Negotiating buffer formats, sizes, and usage flags between the application's Surfaces and the HAL.
  • Callback Dispatch: Routing CaptureResult metadata and stream errors back to the application.

Permission and Privacy Enforcement

Security is a paramount concern for camera access. CameraService rigorously enforces Android's permission model.

Sensor Privacy Manager

Android includes a SensorPrivacyManager (often tied to a hardware or software toggle) that can globally disable camera access. CameraService registers a listener with this manager.

If sensor privacy is toggled ON while a camera is active:

  • The service intercepts the signal.
  • It mutes the output (often by returning blank frames or errors).
  • Or, it forcefully disconnects the client, depending on the Android version and OEM implementation.

AppOps and UID Verification

Every connection request must pass through AppOpsManager. CameraService checks the android.permission.CAMERA permission and ensures the calling UID matches the provided package name, preventing spoofing attacks.

// Permission check example
if (!checkPermission(String16("android.permission.CAMERA"), clientPid, clientUid)) {
    ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
    return PERMISSION_DENIED;
}

State Machine Management

The camera subsystem is highly stateful. CameraService maintains an internal state machine for each device to manage transitions safely.

Typical states include:

  • UNINITIALIZED: Hardware is not powered or initialized.
  • OPENED: The device is claimed, but no streams are configured.
  • CONFIGURED: Streams are negotiated and buffers are allocated.
  • ACTIVE: The hardware is actively processing capture requests.
  • ERROR: A fatal hardware or HAL error occurred.

Transitions between these states must be synchronized to prevent race conditions, especially when handling async callbacks from the HAL alongside new requests from the application.

Diagnostics and Debugging

To inspect the internal state of the CameraService, developers use the dumpsys utility.

# Detailed dump of the camera service
adb shell dumpsys media.camera

This command outputs critical debugging information:

  • Active camera sessions and their owning PIDs.
  • The state of all active streams (dimensions, formats, producer/consumer counts).
  • A history of recent API calls and state transitions.
  • The latest camera metadata sent to and received from the HAL.