diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java index 4f3a38b6cdcad..53ff8ff768de3 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -94,6 +94,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.ShellCommand; +import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -147,6 +148,8 @@ import java.util.Objects; public final class SensorPrivacyService extends SystemService { private static final String TAG = SensorPrivacyService.class.getSimpleName(); + private static final boolean DEBUG = false; + private static final boolean DEBUG_LOGGING = false; /** Version number indicating compatibility parsing the persisted file */ private static final int CURRENT_PERSISTENCE_VERSION = 1; @@ -162,6 +165,7 @@ public final class SensorPrivacyService extends SystemService { 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_LAST_CHANGE = "last-change"; private static final String XML_ATTRIBUTE_SENSOR = "sensor"; private static final String SENSOR_PRIVACY_CHANNEL_ID = Context.SENSOR_PRIVACY_SERVICE; @@ -248,7 +252,7 @@ public final class SensorPrivacyService extends SystemService { @GuardedBy("mLock") private SparseBooleanArray mEnabled = new SparseBooleanArray(); @GuardedBy("mLock") - private SparseArray mIndividualEnabled = new SparseArray<>(); + private SparseArray> mIndividualEnabled = new SparseArray<>(); /** * Packages for which not to show sensor use reminders. @@ -262,6 +266,34 @@ public final class SensorPrivacyService extends SystemService { private final ArrayMap> mQueuedSensorUseReminderDialogs = new ArrayMap<>(); + private class SensorState { + private boolean mEnabled; + private long mLastChange; + + SensorState(boolean enabled) { + mEnabled = enabled; + mLastChange = getCurrentTimeMillis(); + } + + SensorState(boolean enabled, long lastChange) { + mEnabled = enabled; + if (lastChange < 0) { + mLastChange = getCurrentTimeMillis(); + } else { + mLastChange = lastChange; + } + } + + boolean setEnabled(boolean enabled) { + if (mEnabled != enabled) { + mEnabled = enabled; + mLastChange = getCurrentTimeMillis(); + return true; + } + return false; + } + } + private class SensorUseReminderDialogInfo { private int mTaskId; private UserHandle mUser; @@ -326,11 +358,11 @@ public final class SensorPrivacyService extends SystemService { // Reset sensor privacy when restriction is added if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE) && newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) { - setIndividualSensorPrivacyUnchecked(userId, CAMERA, false); + setIndividualSensorPrivacyUnchecked(userId, OTHER, CAMERA, false); } if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE) && newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) { - setIndividualSensorPrivacyUnchecked(userId, MICROPHONE, false); + setIndividualSensorPrivacyUnchecked(userId, OTHER, MICROPHONE, false); } } @@ -671,20 +703,33 @@ public final class SensorPrivacyService extends SystemService { return; } - if (userId == mUserManagerInternal.getProfileParentId(userId)) { - logSensorPrivacyToggle(source, sensor, enable); - } - - setIndividualSensorPrivacyUnchecked(userId, sensor, enable); + setIndividualSensorPrivacyUnchecked(userId, source, sensor, enable); } - private void setIndividualSensorPrivacyUnchecked(int userId, int sensor, boolean enable) { + private void setIndividualSensorPrivacyUnchecked(int userId, int source, int sensor, + boolean enable) { synchronized (mLock) { - SparseBooleanArray userIndividualEnabled = mIndividualEnabled.get(userId, - new SparseBooleanArray()); - userIndividualEnabled.put(sensor, enable); + SparseArray userIndividualEnabled = mIndividualEnabled.get(userId, + new SparseArray<>()); + SensorState sensorState = userIndividualEnabled.get(sensor); + long lastChange; + if (sensorState != null) { + lastChange = sensorState.mLastChange; + if (!sensorState.setEnabled(enable)) { + // State not changing + return; + } + } else { + sensorState = new SensorState(enable); + lastChange = sensorState.mLastChange; + userIndividualEnabled.put(sensor, sensorState); + } mIndividualEnabled.put(userId, userIndividualEnabled); + if (userId == mUserManagerInternal.getProfileParentId(userId)) { + logSensorPrivacyToggle(source, sensor, sensorState.mEnabled, lastChange); + } + if (!enable) { long token = Binder.clearCallingIdentity(); try { @@ -728,12 +773,12 @@ public final class SensorPrivacyService extends SystemService { return true; } - private void logSensorPrivacyToggle(int source, int sensor, boolean enable) { - long logMins = 0L; - //(TODO:pyuli) : Add timestamp after persistent storage for timestamp is done. + private void logSensorPrivacyToggle(int source, int sensor, boolean enabled, + long lastChange) { + long logMins = Math.max(0, (getCurrentTimeMillis() - lastChange) / (1000 * 60)); int logAction = -1; - if (enable) { + if (enabled) { logAction = PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_OFF; } else { logAction = PRIVACY_SENSOR_TOGGLE_INTERACTION__ACTION__TOGGLE_ON; @@ -766,6 +811,11 @@ public final class SensorPrivacyService extends SystemService { logSource = PRIVACY_SENSOR_TOGGLE_INTERACTION__SOURCE__SOURCE_UNKNOWN; } + if (DEBUG || DEBUG_LOGGING) { + Log.d(TAG, "Logging sensor toggle interaction:" + " logSensor=" + logSensor + + " logAction=" + logAction + " logSource=" + logSource + " logMins=" + + logMins); + } write(PRIVACY_SENSOR_TOGGLE_INTERACTION, logSensor, logAction, logSource, logMins); } @@ -828,11 +878,15 @@ public final class SensorPrivacyService extends SystemService { public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) { enforceObserveSensorPrivacyPermission(); synchronized (mLock) { - SparseBooleanArray states = mIndividualEnabled.get(userId); + SparseArray states = mIndividualEnabled.get(userId); if (states == null) { return false; } - return states.get(sensor, false); + SensorState state = states.get(sensor); + if (state == null) { + return false; + } + return state.mEnabled; } } @@ -857,7 +911,7 @@ public final class SensorPrivacyService extends SystemService { // these should never be changed even with refactorings. if (persistenceVersion == 0) { boolean enabled = parser.getAttributeBoolean(null, "enabled", false); - SparseBooleanArray individualEnabled = new SparseBooleanArray(); + SparseArray individualEnabled = new SparseArray<>(); version = 0; XmlUtils.nextElement(parser); @@ -867,7 +921,7 @@ public final class SensorPrivacyService extends SystemService { int sensor = XmlUtils.readIntAttribute(parser, "sensor"); boolean indEnabled = XmlUtils.readBooleanAttribute(parser, "enabled"); - individualEnabled.put(sensor, indEnabled); + individualEnabled.put(sensor, new SensorState(indEnabled)); XmlUtils.skipCurrentTag(parser); } else { XmlUtils.nextElement(parser); @@ -877,7 +931,8 @@ public final class SensorPrivacyService extends SystemService { map.put(VER0_INDIVIDUAL_ENABLED, individualEnabled); } else if (persistenceVersion == CURRENT_PERSISTENCE_VERSION) { SparseBooleanArray enabled = new SparseBooleanArray(); - SparseArray individualEnabled = new SparseArray<>(); + SparseArray> individualEnabled = + new SparseArray<>(); version = parser.getAttributeInt(null, XML_ATTRIBUTE_VERSION, 1); @@ -913,10 +968,13 @@ public final class SensorPrivacyService extends SystemService { int sensor = parser.getAttributeInt(null, XML_ATTRIBUTE_SENSOR); boolean isEnabled = parser.getAttributeBoolean(null, XML_ATTRIBUTE_ENABLED); - SparseBooleanArray userIndividualEnabled = individualEnabled.get( - currentUserId, new SparseBooleanArray()); + long lastChange = parser + .getAttributeLong(null, XML_ATTRIBUTE_LAST_CHANGE, -1); + SparseArray userIndividualEnabled = + individualEnabled.get(currentUserId, new SparseArray<>()); - userIndividualEnabled.put(sensor, isEnabled); + userIndividualEnabled + .put(sensor, new SensorState(isEnabled, lastChange)); individualEnabled.put(currentUserId, userIndividualEnabled); } } @@ -949,7 +1007,7 @@ public final class SensorPrivacyService extends SystemService { mEnabled = new SparseBooleanArray(); mIndividualEnabled = new SparseArray<>(); forAllUsers(userId -> mEnabled.put(userId, false)); - forAllUsers(userId -> mIndividualEnabled.put(userId, new SparseBooleanArray())); + forAllUsers(userId -> mIndividualEnabled.put(userId, new SparseArray<>())); return true; } boolean upgraded = false; @@ -986,7 +1044,7 @@ public final class SensorPrivacyService extends SystemService { if (version == CURRENT_VERSION) { mEnabled = (SparseBooleanArray) map.get(VER1_ENABLED); mIndividualEnabled = - (SparseArray) map.get(VER1_INDIVIDUAL_ENABLED); + (SparseArray>) map.get(VER1_INDIVIDUAL_ENABLED); } return upgraded; } @@ -1016,15 +1074,18 @@ public final class SensorPrivacyService extends SystemService { serializer.attributeBoolean( null, XML_ATTRIBUTE_ENABLED, isSensorPrivacyEnabled(userId)); - SparseBooleanArray individualEnabled = - mIndividualEnabled.get(userId, new SparseBooleanArray()); + SparseArray individualEnabled = + mIndividualEnabled.get(userId, new SparseArray<>()); 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); + SensorState sensorState = individualEnabled.valueAt(i); + boolean enabled = sensorState.mEnabled; + long lastChange = sensorState.mLastChange; serializer.attributeInt(null, XML_ATTRIBUTE_SENSOR, sensor); serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enabled); + serializer.attributeLong(null, XML_ATTRIBUTE_LAST_CHANGE, lastChange); serializer.endTag(null, XML_TAG_INDIVIDUAL_SENSOR_PRIVACY); } serializer.endTag(null, XML_TAG_USER); @@ -1229,7 +1290,7 @@ public final class SensorPrivacyService extends SystemService { dumpStream.write("is_enabled", SensorPrivacyUserProto.IS_ENABLED, mEnabled.get(userId, false)); - SparseBooleanArray individualEnabled = mIndividualEnabled.get(userId); + SparseArray individualEnabled = mIndividualEnabled.get(userId); if (individualEnabled != null) { int numIndividualEnabled = individualEnabled.size(); for (int i = 0; i < numIndividualEnabled; i++) { @@ -1241,7 +1302,8 @@ public final class SensorPrivacyService extends SystemService { individualEnabled.keyAt(i)); dumpStream.write("is_enabled", SensorPrivacyIndividualEnabledSensorProto.IS_ENABLED, - individualEnabled.valueAt(i)); + individualEnabled.valueAt(i).mEnabled); + // TODO dump last change dumpStream.end(individualToken); } @@ -1321,7 +1383,7 @@ public final class SensorPrivacyService extends SystemService { enforceManageSensorPrivacyPermission(); synchronized (mLock) { - SparseBooleanArray individualEnabled = + SparseArray individualEnabled = mIndividualEnabled.get(userId); if (individualEnabled != null) { individualEnabled.delete(sensor); @@ -1682,7 +1744,7 @@ public final class SensorPrivacyService extends SystemService { if (mSensorPrivacyServiceImpl .isIndividualSensorPrivacyEnabled(getCurrentUser(), MICROPHONE)) { mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked( - getCurrentUser(), MICROPHONE, false); + getCurrentUser(), OTHER, MICROPHONE, false); mMicUnmutedForEmergencyCall = true; } else { mMicUnmutedForEmergencyCall = false; @@ -1697,11 +1759,19 @@ public final class SensorPrivacyService extends SystemService { mIsInEmergencyCall = false; if (mMicUnmutedForEmergencyCall) { mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked( - getCurrentUser(), MICROPHONE, true); + getCurrentUser(), OTHER, MICROPHONE, true); mMicUnmutedForEmergencyCall = false; } } } } } + + private static long getCurrentTimeMillis() { + try { + return SystemClock.currentNetworkTimeMillis(); + } catch (Exception e) { + return System.currentTimeMillis(); + } + } }