Search code examples
androidcameraandroid-camerahardwareusagestatsmanager

How to restrict or detect an active camera device in a background process in Android?


I am working on a security requirement for our product which states that the camera cannot be active while using our library. All of the possible solutions I investigated lack uniformity and coverage of all potential edge cases because with the most recent Android API levels users privacy is getting enhanced and for example, ActivityManager.getRunningTasks(int maxInt) and ActivityManager.getRunningAppProcesses() are deprecated and limited based on Android Docs, which could potentially give a solution.

Some other potential ways(based on Android Docs) of finding out if the camera is active:

  1. android.hardware.camera2.CameraManager
  • Higher-priority(top most (foreground)) process in general gets highest priority when accessing the camera
  • Opening more than one camera produces undefined behavior depending on device implementation or API level: throws a CameraAccessException in case someone already uses the camera(but still depends on the configuration), one or more of already opened CameraDevice will be disconnected
  • AvailabilityCallback could be used to detect if a camera is unavailable(meaning someone started using it), but what if the camera was active before launching our library
  1. Device administration
  • Used for enterprise apps and we are not.
  • They started deprecating disable-camera policy.
  1. UsageStatsManager (probably the most promising)
  • UsageStatsManager.queryEvents Logs:

    1: W UsageStatsManager TEST :: UsageStats event: me.jagar.xscamera2 8 secodns ago
    2: W UsageStatsManager TEST :: UsageStats event: me.jagar.xscamera2 8 secodns ago
    3: W UsageStatsManager TEST :: UsageStats event: com.google.android.apps.nexuslauncher 8 secodns ago
    4: W UsageStatsManager TEST :: UsageStats event: android 8 secodns ago 5: W UsageStatsManager TEST :: UsageStats event: me.jagar.xscamera2 7 secodns ago
    6: W UsageStatsManager TEST :: UsageStats event: com.google.android.apps.nexuslauncher 1 secodns ago

In line 4 that's where android hardware(camera) service is being activated by me.jagar.xscamera2. Complication: cannot rely on just android package name(says nothing about "camera service")

  • In addition, UsageStatsManager provides types of the events captured. Logs:

    1: W UsageStatsManager TEST :: UsageStats event PKG NAME: me.jagar.xscamera2 :: 29 secodns ago :: TYPE: 19 -- HERE I STARTED THE RECORDING

    2: W UsageStatsManager TEST :: UsageStats event PKG NAME: me.jagar.xscamera2 :: 29 secodns ago :: TYPE: 2

    3: W UsageStatsManager TEST :: UsageStats event PKG NAME: com.google.android.apps.nexuslauncher :: 29 secodns ago :: TYPE: 1

    4: W UsageStatsManager TEST :: UsageStats event PKG NAME: android :: 29 secodns ago :: TYPE: 12

    5: W UsageStatsManager TEST :: UsageStats event PKG NAME: me.jagar.xscamera2 :: 29 secodns ago :: TYPE: 23

    6: W UsageStatsManager TEST :: UsageStats event PKG NAME: com.google.android.apps.nexuslauncher :: 22 secodns ago :: TYPE: 2

    7: W UsageStatsManager TEST :: UsageStats event PKG NAME: com.google.android.apps.nexuslauncher :: 21 secodns ago :: TYPE: 23

    8: W UsageStatsManager TEST :: UsageStats event PKG NAME: me.jagar.xscamera2 :: 19 secodns ago :: TYPE: 12

    9: W UsageStatsManager TEST :: UsageStats event PKG NAME: me.jagar.xscamera2 :: 11 secodns ago :: TYPE: 1

    10: W UsageStatsManager TEST :: UsageStats event PKG NAME: me.jagar.xscamera2 :: 8 secodns ago :: TYPE: 20 -- HERE I STOPED THE RECORDING

Where:

UsageEvents.NOTIFICATION_INTERRUPTION = 12
UsageEvents.FOREGROUND_SERVICE_START = 19
UsageEvents.FOREGROUND_SERVICE_STOP = 20

me.jagar.xscamera2 is an arbitrary app what starts a foreground service for a preview and uses camera device to record in background.

Complication: Nothing tells me about camera device specifically. However, we can restrict any foreground service, which potentially gains preference to acquire the camera device, but on the other hand how do I make sure that I capture a long enough events list to see if the foreground service was started let's say a week ago, but never stopped? A year ago?

This answer has something useful: https://stackoverflow.com/a/39936381/23303897 . But I am not completely sure what do they mean.

Any other thoughts and solutions? What am I missing?


Solution

  • So, the answer is to use CameraManager.AvailabilityCallback

    In my initial question I said that AvailabilityCallback could be used to detect if a camera is unavailable(meaning someone started using it), but what if the camera was active before launching our library?!

    I missed/misinterpreted one sentence from docs which states:

    The first time a callback is registered, it is immediately called with the availability status of all currently known camera devices.

    Docs source: https://developer.android.com/reference/android/hardware/camera2/CameraManager#registerAvailabilityCallback(android.hardware.camera2.CameraManager.AvailabilityCallback,%20android.os.Handler)

    If you have the same issue make sure to implement CameraManager.AvailabilityCallback and registerAvailabilityCallback(...). Implement your logic inside the callback covering the initial case when you roll call statuses of all currently known camera devices and then listen for the new states of the camera devices and do what you gotta do... Make sure to unregister the same instance of CameraManager.AvailabilityCallback!