No camera for idle uids - framework
If a UID is idle (being in the background for more than
cartain amount of time) it should not be able to use the
camera. If the UID becomes idle we generate an eror and
close the cameras for this UID. If an app in an idle UID
tries to use the camera we immediately generate an error.
Since apps already should handle these errors it is safe
to apply this policy to all apps to protect user privacy.
Test: Pass - cts-tradefed run cts -m CtsCameraTestCases
Added - CameraTest#testCameraAccessForIdleUid
Change-Id: If6ad1662f2af6592b6aca1aeee4bd481389b5e00
This commit is contained in:
@@ -1325,6 +1325,25 @@ public class AppOpsManager {
|
||||
return sOpDefaultMode[op];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the human readable mode.
|
||||
* @hide
|
||||
*/
|
||||
public static String modeToString(int mode) {
|
||||
switch (mode) {
|
||||
case MODE_ALLOWED:
|
||||
return "allow";
|
||||
case MODE_IGNORED:
|
||||
return "ignore";
|
||||
case MODE_ERRORED:
|
||||
return "deny";
|
||||
case MODE_DEFAULT:
|
||||
return "default";
|
||||
default:
|
||||
return "mode=" + mode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve whether the op allows itself to be reset.
|
||||
* @hide
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
|
||||
package android.hardware.camera2.impl;
|
||||
|
||||
import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
|
||||
import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
|
||||
|
||||
import android.graphics.ImageFormat;
|
||||
import android.hardware.camera2.CameraAccessException;
|
||||
import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
@@ -31,7 +30,6 @@ import android.hardware.camera2.ICameraDeviceUser;
|
||||
import android.hardware.camera2.TotalCaptureResult;
|
||||
import android.hardware.camera2.params.InputConfiguration;
|
||||
import android.hardware.camera2.params.OutputConfiguration;
|
||||
import android.hardware.camera2.params.ReprocessFormatsMap;
|
||||
import android.hardware.camera2.params.SessionConfiguration;
|
||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||
import android.hardware.camera2.utils.SubmitInfo;
|
||||
@@ -1798,34 +1796,36 @@ public class CameraDeviceImpl extends CameraDevice
|
||||
case ERROR_CAMERA_DISCONNECTED:
|
||||
CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown error from camera device: " + errorCode);
|
||||
// no break
|
||||
case ERROR_CAMERA_DEVICE:
|
||||
case ERROR_CAMERA_SERVICE:
|
||||
mInError = true;
|
||||
final int publicErrorCode = (errorCode == ERROR_CAMERA_DEVICE) ?
|
||||
StateCallback.ERROR_CAMERA_DEVICE :
|
||||
StateCallback.ERROR_CAMERA_SERVICE;
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!CameraDeviceImpl.this.isClosed()) {
|
||||
mDeviceCallback.onError(CameraDeviceImpl.this, publicErrorCode);
|
||||
}
|
||||
}
|
||||
};
|
||||
CameraDeviceImpl.this.mDeviceHandler.post(r);
|
||||
break;
|
||||
case ERROR_CAMERA_REQUEST:
|
||||
case ERROR_CAMERA_RESULT:
|
||||
case ERROR_CAMERA_BUFFER:
|
||||
onCaptureErrorLocked(errorCode, resultExtras);
|
||||
break;
|
||||
case ERROR_CAMERA_DEVICE:
|
||||
scheduleNotifyError(StateCallback.ERROR_CAMERA_DEVICE);
|
||||
break;
|
||||
case ERROR_CAMERA_DISABLED:
|
||||
scheduleNotifyError(StateCallback.ERROR_CAMERA_DISABLED);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown error from camera device: " + errorCode);
|
||||
scheduleNotifyError(StateCallback.ERROR_CAMERA_SERVICE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleNotifyError(int code) {
|
||||
mInError = true;
|
||||
CameraDeviceImpl.this.mDeviceHandler.post(obtainRunnable(
|
||||
CameraDeviceCallbacks::notifyError, this, code));
|
||||
}
|
||||
|
||||
private void notifyError(int code) {
|
||||
if (!CameraDeviceImpl.this.isClosed()) {
|
||||
mDeviceCallback.onError(CameraDeviceImpl.this, code);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
|
||||
if (DEBUG) {
|
||||
|
||||
@@ -3711,6 +3711,11 @@
|
||||
<permission android:name="android.permission.MODIFY_QUIET_MODE"
|
||||
android:protectionLevel="signature|privileged" />
|
||||
|
||||
<!-- Allows internal management of the camera framework
|
||||
@hide -->
|
||||
<permission android:name="android.permission.MANAGE_CAMERA"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows an application to control remote animations. See
|
||||
{@link ActivityOptions#makeRemoteAnimation}
|
||||
@hide <p>Not for use by third-party applications. -->
|
||||
|
||||
@@ -162,6 +162,7 @@
|
||||
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
|
||||
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
|
||||
<assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="cameraserver" />
|
||||
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="cameraserver" />
|
||||
|
||||
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
|
||||
|
||||
|
||||
@@ -136,8 +136,8 @@
|
||||
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE" />
|
||||
<uses-permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_SENSORS" />
|
||||
|
||||
<uses-permission android:name="android.permission.MANAGE_AUDIO_POLICY" />
|
||||
<uses-permission android:name="android.permission.MANAGE_CAMERA" />
|
||||
|
||||
<application android:label="@string/app_label"
|
||||
android:defaultToDeviceProtectedStorage="true"
|
||||
|
||||
@@ -1316,14 +1316,8 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
isPrivileged = (appInfo.privateFlags
|
||||
& ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
|
||||
} else {
|
||||
if ("media".equals(packageName)) {
|
||||
pkgUid = Process.MEDIA_UID;
|
||||
isPrivileged = false;
|
||||
} else if ("audioserver".equals(packageName)) {
|
||||
pkgUid = Process.AUDIOSERVER_UID;
|
||||
isPrivileged = false;
|
||||
} else if ("cameraserver".equals(packageName)) {
|
||||
pkgUid = Process.CAMERASERVER_UID;
|
||||
pkgUid = resolveUid(packageName);
|
||||
if (pkgUid >= 0) {
|
||||
isPrivileged = false;
|
||||
}
|
||||
}
|
||||
@@ -1957,9 +1951,8 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
if (nonpackageUid != -1) {
|
||||
packageName = null;
|
||||
} else {
|
||||
if ("root".equals(packageName)) {
|
||||
packageUid = 0;
|
||||
} else {
|
||||
packageUid = resolveUid(packageName);
|
||||
if (packageUid < 0) {
|
||||
packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
|
||||
}
|
||||
@@ -2052,6 +2045,10 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
if (ops == null || ops.size() <= 0) {
|
||||
pw.println("No operations.");
|
||||
if (shell.op > AppOpsManager.OP_NONE && shell.op < AppOpsManager._NUM_OP) {
|
||||
pw.println("Default mode: " + AppOpsManager.modeToString(
|
||||
AppOpsManager.opToDefaultMode(shell.op)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
final long now = System.currentTimeMillis();
|
||||
@@ -2061,24 +2058,7 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
AppOpsManager.OpEntry ent = entries.get(j);
|
||||
pw.print(AppOpsManager.opToName(ent.getOp()));
|
||||
pw.print(": ");
|
||||
switch (ent.getMode()) {
|
||||
case AppOpsManager.MODE_ALLOWED:
|
||||
pw.print("allow");
|
||||
break;
|
||||
case AppOpsManager.MODE_IGNORED:
|
||||
pw.print("ignore");
|
||||
break;
|
||||
case AppOpsManager.MODE_ERRORED:
|
||||
pw.print("deny");
|
||||
break;
|
||||
case AppOpsManager.MODE_DEFAULT:
|
||||
pw.print("default");
|
||||
break;
|
||||
default:
|
||||
pw.print("mode=");
|
||||
pw.print(ent.getMode());
|
||||
break;
|
||||
}
|
||||
pw.print(AppOpsManager.modeToString(ent.getMode()));
|
||||
if (ent.getTime() != 0) {
|
||||
pw.print("; time=");
|
||||
TimeUtils.formatDuration(now - ent.getTime(), pw);
|
||||
@@ -2563,16 +2543,41 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
|
||||
private static String resolvePackageName(int uid, String packageName) {
|
||||
if (uid == 0) {
|
||||
if (uid == Process.ROOT_UID) {
|
||||
return "root";
|
||||
} else if (uid == Process.SHELL_UID) {
|
||||
return "com.android.shell";
|
||||
} else if (uid == Process.MEDIA_UID) {
|
||||
return "media";
|
||||
} else if (uid == Process.AUDIOSERVER_UID) {
|
||||
return "audioserver";
|
||||
} else if (uid == Process.CAMERASERVER_UID) {
|
||||
return "cameraserver";
|
||||
} else if (uid == Process.SYSTEM_UID && packageName == null) {
|
||||
return "android";
|
||||
}
|
||||
return packageName;
|
||||
}
|
||||
|
||||
private static int resolveUid(String packageName) {
|
||||
if (packageName == null) {
|
||||
return -1;
|
||||
}
|
||||
switch (packageName) {
|
||||
case "root":
|
||||
return Process.ROOT_UID;
|
||||
case "shell":
|
||||
return Process.SHELL_UID;
|
||||
case "media":
|
||||
return Process.MEDIA_UID;
|
||||
case "audioserver":
|
||||
return Process.AUDIOSERVER_UID;
|
||||
case "cameraserver":
|
||||
return Process.CAMERASERVER_UID;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static String[] getPackagesForUid(int uid) {
|
||||
String[] packageNames = null;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user