From 2e4241337d7325de4373383eb5a6fc0b4dbfe460 Mon Sep 17 00:00:00 2001 From: Evan Severson Date: Tue, 5 Oct 2021 09:18:41 -0700 Subject: [PATCH] Fix setting camera op restriction on reboot In SensorPrivacyService we set the camera state to what was read on the microphone's persisted value. Test: atest SensorPrivacyServiceMockingTest Fixes: 201793410 Change-Id: If5cbd2b6cd2c8e155b8a56e0692a0379d188ffce --- .../android/server/SensorPrivacyService.java | 13 +- .../persisted_file_micMute_camMute.xml | 7 ++ .../persisted_file_micMute_camUnmute.xml | 7 ++ .../persisted_file_micUnmute_camMute.xml | 7 ++ .../persisted_file_micUnmute_camUnmute.xml | 7 ++ .../SensorPrivacyServiceMockingTest.java | 112 +++++++++++++++++- 6 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micMute_camMute.xml create mode 100644 services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micMute_camUnmute.xml create mode 100644 services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camMute.xml create mode 100644 services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camUnmute.xml diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java index 93a820cf14069..06a78c864cac2 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -39,6 +39,7 @@ import static android.hardware.SensorPrivacyManager.Sources.OTHER; import static android.hardware.SensorPrivacyManager.Sources.QS_TILE; import static android.hardware.SensorPrivacyManager.Sources.SETTINGS; import static android.hardware.SensorPrivacyManager.Sources.SHELL; +import static android.os.UserHandle.USER_NULL; import static android.os.UserHandle.USER_SYSTEM; import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN; @@ -195,7 +196,7 @@ public final class SensorPrivacyService extends SystemService { private EmergencyCallHelper mEmergencyCallHelper; private KeyguardManager mKeyguardManager; - private int mCurrentUser = -1; + private int mCurrentUser = USER_NULL; public SensorPrivacyService(Context context) { super(context); @@ -228,9 +229,9 @@ public final class SensorPrivacyService extends SystemService { @Override public void onUserStarting(TargetUser user) { - if (mCurrentUser == -1) { + if (mCurrentUser == USER_NULL) { mCurrentUser = user.getUserIdentifier(); - mSensorPrivacyServiceImpl.userSwitching(-1, user.getUserIdentifier()); + mSensorPrivacyServiceImpl.userSwitching(USER_NULL, user.getUserIdentifier()); } } @@ -1294,13 +1295,13 @@ public final class SensorPrivacyService extends SystemService { micState = isIndividualSensorPrivacyEnabledLocked(to, MICROPHONE); camState = isIndividualSensorPrivacyEnabledLocked(to, CAMERA); } - if (prevMicState != micState) { + if (from == USER_NULL || prevMicState != micState) { mHandler.onUserGlobalSensorPrivacyChanged(MICROPHONE, micState); setGlobalRestriction(MICROPHONE, micState); } - if (prevCamState != camState) { + if (from == USER_NULL || prevCamState != camState) { mHandler.onUserGlobalSensorPrivacyChanged(CAMERA, camState); - setGlobalRestriction(CAMERA, micState); + setGlobalRestriction(CAMERA, camState); } } diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micMute_camMute.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micMute_camMute.xml new file mode 100644 index 0000000000000..a4de08a854873 --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micMute_camMute.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micMute_camUnmute.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micMute_camUnmute.xml new file mode 100644 index 0000000000000..47649d7392e64 --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micMute_camUnmute.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camMute.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camMute.xml new file mode 100644 index 0000000000000..4fd9ebf987174 --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camMute.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camUnmute.xml b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camUnmute.xml new file mode 100644 index 0000000000000..e8f9edfde2d7d --- /dev/null +++ b/services/tests/mockingservicestests/assets/SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camUnmute.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java index ba79a764b6729..38f01b5acc0c8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/sensorprivacy/SensorPrivacyServiceMockingTest.java @@ -16,12 +16,18 @@ package com.android.server.sensorprivacy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; + import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.AppOpsManager; +import android.app.AppOpsManagerInternal; import android.content.Context; import android.content.pm.UserInfo; import android.os.Environment; @@ -33,8 +39,10 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.server.LocalServices; import com.android.server.SensorPrivacyService; +import com.android.server.SystemService; import com.android.server.pm.UserManagerInternal; +import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -44,6 +52,7 @@ import org.mockito.quality.Strictness; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.util.concurrent.CompletableFuture; @RunWith(AndroidTestingRunner.class) public class SensorPrivacyServiceMockingTest { @@ -63,10 +72,21 @@ public class SensorPrivacyServiceMockingTest { public static final String PERSISTENCE_FILE6 = String.format(PERSISTENCE_FILE_PATHS_TEMPLATE, 6); + public static final String PERSISTENCE_FILE_MIC_MUTE_CAM_MUTE = + "SensorPrivacyServiceMockingTest/persisted_file_micMute_camMute.xml"; + public static final String PERSISTENCE_FILE_MIC_MUTE_CAM_UNMUTE = + "SensorPrivacyServiceMockingTest/persisted_file_micMute_camUnmute.xml"; + public static final String PERSISTENCE_FILE_MIC_UNMUTE_CAM_MUTE = + "SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camMute.xml"; + public static final String PERSISTENCE_FILE_MIC_UNMUTE_CAM_UNMUTE = + "SensorPrivacyServiceMockingTest/persisted_file_micUnmute_camUnmute.xml"; + private Context mContext; @Mock private AppOpsManager mMockedAppOpsManager; @Mock + private AppOpsManagerInternal mMockedAppOpsManagerInternal; + @Mock private UserManagerInternal mMockedUserManagerInternal; @Mock private ActivityManager mMockedActivityManager; @@ -134,13 +154,103 @@ public class SensorPrivacyServiceMockingTest { } } + @Test + public void testServiceInit_AppOpsRestricted_micMute_camMute() throws IOException { + testServiceInit_AppOpsRestricted(PERSISTENCE_FILE_MIC_MUTE_CAM_MUTE, true, true); + } + + @Test + public void testServiceInit_AppOpsRestricted_micMute_camUnmute() throws IOException { + testServiceInit_AppOpsRestricted(PERSISTENCE_FILE_MIC_MUTE_CAM_UNMUTE, true, false); + } + + @Test + public void testServiceInit_AppOpsRestricted_micUnmute_camMute() throws IOException { + testServiceInit_AppOpsRestricted(PERSISTENCE_FILE_MIC_UNMUTE_CAM_MUTE, false, true); + } + + @Test + public void testServiceInit_AppOpsRestricted_micUnmute_camUnmute() throws IOException { + testServiceInit_AppOpsRestricted(PERSISTENCE_FILE_MIC_UNMUTE_CAM_UNMUTE, false, false); + } + + private void testServiceInit_AppOpsRestricted(String persistenceFileMicMuteCamMute, + boolean expectedMicState, boolean expectedCamState) + throws IOException { + MockitoSession mockitoSession = ExtendedMockito.mockitoSession() + .initMocks(this) + .strictness(Strictness.WARN) + .spyStatic(LocalServices.class) + .spyStatic(Environment.class) + .startMocking(); + + try { + mContext = InstrumentationRegistry.getInstrumentation().getContext(); + spyOn(mContext); + + doReturn(mMockedAppOpsManager).when(mContext).getSystemService(AppOpsManager.class); + doReturn(mMockedAppOpsManagerInternal) + .when(() -> LocalServices.getService(AppOpsManagerInternal.class)); + doReturn(mMockedUserManagerInternal) + .when(() -> LocalServices.getService(UserManagerInternal.class)); + doReturn(mMockedActivityManager).when(mContext).getSystemService(ActivityManager.class); + doReturn(mMockedActivityTaskManager) + .when(mContext).getSystemService(ActivityTaskManager.class); + doReturn(mMockedTelephonyManager).when(mContext).getSystemService( + TelephonyManager.class); + + String dataDir = mContext.getApplicationInfo().dataDir; + doReturn(new File(dataDir)).when(() -> Environment.getDataSystemDirectory()); + + File onDeviceFile = new File(dataDir, "sensor_privacy.xml"); + onDeviceFile.delete(); + + doReturn(new int[]{0}).when(mMockedUserManagerInternal).getUserIds(); + doReturn(ExtendedMockito.mock(UserInfo.class)).when(mMockedUserManagerInternal) + .getUserInfo(0); + + CompletableFuture micState = new CompletableFuture<>(); + CompletableFuture camState = new CompletableFuture<>(); + doAnswer(invocation -> { + int code = invocation.getArgument(0); + boolean restricted = invocation.getArgument(1); + if (code == AppOpsManager.OP_RECORD_AUDIO) { + micState.complete(restricted); + } else if (code == AppOpsManager.OP_CAMERA) { + camState.complete(restricted); + } + return null; + }).when(mMockedAppOpsManagerInternal).setGlobalRestriction(anyInt(), anyBoolean(), + any()); + + initServiceWithPersistenceFile(onDeviceFile, persistenceFileMicMuteCamMute, 0); + + Assert.assertTrue(micState.join() == expectedMicState); + Assert.assertTrue(camState.join() == expectedCamState); + + } finally { + mockitoSession.finishMocking(); + } + } + private void initServiceWithPersistenceFile(File onDeviceFile, String persistenceFilePath) throws IOException { + initServiceWithPersistenceFile(onDeviceFile, persistenceFilePath, -1); + } + + private void initServiceWithPersistenceFile(File onDeviceFile, + String persistenceFilePath, int startingUserId) throws IOException { if (persistenceFilePath != null) { Files.copy(mContext.getAssets().open(persistenceFilePath), onDeviceFile.toPath()); } - new SensorPrivacyService(mContext); + SensorPrivacyService service = new SensorPrivacyService(mContext); + if (startingUserId != -1) { + SystemService.TargetUser mockedTargetUser = + ExtendedMockito.mock(SystemService.TargetUser.class); + doReturn(startingUserId).when(mockedTargetUser).getUserIdentifier(); + service.onUserStarting(mockedTargetUser); + } onDeviceFile.delete(); } }