Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e14c632 authored by Tyler Gunn's avatar Tyler Gunn Committed by android-build-merger
Browse files

When setting camera, ensure calling user is the same as logged in user. am:...

When setting camera, ensure calling user is the same as logged in user. am: d8a27d5f am: 05a2ac2d
am: 90b7645a

Change-Id: I43936faeba5b56ceba870cf58079ded4d66a24be
parents f6bee082 90b7645a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -2008,7 +2008,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {

        if (videoProvider != null ) {
            try {
                mVideoProviderProxy = new VideoProviderProxy(mLock, videoProvider, this);
                mVideoProviderProxy = new VideoProviderProxy(mLock, videoProvider, this,
                        mCallsManager);
            } catch (RemoteException ignored) {
                // Ignore RemoteException.
            }
+4 −2
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ import java.util.stream.Stream;
 */
@VisibleForTesting
public class CallsManager extends Call.ListenerBase
        implements VideoProviderProxy.Listener, CallFilterResultCallback {
        implements VideoProviderProxy.Listener, CallFilterResultCallback, CurrentUserProxy {

    // TODO: Consider renaming this CallsManagerPlugin.
    @VisibleForTesting
@@ -650,6 +650,7 @@ public class CallsManager extends Call.ListenerBase
        return mCallAudioManager.getForegroundCall();
    }

    @Override
    public UserHandle getCurrentUserHandle() {
        return mCurrentUserHandle;
    }
@@ -2274,7 +2275,8 @@ public class CallsManager extends Call.ListenerBase
     * Callback when foreground user is switched. We will reload missed call in all profiles
     * including the user itself. There may be chances that profiles are not started yet.
     */
    void onUserSwitch(UserHandle userHandle) {
    @VisibleForTesting
    public void onUserSwitch(UserHandle userHandle) {
        mCurrentUserHandle = userHandle;
        mMissedCallNotifier.setCurrentUserHandle(userHandle);
        final UserManager userManager = UserManager.get(mContext);
+29 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.server.telecom;

import android.os.UserHandle;

/**
 * Defines common functionality for a class which has knowledge of the currently logged in user.
 * Implemented by {@link CallsManager} and used by {@link VideoProviderProxy} so that it does not
 * have a dependency on the entire CallsManager when all that is required is the ability to find out
 * the handle of the currently logged in user.
 */
public interface CurrentUserProxy {
    UserHandle getCurrentUserHandle();
}
+23 −4
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.UserHandle;
import android.telecom.Connection;
import android.telecom.InCallService;
import android.telecom.Log;
@@ -88,6 +89,11 @@ public class VideoProviderProxy extends Connection.VideoProvider {
     */
    private Call mCall;

    /**
     * Interface providing access to the currently logged in user.
     */
    private CurrentUserProxy mCurrentUserProxy;

    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
@@ -106,7 +112,8 @@ public class VideoProviderProxy extends Connection.VideoProvider {
     * @throws RemoteException Remote exception.
     */
    VideoProviderProxy(TelecomSystem.SyncRoot lock,
            IVideoProvider videoProvider, Call call) throws RemoteException {
            IVideoProvider videoProvider, Call call, CurrentUserProxy currentUserProxy)
            throws RemoteException {

        super(Looper.getMainLooper());

@@ -118,6 +125,7 @@ public class VideoProviderProxy extends Connection.VideoProvider {
        mVideoCallListenerBinder = new VideoCallListenerBinder();
        mConectionServiceVideoProvider.addVideoCallback(mVideoCallListenerBinder);
        mCall = call;
        mCurrentUserProxy = currentUserProxy;
    }

    /**
@@ -300,13 +308,15 @@ public class VideoProviderProxy extends Connection.VideoProvider {
    public void onSetCamera(String cameraId, String callingPackage, int callingUid,
            int callingPid) {
        synchronized (mLock) {
            logFromInCall("setCamera: " + cameraId + " callingPackage=" + callingPackage);
            logFromInCall("setCamera: " + cameraId + " callingPackage=" + callingPackage +
                    "; callingUid=" + callingUid);

            if (!TextUtils.isEmpty(cameraId)) {
                if (!canUseCamera(mCall.getContext(), callingPackage, callingUid, callingPid)) {
                    // Calling app is not permitted to use the camera.  Ignore the request and send
                    // back a call session event indicating the error.
                    Log.i(this, "onSetCamera: camera permission denied; package=%d, uid=%d, pid=%d",
                    Log.i(this, "onSetCamera: camera permission denied; package=%d, uid=%d, "
                            + "pid=%d",
                            callingPackage, callingUid, callingPid);
                    VideoProviderProxy.this.handleCallSessionEvent(
                            Connection.VideoProvider.SESSION_EVENT_CAMERA_PERMISSION_ERROR);
@@ -528,11 +538,20 @@ public class VideoProviderProxy extends Connection.VideoProvider {
     * @param context The context.
     * @param callingPackage The package name of the caller (i.e. Dialer).
     * @param callingUid The UID of the caller.
     * @param callingPid The PID of the caller.
     * @return {@code true} if the calling uid and package can use the camera, {@code false}
     *      otherwise.
     */
    private boolean canUseCamera(Context context, String callingPackage, int callingUid,
            int callingPid) {

        UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
        UserHandle currentUserHandle = mCurrentUserProxy.getCurrentUserHandle();
        if (currentUserHandle != null && !currentUserHandle.equals(callingUser)) {
            Log.w(this, "canUseCamera attempt to user camera by background user.");
            return false;
        }

        try {
            context.enforcePermission(Manifest.permission.CAMERA, callingPid, callingUid,
                    "Camera permission required.");
@@ -548,7 +567,7 @@ public class VideoProviderProxy extends Connection.VideoProvider {
            return appOpsManager != null && appOpsManager.noteOp(AppOpsManager.OP_CAMERA,
                    callingUid, callingPackage) == AppOpsManager.MODE_ALLOWED;
        } catch (SecurityException se) {
            Log.w(this, "canUserCamera got appOpps Exception " + se.toString());
            Log.w(this, "canUseCamera got appOpps Exception " + se.toString());
            return false;
        }
    }
+26 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.graphics.SurfaceTexture;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.telecom.Connection.VideoProvider;
import android.telecom.InCallService;
import android.telecom.InCallService.VideoCall;
@@ -210,6 +211,31 @@ public class VideoProviderTest extends TelecomSystemTest {
                sessionEventCaptor.getValue().intValue());
    }

    /**
     * Tests the caller user handle check in {@link VideoCall#setCamera(String)} to ensure a camera
     * change from a background user is not permitted.
     */
    @MediumTest
    public void testCameraChangeUserFail() throws Exception {
        // Wait until the callback has been received before performing verification.
        doAnswer(mVerification).when(mVideoCallCallback).onCallSessionEvent(anyInt());

        // Set a fake user to be the current foreground user.
        mTelecomSystem.getCallsManager().onUserSwitch(new UserHandle(1000));

        // Make a request to change the camera
        mVideoCall.setCamera(MockVideoProvider.CAMERA_FRONT);
        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);

        // Capture the session event reported via the callback.
        ArgumentCaptor<Integer> sessionEventCaptor = ArgumentCaptor.forClass(Integer.class);
        verify(mVideoCallCallback, timeout(TEST_TIMEOUT)).onCallSessionEvent(
                sessionEventCaptor.capture());

        assertEquals(VideoProvider.SESSION_EVENT_CAMERA_PERMISSION_ERROR,
                sessionEventCaptor.getValue().intValue());
    }

    /**
     * Tests the caller permission check in {@link VideoCall#setCamera(String)} to ensure the
     * caller can null out the camera, even if they do not have camera permission.