Perform camera permission and app ops check when setting camera for VT.

When a calling InCallService attempts to use the setCamera API on the
VideoCall, Telecom will perform a permission check to ensure that the
caller has the correct camera permission and passes the app-ops camera
check.  A failure to set the camera will result in a callback via the
call session event API.

This got a little messy as the app ops package name needs to come from the
InCallService, and handler usage in the VideoProvider API means we had to
pass around the uid/pid of the caller, obtained before we trampoline onto
the handler.

Test: Unit tests added, manual testing performed.
Bug: 32747443
Change-Id: I555a04f9c3fb45e60bb811f64ba855ccf2e3b0e2
This commit is contained in:
Tyler Gunn
2016-11-09 10:19:23 -08:00
committed by Brad Ebinger
parent ed839943e0
commit bf9c6fdb43
12 changed files with 107 additions and 25 deletions

View File

@@ -25,6 +25,7 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -799,7 +800,7 @@ public abstract class Connection extends Conferenceable {
public static final int SESSION_EVENT_TX_STOP = 4;
/**
* A camera failure has occurred for the selected camera. The {@link InCallService} can use
* A camera failure has occurred for the selected camera. The {@link VideoProvider} can use
* this as a cue to inform the user the camera is not available.
* @see #handleCallSessionEvent(int)
*/
@@ -807,12 +808,20 @@ public abstract class Connection extends Conferenceable {
/**
* Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready
* for operation. The {@link InCallService} can use this as a cue to inform the user that
* for operation. The {@link VideoProvider} can use this as a cue to inform the user that
* the camera has become available again.
* @see #handleCallSessionEvent(int)
*/
public static final int SESSION_EVENT_CAMERA_READY = 6;
/**
* Session event raised by Telecom when
* {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the
* caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission.
* @see #handleCallSessionEvent(int)
*/
public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7;
/**
* Session modify request was successful.
* @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)
@@ -862,6 +871,8 @@ public abstract class Connection extends Conferenceable {
private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP";
private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL";
private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY";
private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR =
"CAMERA_PERMISSION_ERROR";
private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN";
private VideoProvider.VideoProviderHandler mMessageHandler;
@@ -920,8 +931,17 @@ public abstract class Connection extends Conferenceable {
break;
}
case MSG_SET_CAMERA:
onSetCamera((String) msg.obj);
break;
{
SomeArgs args = (SomeArgs) msg.obj;
try {
onSetCamera((String) args.arg1);
onSetCamera((String) args.arg1, (String) args.arg2, args.argi1,
args.argi2);
} finally {
args.recycle();
}
}
break;
case MSG_SET_PREVIEW_SURFACE:
onSetPreviewSurface((Surface) msg.obj);
break;
@@ -976,8 +996,19 @@ public abstract class Connection extends Conferenceable {
MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget();
}
public void setCamera(String cameraId) {
mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget();
public void setCamera(String cameraId, String callingPackageName) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = cameraId;
// Propagate the calling package; originally determined in
// android.telecom.InCallService.VideoCall#setCamera(String) from the calling
// process.
args.arg2 = callingPackageName;
// Pass along the uid and pid of the calling app; this gets lost when we put the
// message onto the handler. These are required for Telecom to perform a permission
// check to see if the calling app is able to use the camera.
args.argi1 = Binder.getCallingUid();
args.argi2 = Binder.getCallingPid();
mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
}
public void setPreviewSurface(Surface surface) {
@@ -1061,6 +1092,29 @@ public abstract class Connection extends Conferenceable {
*/
public abstract void onSetCamera(String cameraId);
/**
* Sets the camera to be used for the outgoing video.
* <p>
* The {@link VideoProvider} should respond by communicating the capabilities of the chosen
* camera via
* {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}.
* <p>
* This prototype is used internally to ensure that the calling package name, UID and PID
* are sent to Telecom so that can perform a camera permission check on the caller.
* <p>
* Sent from the {@link InCallService} via
* {@link InCallService.VideoCall#setCamera(String)}.
*
* @param cameraId The id of the camera (use ids as reported by
* {@link CameraManager#getCameraIdList()}).
* @param callingPackageName The AppOpps package name of the caller.
* @param callingUid The UID of the caller.
* @param callingPid The PID of the caller.
* @hide
*/
public void onSetCamera(String cameraId, String callingPackageName, int callingUid,
int callingPid) {}
/**
* Sets the surface to be used for displaying a preview of what the user's camera is
* currently capturing. When video transmission is enabled, this is the video signal which
@@ -1247,7 +1301,8 @@ public abstract class Connection extends Conferenceable {
* {@link VideoProvider#SESSION_EVENT_TX_START},
* {@link VideoProvider#SESSION_EVENT_TX_STOP},
* {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE},
* {@link VideoProvider#SESSION_EVENT_CAMERA_READY}.
* {@link VideoProvider#SESSION_EVENT_CAMERA_READY},
* {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}.
*/
public void handleCallSessionEvent(int event) {
if (mVideoCallbacks != null) {
@@ -1396,6 +1451,8 @@ public abstract class Connection extends Conferenceable {
return SESSION_EVENT_TX_START_STR;
case SESSION_EVENT_TX_STOP:
return SESSION_EVENT_TX_STOP_STR;
case SESSION_EVENT_CAMERA_PERMISSION_ERROR:
return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR;
default:
return SESSION_EVENT_UNKNOWN_STR + " " + event;
}