summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/ISensorPrivacyManager.aidl5
-rw-r--r--core/java/android/hardware/SensorPrivacyManager.java27
-rw-r--r--core/proto/android/hardware/sensorprivacy.proto18
-rw-r--r--services/core/java/com/android/server/SensorPrivacyService.java356
4 files changed, 328 insertions, 78 deletions
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index 4e368d0610b3..46682adcb147 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -34,10 +34,11 @@ interface ISensorPrivacyManager {
// =============== End of transactions used on native side as well ============================
// TODO(evanseverson) add to native interface
- boolean isIndividualSensorPrivacyEnabled(int sensor);
+ boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
// TODO(evanseverson) add to native interface
- void setIndividualSensorPrivacy(int sensor, boolean enable);
+ void setIndividualSensorPrivacy(int userId, int sensor, boolean enable);
+ void setIndividualSensorPrivacyForProfileGroup(int userId, int sensor, boolean enable);
// TODO(evanseverson) listeners
} \ No newline at end of file
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index c647239d9049..4d488715b2c5 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.UserIdInt;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
@@ -198,9 +199,10 @@ public final class SensorPrivacyManager {
*
* @return true if sensor privacy is currently enabled, false otherwise.
*/
- public boolean isIndividualSensorPrivacyEnabled(@IndividualSensor int sensor) {
+ public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId,
+ @IndividualSensor int sensor) {
try {
- return mService.isIndividualSensorPrivacyEnabled(sensor);
+ return mService.isIndividualSensorPrivacyEnabled(userId, sensor);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -212,9 +214,26 @@ public final class SensorPrivacyManager {
* @param enable the state to which sensor privacy should be set.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
- public void setIndividualSensorPrivacy(@IndividualSensor int sensor, boolean enable) {
+ public void setIndividualSensorPrivacy(@UserIdInt int userId, @IndividualSensor int sensor,
+ boolean enable) {
try {
- mService.setIndividualSensorPrivacy(sensor, enable);
+ mService.setIndividualSensorPrivacy(userId, sensor, enable);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets sensor privacy to the specified state for an individual sensor for the profile group of
+ * the given user.
+ *
+ * @param enable the state to which sensor privacy should be set.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_SENSOR_PRIVACY)
+ public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId,
+ @IndividualSensor int sensor, boolean enable) {
+ try {
+ mService.setIndividualSensorPrivacyForProfileGroup(userId, sensor, enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/proto/android/hardware/sensorprivacy.proto b/core/proto/android/hardware/sensorprivacy.proto
index 07e938ddfc5d..401e0038cada 100644
--- a/core/proto/android/hardware/sensorprivacy.proto
+++ b/core/proto/android/hardware/sensorprivacy.proto
@@ -25,11 +25,29 @@ import "frameworks/base/core/proto/android/privacy.proto";
message SensorPrivacyServiceDumpProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ // DEPRECATED
// Is global sensor privacy enabled
optional bool is_enabled = 1;
+ // DEPRECATED
// Per sensor privacy enabled
repeated SensorPrivacyIndividualEnabledSensorProto individual_enabled_sensor = 2;
+
+ // Per user settings for sensor privacy
+ repeated SensorPrivacyUserProto user = 3;
+}
+
+message SensorPrivacyUserProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // User id
+ optional int32 user_id = 1;
+
+ // Is global sensor privacy enabled
+ optional bool is_enabled = 2;
+
+ // Per sensor privacy enabled
+ repeated SensorPrivacyIndividualEnabledSensorProto individual_enabled_sensor = 3;
}
message SensorPrivacyIndividualEnabledSensorProto {
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 010213453940..2b705f5ffb3e 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -20,12 +20,14 @@ import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.UserHandle.USER_SYSTEM;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.CAMERA;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -49,12 +51,15 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.ShellCommand;
+import android.os.UserHandle;
import android.service.SensorPrivacyIndividualEnabledSensorProto;
import android.service.SensorPrivacyServiceDumpProto;
+import android.service.SensorPrivacyUserProto;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.IndentingPrintWriter;
import android.util.Log;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -63,9 +68,11 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.pm.UserManagerInternal;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -84,9 +91,19 @@ public final class SensorPrivacyService extends SystemService {
private static final String TAG = "SensorPrivacyService";
+ /** Version number indicating compatibility parsing the persisted file */
+ private static final int CURRENT_PERSISTENCE_VERSION = 1;
+ /** Version number indicating the persisted data needs upgraded to match new internal data
+ * structures and features */
+ private static final int CURRENT_VERSION = 1;
+
private static final String SENSOR_PRIVACY_XML_FILE = "sensor_privacy.xml";
private static final String XML_TAG_SENSOR_PRIVACY = "sensor-privacy";
+ private static final String XML_TAG_USER = "user";
private static final String XML_TAG_INDIVIDUAL_SENSOR_PRIVACY = "individual-sensor-privacy";
+ private static final String XML_ATTRIBUTE_ID = "id";
+ private static final String XML_ATTRIBUTE_PERSISTENCE_VERSION = "persistence-version";
+ private static final String XML_ATTRIBUTE_VERSION = "version";
private static final String XML_ATTRIBUTE_ENABLED = "enabled";
private static final String XML_ATTRIBUTE_SENSOR = "sensor";
@@ -96,10 +113,18 @@ public final class SensorPrivacyService extends SystemService {
private static final String EXTRA_SENSOR = SensorPrivacyService.class.getName()
+ ".extra.sensor";
+ // These are associated with fields that existed for older persisted versions of files
+ private static final int VER0_ENABLED = 0;
+ private static final int VER0_INDIVIDUAL_ENABLED = 1;
+ private static final int VER1_ENABLED = 0;
+ private static final int VER1_INDIVIDUAL_ENABLED = 1;
+
private final SensorPrivacyServiceImpl mSensorPrivacyServiceImpl;
+ private final UserManagerInternal mUserManagerInternal;
public SensorPrivacyService(Context context) {
super(context);
+ mUserManagerInternal = getLocalService(UserManagerInternal.class);
mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl(context);
}
@@ -117,8 +142,9 @@ public final class SensorPrivacyService extends SystemService {
@GuardedBy("mLock")
private final AtomicFile mAtomicFile;
@GuardedBy("mLock")
- private boolean mEnabled;
- private SparseBooleanArray mIndividualEnabled = new SparseBooleanArray();
+ private SparseBooleanArray mEnabled = new SparseBooleanArray();
+ @GuardedBy("mLock")
+ private SparseArray<SparseBooleanArray> mIndividualEnabled = new SparseArray<>();
SensorPrivacyServiceImpl(Context context) {
mContext = context;
@@ -127,7 +153,9 @@ public final class SensorPrivacyService extends SystemService {
SENSOR_PRIVACY_XML_FILE);
mAtomicFile = new AtomicFile(sensorPrivacyFile);
synchronized (mLock) {
- readPersistedSensorPrivacyStateLocked();
+ if (readPersistedSensorPrivacyStateLocked()) {
+ persistSensorPrivacyStateLocked();
+ }
}
int[] micAndCameraOps = new int[]{OP_RECORD_AUDIO, OP_CAMERA};
@@ -138,7 +166,8 @@ public final class SensorPrivacyService extends SystemService {
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- setIndividualSensorPrivacy(intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
+ setIndividualSensorPrivacy(intent.getIntExtra(Intent.EXTRA_USER_ID, -1),
+ intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
}
}, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY));
}
@@ -174,7 +203,8 @@ public final class SensorPrivacyService extends SystemService {
* @param sensor The sensor that is attempting to be used
*/
private void onSensorUseStarted(int uid, String packageName, int sensor) {
- if (!isIndividualSensorPrivacyEnabled(sensor)) {
+ int userId = UserHandle.getUserId(uid);
+ if (!isIndividualSensorPrivacyEnabled(userId, sensor)) {
return;
}
@@ -216,7 +246,8 @@ public final class SensorPrivacyService extends SystemService {
PendingIntent.getBroadcast(mContext, sensor,
new Intent(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY)
.setPackage(mContext.getPackageName())
- .putExtra(EXTRA_SENSOR, sensor),
+ .putExtra(EXTRA_SENSOR, sensor)
+ .putExtra(Intent.EXTRA_USER_ID, userId),
PendingIntent.FLAG_IMMUTABLE
| PendingIntent.FLAG_UPDATE_CURRENT))
.build())
@@ -229,18 +260,27 @@ public final class SensorPrivacyService extends SystemService {
*/
@Override
public void setSensorPrivacy(boolean enable) {
+ // Keep the state consistent between all users to make it a single global state
+ forAllUsers(userId -> setSensorPrivacy(userId, enable));
+ }
+
+ private void setSensorPrivacy(@UserIdInt int userId, boolean enable) {
enforceSensorPrivacyPermission();
synchronized (mLock) {
- mEnabled = enable;
+ mEnabled.put(userId, enable);
persistSensorPrivacyStateLocked();
}
mHandler.onSensorPrivacyChanged(enable);
}
- public void setIndividualSensorPrivacy(int sensor, boolean enable) {
+ @Override
+ public void setIndividualSensorPrivacy(@UserIdInt int userId, int sensor, boolean enable) {
enforceSensorPrivacyPermission();
synchronized (mLock) {
- mIndividualEnabled.put(sensor, enable);
+ SparseBooleanArray userIndividualEnabled = mIndividualEnabled.get(userId,
+ new SparseBooleanArray());
+ userIndividualEnabled.put(sensor, enable);
+ mIndividualEnabled.put(userId, userIndividualEnabled);
if (!enable) {
// Remove any notifications prompting the user to disable sensory privacy
@@ -249,11 +289,21 @@ public final class SensorPrivacyService extends SystemService {
notificationManager.cancel(sensor);
}
-
persistSensorPrivacyState();
}
}
+ @Override
+ public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId, int sensor,
+ boolean enable) {
+ int parentId = mUserManagerInternal.getProfileParentId(userId);
+ forAllUsers(userId2 -> {
+ if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
+ setIndividualSensorPrivacy(userId2, sensor, enable);
+ }
+ });
+ }
+
/**
* Enforces the caller contains the necessary permission to change the state of sensor
* privacy.
@@ -273,53 +323,179 @@ public final class SensorPrivacyService extends SystemService {
*/
@Override
public boolean isSensorPrivacyEnabled() {
+ return isSensorPrivacyEnabled(USER_SYSTEM);
+ }
+
+ private boolean isSensorPrivacyEnabled(@UserIdInt int userId) {
synchronized (mLock) {
- return mEnabled;
+ return mEnabled.get(userId, false);
}
}
@Override
- public boolean isIndividualSensorPrivacyEnabled(int sensor) {
+ public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
synchronized (mLock) {
- return mIndividualEnabled.get(sensor, false);
+ SparseBooleanArray states = mIndividualEnabled.get(userId);
+ if (states == null) {
+ return false;
+ }
+ return states.get(sensor, false);
}
}
/**
* Returns the state of sensor privacy from persistent storage.
*/
- private void readPersistedSensorPrivacyStateLocked() {
+ private boolean readPersistedSensorPrivacyStateLocked() {
// if the file does not exist then sensor privacy has not yet been enabled on
// the device.
- if (!mAtomicFile.exists()) {
- return;
- }
- try (FileInputStream inputStream = mAtomicFile.openRead()) {
- TypedXmlPullParser parser = Xml.resolvePullParser(inputStream);
- XmlUtils.beginDocument(parser, XML_TAG_SENSOR_PRIVACY);
- parser.next();
- mEnabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED, false);
-
- XmlUtils.nextElement(parser);
- while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
- String tagName = parser.getName();
- if (XML_TAG_INDIVIDUAL_SENSOR_PRIVACY.equals(tagName)) {
- int sensor = XmlUtils.readIntAttribute(parser, XML_ATTRIBUTE_SENSOR);
- boolean enabled = XmlUtils.readBooleanAttribute(parser,
- XML_ATTRIBUTE_ENABLED);
- mIndividualEnabled.put(sensor, enabled);
- XmlUtils.skipCurrentTag(parser);
- } else {
+
+ SparseArray<Object> map = new SparseArray<>();
+ int version = -1;
+
+ if (mAtomicFile.exists()) {
+ try (FileInputStream inputStream = mAtomicFile.openRead()) {
+ TypedXmlPullParser parser = Xml.resolvePullParser(inputStream);
+ XmlUtils.beginDocument(parser, XML_TAG_SENSOR_PRIVACY);
+ final int persistenceVersion = parser.getAttributeInt(null,
+ XML_ATTRIBUTE_PERSISTENCE_VERSION, 0);
+
+ // Use inline string literals for xml tags/attrs when parsing old versions since
+ // these should never be changed even with refactorings.
+ if (persistenceVersion == 0) {
+ boolean enabled = parser.getAttributeBoolean(null, "enabled", false);
+ SparseBooleanArray individualEnabled = new SparseBooleanArray();
+ version = 0;
+
XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ String tagName = parser.getName();
+ if ("individual-sensor-privacy".equals(tagName)) {
+ int sensor = XmlUtils.readIntAttribute(parser, "sensor");
+ boolean indEnabled = XmlUtils.readBooleanAttribute(parser,
+ "enabled");
+ individualEnabled.put(sensor, indEnabled);
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ XmlUtils.nextElement(parser);
+ }
+ }
+ map.put(VER0_ENABLED, enabled);
+ map.put(VER0_INDIVIDUAL_ENABLED, individualEnabled);
+ } else if (persistenceVersion == CURRENT_PERSISTENCE_VERSION) {
+ SparseBooleanArray enabled = new SparseBooleanArray();
+ SparseArray<SparseBooleanArray> individualEnabled = new SparseArray<>();
+ version = parser.getAttributeInt(null,
+ XML_ATTRIBUTE_VERSION, 1);
+
+ int currentUserId = -1;
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ XmlUtils.nextElement(parser);
+ String tagName = parser.getName();
+ if (XML_TAG_USER.equals(tagName)) {
+ currentUserId = parser.getAttributeInt(null, XML_ATTRIBUTE_ID);
+ boolean isEnabled = parser.getAttributeBoolean(null,
+ XML_ATTRIBUTE_ENABLED);
+ if (enabled.indexOfKey(currentUserId) >= 0) {
+ Log.e(TAG, "User listed multiple times in file.",
+ new RuntimeException());
+ mAtomicFile.delete();
+ version = -1;
+ break;
+ }
+
+ if (mUserManagerInternal.getUserInfo(currentUserId) == null) {
+ // User may no longer exist, skip this user
+ currentUserId = -1;
+ continue;
+ }
+
+ enabled.put(currentUserId, isEnabled);
+ }
+ if (XML_TAG_INDIVIDUAL_SENSOR_PRIVACY.equals(tagName)) {
+ if (mUserManagerInternal.getUserInfo(currentUserId) == null) {
+ // User may no longer exist or isn't set
+ continue;
+ }
+ int sensor = parser.getAttributeIndex(null, XML_ATTRIBUTE_SENSOR);
+ boolean isEnabled = parser.getAttributeBoolean(null,
+ XML_ATTRIBUTE_ENABLED);
+ SparseBooleanArray userIndividualEnabled = individualEnabled.get(
+ currentUserId, new SparseBooleanArray());
+
+ userIndividualEnabled.put(sensor, isEnabled);
+ individualEnabled.put(currentUserId, userIndividualEnabled);
+ }
+ }
+
+ map.put(VER1_ENABLED, enabled);
+ map.put(VER1_INDIVIDUAL_ENABLED, individualEnabled);
+ } else {
+ Log.e(TAG, "Unknown persistence version: " + persistenceVersion
+ + ". Deleting.",
+ new RuntimeException());
+ mAtomicFile.delete();
+ version = -1;
}
+
+ } catch (IOException | XmlPullParserException e) {
+ Log.e(TAG, "Caught an exception reading the state from storage: ", e);
+ // Delete the file to prevent the same error on subsequent calls and assume
+ // sensor privacy is not enabled.
+ mAtomicFile.delete();
+ version = -1;
}
+ }
+
+ return upgradeAndInit(version, map);
+ }
- } catch (IOException | XmlPullParserException e) {
- Log.e(TAG, "Caught an exception reading the state from storage: ", e);
- // Delete the file to prevent the same error on subsequent calls and assume sensor
- // privacy is not enabled.
- mAtomicFile.delete();
+ private boolean upgradeAndInit(int version, SparseArray map) {
+ if (version == -1) {
+ // New file, default state for current version goes here.
+ mEnabled = new SparseBooleanArray();
+ mIndividualEnabled = new SparseArray<>();
+ forAllUsers(userId -> mEnabled.put(userId, false));
+ forAllUsers(userId -> mIndividualEnabled.put(userId, new SparseBooleanArray()));
+ return true;
+ }
+ boolean upgraded = false;
+ final int[] users = getLocalService(UserManagerInternal.class).getUserIds();
+ if (version == 0) {
+ final boolean enabled = (boolean) map.get(VER0_ENABLED);
+ final SparseBooleanArray individualEnabled =
+ (SparseBooleanArray) map.get(VER0_INDIVIDUAL_ENABLED);
+
+ final SparseBooleanArray perUserEnabled = new SparseBooleanArray();
+ final SparseArray<SparseBooleanArray> perUserIndividualEnabled =
+ new SparseArray<>();
+
+ // Copy global state to each user
+ for (int i = 0; i < users.length; i++) {
+ int user = users[i];
+ perUserEnabled.put(user, enabled);
+ SparseBooleanArray userIndividualSensorEnabled = new SparseBooleanArray();
+ perUserIndividualEnabled.put(user, userIndividualSensorEnabled);
+ for (int j = 0; j < individualEnabled.size(); j++) {
+ final int sensor = individualEnabled.keyAt(j);
+ final boolean isSensorEnabled = individualEnabled.valueAt(j);
+ userIndividualSensorEnabled.put(sensor, isSensorEnabled);
+ }
+ }
+
+ map.clear();
+ map.put(VER1_ENABLED, perUserEnabled);
+ map.put(VER1_INDIVIDUAL_ENABLED, perUserIndividualEnabled);
+
+ version = 1;
+ upgraded = true;
+ }
+ if (version == CURRENT_VERSION) {
+ mEnabled = (SparseBooleanArray) map.get(VER1_ENABLED);
+ mIndividualEnabled =
+ (SparseArray<SparseBooleanArray>) map.get(VER1_INDIVIDUAL_ENABLED);
}
+ return upgraded;
}
/**
@@ -338,16 +514,29 @@ public final class SensorPrivacyService extends SystemService {
TypedXmlSerializer serializer = Xml.resolveSerializer(outputStream);
serializer.startDocument(null, true);
serializer.startTag(null, XML_TAG_SENSOR_PRIVACY);
- serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, mEnabled);
- int numIndividual = mIndividualEnabled.size();
- for (int i = 0; i < numIndividual; i++) {
- serializer.startTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY);
- int sensor = mIndividualEnabled.keyAt(i);
- boolean enabled = mIndividualEnabled.valueAt(i);
- serializer.attributeInt(null, XML_ATTRIBUTE_SENSOR, sensor);
- serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enabled);
- serializer.endTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY);
- }
+ serializer.attributeInt(
+ null, XML_ATTRIBUTE_PERSISTENCE_VERSION, CURRENT_PERSISTENCE_VERSION);
+ serializer.attributeInt(null, XML_ATTRIBUTE_VERSION, CURRENT_VERSION);
+ forAllUsers(userId -> {
+ serializer.startTag(null, XML_TAG_USER);
+ serializer.attributeInt(null, XML_ATTRIBUTE_ID, userId);
+ serializer.attributeBoolean(
+ null, XML_ATTRIBUTE_ENABLED, isSensorPrivacyEnabled(userId));
+
+ SparseBooleanArray individualEnabled =
+ mIndividualEnabled.get(userId, new SparseBooleanArray());
+ int numIndividual = individualEnabled.size();
+ for (int i = 0; i < numIndividual; i++) {
+ serializer.startTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY);
+ int sensor = individualEnabled.keyAt(i);
+ boolean enabled = individualEnabled.valueAt(i);
+ serializer.attributeInt(null, XML_ATTRIBUTE_SENSOR, sensor);
+ serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enabled);
+ serializer.endTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY);
+ }
+ serializer.endTag(null, XML_TAG_USER);
+
+ });
serializer.endTag(null, XML_TAG_SENSOR_PRIVACY);
serializer.endDocument();
mAtomicFile.finishWrite(outputStream);
@@ -422,22 +611,32 @@ public final class SensorPrivacyService extends SystemService {
*/
private void dump(@NonNull DualDumpOutputStream dumpStream) {
synchronized (mLock) {
- dumpStream.write("is_enabled", SensorPrivacyServiceDumpProto.IS_ENABLED, mEnabled);
- int numIndividualEnabled = mIndividualEnabled.size();
- for (int i = 0; i < numIndividualEnabled; i++) {
- long token = dumpStream.start("individual_enabled_sensor",
- SensorPrivacyServiceDumpProto.INDIVIDUAL_ENABLED_SENSOR);
-
- dumpStream.write("sensor",
- SensorPrivacyIndividualEnabledSensorProto.SENSOR,
- mIndividualEnabled.keyAt(i));
- dumpStream.write("is_enabled",
- SensorPrivacyIndividualEnabledSensorProto.IS_ENABLED,
- mIndividualEnabled.valueAt(i));
-
- dumpStream.end(token);
- }
+ forAllUsers(userId -> {
+ long userToken = dumpStream.start("users", SensorPrivacyServiceDumpProto.USER);
+ dumpStream.write("user_id", SensorPrivacyUserProto.USER_ID, userId);
+ dumpStream.write("is_enabled", SensorPrivacyUserProto.IS_ENABLED,
+ mEnabled.get(userId, false));
+
+ SparseBooleanArray individualEnabled = mIndividualEnabled.get(userId);
+ if (individualEnabled != null) {
+ int numIndividualEnabled = individualEnabled.size();
+ for (int i = 0; i < numIndividualEnabled; i++) {
+ long individualToken = dumpStream.start("individual_enabled_sensor",
+ SensorPrivacyUserProto.INDIVIDUAL_ENABLED_SENSOR);
+
+ dumpStream.write("sensor",
+ SensorPrivacyIndividualEnabledSensorProto.SENSOR,
+ individualEnabled.keyAt(i));
+ dumpStream.write("is_enabled",
+ SensorPrivacyIndividualEnabledSensorProto.IS_ENABLED,
+ individualEnabled.valueAt(i));
+
+ dumpStream.end(individualToken);
+ }
+ }
+ dumpStream.end(userToken);
+ });
}
dumpStream.flush();
@@ -477,30 +676,32 @@ public final class SensorPrivacyService extends SystemService {
return handleDefaultCommands(cmd);
}
+ int userId = Integer.parseInt(getNextArgRequired());
+
final PrintWriter pw = getOutPrintWriter();
switch (cmd) {
case "enable" : {
- int sensor = sensorStrToId(getNextArg());
+ int sensor = sensorStrToId(getNextArgRequired());
if (sensor == UNKNOWN) {
pw.println("Invalid sensor");
return -1;
}
- setIndividualSensorPrivacy(sensor, true);
+ setIndividualSensorPrivacy(userId, sensor, true);
}
break;
case "disable" : {
- int sensor = sensorStrToId(getNextArg());
+ int sensor = sensorStrToId(getNextArgRequired());
if (sensor == UNKNOWN) {
pw.println("Invalid sensor");
return -1;
}
- setIndividualSensorPrivacy(sensor, false);
+ setIndividualSensorPrivacy(userId, sensor, false);
}
break;
case "reset": {
- int sensor = sensorStrToId(getNextArg());
+ int sensor = sensorStrToId(getNextArgRequired());
if (sensor == UNKNOWN) {
pw.println("Invalid sensor");
return -1;
@@ -509,7 +710,11 @@ public final class SensorPrivacyService extends SystemService {
enforceSensorPrivacyPermission();
synchronized (mLock) {
- mIndividualEnabled.delete(sensor);
+ SparseBooleanArray individualEnabled =
+ mIndividualEnabled.get(userId);
+ if (individualEnabled != null) {
+ individualEnabled.delete(sensor);
+ }
persistSensorPrivacyState();
}
}
@@ -530,13 +735,13 @@ public final class SensorPrivacyService extends SystemService {
pw.println(" help");
pw.println(" Print this help text.");
pw.println("");
- pw.println(" enable SENSOR");
+ pw.println(" enable USER_ID SENSOR");
pw.println(" Enable privacy for a certain sensor.");
pw.println("");
- pw.println(" disable SENSOR");
+ pw.println(" disable USER_ID SENSOR");
pw.println(" Disable privacy for a certain sensor.");
pw.println("");
- pw.println(" reset SENSOR");
+ pw.println(" reset USER_ID SENSOR");
pw.println(" Reset privacy state for a certain sensor.");
pw.println("");
}
@@ -628,4 +833,11 @@ public final class SensorPrivacyService extends SystemService {
}
}
}
+
+ private void forAllUsers(FunctionalUtils.ThrowingConsumer<Integer> c) {
+ int[] userIds = mUserManagerInternal.getUserIds();
+ for (int i = 0; i < userIds.length; i++) {
+ c.accept(userIds[i]);
+ }
+ }
}