Merge "Fix setting camera op restriction on reboot" into sc-qpr1-dev am: 395f43dd6f am: 77251b3ec4

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15983492

Change-Id: I13f6757e3865068b4316143667d8137c75da3c19
This commit is contained in:
Evan Severson
2021-10-07 03:23:09 +00:00
committed by Automerger Merge Worker
6 changed files with 146 additions and 7 deletions

View File

@@ -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);
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<sensor-privacy persistence-version="1" version="1">
<user id="0" enabled="false">
<individual-sensor-privacy sensor="1" enabled="true" />
<individual-sensor-privacy sensor="2" enabled="true" />
</user>
</sensor-privacy>

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<sensor-privacy persistence-version="1" version="1">
<user id="0" enabled="false">
<individual-sensor-privacy sensor="1" enabled="true" />
<individual-sensor-privacy sensor="2" enabled="false" />
</user>
</sensor-privacy>

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<sensor-privacy persistence-version="1" version="1">
<user id="0" enabled="false">
<individual-sensor-privacy sensor="1" enabled="false" />
<individual-sensor-privacy sensor="2" enabled="true" />
</user>
</sensor-privacy>

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<sensor-privacy persistence-version="1" version="1">
<user id="0" enabled="false">
<individual-sensor-privacy sensor="1" enabled="false" />
<individual-sensor-privacy sensor="2" enabled="false" />
</user>
</sensor-privacy>

View File

@@ -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<Boolean> micState = new CompletableFuture<>();
CompletableFuture<Boolean> 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();
}
}