Loading core/java/android/hardware/SensorPrivacyManager.java +66 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.service.SensorPrivacyIndividualEnabledSensorProto; import android.service.SensorPrivacySensorProto; import android.service.SensorPrivacyToggleSourceProto; import android.util.ArrayMap; import android.util.Log; Loading Loading @@ -75,7 +76,7 @@ public final class SensorPrivacyManager { private final SparseArray<Boolean> mToggleSupportCache = new SparseArray<>(); /** * Individual sensors not listed in {@link Sensors} * Sensor constants which are used in {@link SensorPrivacyManager} */ public static class Sensors { Loading @@ -84,12 +85,12 @@ public final class SensorPrivacyManager { /** * Constant for the microphone */ public static final int MICROPHONE = SensorPrivacyIndividualEnabledSensorProto.MICROPHONE; public static final int MICROPHONE = SensorPrivacySensorProto.MICROPHONE; /** * Constant for the camera */ public static final int CAMERA = SensorPrivacyIndividualEnabledSensorProto.CAMERA; public static final int CAMERA = SensorPrivacySensorProto.CAMERA; /** * Individual sensors not listed in {@link Sensors} Loading Loading @@ -160,6 +161,68 @@ public final class SensorPrivacyManager { } /** * Types of toggles which can exist for sensor privacy * @hide */ public static class ToggleTypes { private ToggleTypes() {} /** * Constant for software toggle. */ public static final int SOFTWARE = SensorPrivacyIndividualEnabledSensorProto.SOFTWARE; /** * Constant for hardware toggle. */ public static final int HARDWARE = SensorPrivacyIndividualEnabledSensorProto.HARDWARE; /** * Types of toggles which can exist for sensor privacy * * @hide */ @IntDef(value = { SOFTWARE, HARDWARE }) @Retention(RetentionPolicy.SOURCE) public @interface ToggleType {} } /** * Types of state which can exist for the sensor privacy toggle * @hide */ public static class StateTypes { private StateTypes() {} /** * Constant indicating privacy is enabled. */ public static final int ENABLED = SensorPrivacyIndividualEnabledSensorProto.ENABLED; /** * Constant indicating privacy is disabled. */ public static final int DISABLED = SensorPrivacyIndividualEnabledSensorProto.DISABLED; /** * Types of state which can exist for a sensor privacy toggle * * @hide */ @IntDef(value = { ENABLED, DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface StateType {} } /** * A class implementing this interface can register with the {@link * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy Loading Loading @@ -507,7 +570,6 @@ public final class SensorPrivacyManager { /** * Don't show dialogs to turn off sensor privacy for this package. * * @param packageName Package name not to show dialogs for * @param suppress Whether to suppress or re-enable. * * @hide Loading @@ -521,7 +583,6 @@ public final class SensorPrivacyManager { /** * Don't show dialogs to turn off sensor privacy for this package. * * @param packageName Package name not to show dialogs for * @param suppress Whether to suppress or re-enable. * @param userId the user's id * Loading core/proto/android/hardware/sensorprivacy.proto +51 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,13 @@ option java_outer_classname = "SensorPrivacyServiceProto"; import "frameworks/base/core/proto/android/privacy.proto"; message AllSensorPrivacyServiceDumpProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; // Is global sensor privacy enabled optional bool is_enabled = 1; } message SensorPrivacyServiceDumpProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; Loading @@ -35,6 +42,9 @@ message SensorPrivacyServiceDumpProto { // Per user settings for sensor privacy repeated SensorPrivacyUserProto user = 3; // Implementation optional string storage_implementation = 4; } message SensorPrivacyUserProto { Loading @@ -43,16 +53,47 @@ message SensorPrivacyUserProto { // User id optional int32 user_id = 1; // DEPRECATED // Is global sensor privacy enabled optional bool is_enabled = 2; // Per sensor privacy enabled // DEPRECATED repeated SensorPrivacyIndividualEnabledSensorProto individual_enabled_sensor = 3; // Per toggle type sensor privacy repeated SensorPrivacySensorProto sensors = 4; } message SensorPrivacySensorProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; enum Sensor { UNKNOWN = 0; MICROPHONE = 1; CAMERA = 2; } optional int32 sensor = 1; repeated SensorPrivacyIndividualEnabledSensorProto toggles = 2; } message SensorPrivacyIndividualEnabledSensorProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; enum ToggleType { SOFTWARE = 1; HARDWARE = 2; } enum StateType { ENABLED = 1; DISABLED = 2; } // DEPRECATED enum Sensor { UNKNOWN = 0; Loading @@ -63,8 +104,17 @@ message SensorPrivacyIndividualEnabledSensorProto { // Sensor for which privacy might be enabled optional Sensor sensor = 1; // If sensor privacy is enabled for this sensor // DEPRECATED optional bool is_enabled = 2; // Timestamp of the last time the sensor was changed optional int64 last_change = 3; // The toggle type for this state optional ToggleType toggle_type = 4; // If sensor privacy state for this sensor optional StateType state_type = 5; } message SensorPrivacyToggleSourceProto { Loading services/core/java/com/android/server/OWNERS +0 −3 Original line number Diff line number Diff line Loading @@ -10,9 +10,6 @@ per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com # Userspace reboot per-file UserspaceRebootLogger.java = ioffe@google.com, dvander@google.com # Sensor Privacy per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS # ServiceWatcher per-file ServiceWatcher.java = sooniln@google.com Loading services/core/java/com/android/server/sensorprivacy/AllSensorStateController.java 0 → 100644 +155 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.sensorprivacy; import android.annotation.NonNull; import android.os.Environment; import android.os.Handler; import android.util.AtomicFile; import android.util.Log; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.Xml; 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.IoThread; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Objects; class AllSensorStateController { private static final String LOG_TAG = AllSensorStateController.class.getSimpleName(); private static final String SENSOR_PRIVACY_XML_FILE = "sensor_privacy.xml"; private static final String XML_TAG_SENSOR_PRIVACY = "all-sensor-privacy"; private static final String XML_TAG_SENSOR_PRIVACY_LEGACY = "sensor-privacy"; private static final String XML_ATTRIBUTE_ENABLED = "enabled"; private static AllSensorStateController sInstance; private final AtomicFile mAtomicFile = new AtomicFile(new File(Environment.getDataSystemDirectory(), SENSOR_PRIVACY_XML_FILE)); private boolean mEnabled; private SensorPrivacyStateController.AllSensorPrivacyListener mListener; private Handler mListenerHandler; static AllSensorStateController getInstance() { if (sInstance == null) { sInstance = new AllSensorStateController(); } return sInstance; } private AllSensorStateController() { if (!mAtomicFile.exists()) { return; } try (FileInputStream inputStream = mAtomicFile.openRead()) { TypedXmlPullParser parser = Xml.resolvePullParser(inputStream); while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { String tagName = parser.getName(); if (XML_TAG_SENSOR_PRIVACY.equals(tagName)) { mEnabled |= XmlUtils .readBooleanAttribute(parser, XML_ATTRIBUTE_ENABLED, false); break; } if (XML_TAG_SENSOR_PRIVACY_LEGACY.equals(tagName)) { mEnabled |= XmlUtils .readBooleanAttribute(parser, XML_ATTRIBUTE_ENABLED, false); } if ("user".equals(tagName)) { // Migrate from mic/cam toggles format int user = XmlUtils.readIntAttribute(parser, "id", -1); if (user == 0) { mEnabled |= XmlUtils.readBooleanAttribute(parser, XML_ATTRIBUTE_ENABLED); } } XmlUtils.nextElement(parser); } } catch (IOException | XmlPullParserException e) { Log.e(LOG_TAG, "Caught an exception reading the state from storage: ", e); mEnabled = false; } } public boolean getAllSensorStateLocked() { return mEnabled; } public void setAllSensorStateLocked(boolean enabled) { if (mEnabled != enabled) { mEnabled = enabled; if (mListener != null && mListenerHandler != null) { mListenerHandler.sendMessage( PooledLambda.obtainMessage(mListener::onAllSensorPrivacyChanged, enabled)); } } } void setAllSensorPrivacyListenerLocked(Handler handler, SensorPrivacyStateController.AllSensorPrivacyListener listener) { Objects.requireNonNull(handler); Objects.requireNonNull(listener); if (mListener != null) { throw new IllegalStateException("Listener is already set"); } mListener = listener; mListenerHandler = handler; } public void schedulePersistLocked() { IoThread.getHandler().sendMessage(PooledLambda.obtainMessage(this::persist, mEnabled)); } private void persist(boolean enabled) { FileOutputStream outputStream = null; try { outputStream = mAtomicFile.startWrite(); TypedXmlSerializer serializer = Xml.resolveSerializer(outputStream); serializer.startDocument(null, true); serializer.startTag(null, XML_TAG_SENSOR_PRIVACY); serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enabled); serializer.endTag(null, XML_TAG_SENSOR_PRIVACY); serializer.endDocument(); mAtomicFile.finishWrite(outputStream); } catch (IOException e) { Log.e(LOG_TAG, "Caught an exception persisting the sensor privacy state: ", e); mAtomicFile.failWrite(outputStream); } } void resetForTesting() { mListener = null; mListenerHandler = null; mEnabled = false; } void dumpLocked(@NonNull DualDumpOutputStream dumpStream) { // TODO stub } } services/core/java/com/android/server/sensorprivacy/OWNERS 0 → 100644 +1 −0 Original line number Diff line number Diff line include platform/frameworks/native:/libs/sensorprivacy/OWNERS No newline at end of file Loading
core/java/android/hardware/SensorPrivacyManager.java +66 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.service.SensorPrivacyIndividualEnabledSensorProto; import android.service.SensorPrivacySensorProto; import android.service.SensorPrivacyToggleSourceProto; import android.util.ArrayMap; import android.util.Log; Loading Loading @@ -75,7 +76,7 @@ public final class SensorPrivacyManager { private final SparseArray<Boolean> mToggleSupportCache = new SparseArray<>(); /** * Individual sensors not listed in {@link Sensors} * Sensor constants which are used in {@link SensorPrivacyManager} */ public static class Sensors { Loading @@ -84,12 +85,12 @@ public final class SensorPrivacyManager { /** * Constant for the microphone */ public static final int MICROPHONE = SensorPrivacyIndividualEnabledSensorProto.MICROPHONE; public static final int MICROPHONE = SensorPrivacySensorProto.MICROPHONE; /** * Constant for the camera */ public static final int CAMERA = SensorPrivacyIndividualEnabledSensorProto.CAMERA; public static final int CAMERA = SensorPrivacySensorProto.CAMERA; /** * Individual sensors not listed in {@link Sensors} Loading Loading @@ -160,6 +161,68 @@ public final class SensorPrivacyManager { } /** * Types of toggles which can exist for sensor privacy * @hide */ public static class ToggleTypes { private ToggleTypes() {} /** * Constant for software toggle. */ public static final int SOFTWARE = SensorPrivacyIndividualEnabledSensorProto.SOFTWARE; /** * Constant for hardware toggle. */ public static final int HARDWARE = SensorPrivacyIndividualEnabledSensorProto.HARDWARE; /** * Types of toggles which can exist for sensor privacy * * @hide */ @IntDef(value = { SOFTWARE, HARDWARE }) @Retention(RetentionPolicy.SOURCE) public @interface ToggleType {} } /** * Types of state which can exist for the sensor privacy toggle * @hide */ public static class StateTypes { private StateTypes() {} /** * Constant indicating privacy is enabled. */ public static final int ENABLED = SensorPrivacyIndividualEnabledSensorProto.ENABLED; /** * Constant indicating privacy is disabled. */ public static final int DISABLED = SensorPrivacyIndividualEnabledSensorProto.DISABLED; /** * Types of state which can exist for a sensor privacy toggle * * @hide */ @IntDef(value = { ENABLED, DISABLED }) @Retention(RetentionPolicy.SOURCE) public @interface StateType {} } /** * A class implementing this interface can register with the {@link * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy Loading Loading @@ -507,7 +570,6 @@ public final class SensorPrivacyManager { /** * Don't show dialogs to turn off sensor privacy for this package. * * @param packageName Package name not to show dialogs for * @param suppress Whether to suppress or re-enable. * * @hide Loading @@ -521,7 +583,6 @@ public final class SensorPrivacyManager { /** * Don't show dialogs to turn off sensor privacy for this package. * * @param packageName Package name not to show dialogs for * @param suppress Whether to suppress or re-enable. * @param userId the user's id * Loading
core/proto/android/hardware/sensorprivacy.proto +51 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,13 @@ option java_outer_classname = "SensorPrivacyServiceProto"; import "frameworks/base/core/proto/android/privacy.proto"; message AllSensorPrivacyServiceDumpProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; // Is global sensor privacy enabled optional bool is_enabled = 1; } message SensorPrivacyServiceDumpProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; Loading @@ -35,6 +42,9 @@ message SensorPrivacyServiceDumpProto { // Per user settings for sensor privacy repeated SensorPrivacyUserProto user = 3; // Implementation optional string storage_implementation = 4; } message SensorPrivacyUserProto { Loading @@ -43,16 +53,47 @@ message SensorPrivacyUserProto { // User id optional int32 user_id = 1; // DEPRECATED // Is global sensor privacy enabled optional bool is_enabled = 2; // Per sensor privacy enabled // DEPRECATED repeated SensorPrivacyIndividualEnabledSensorProto individual_enabled_sensor = 3; // Per toggle type sensor privacy repeated SensorPrivacySensorProto sensors = 4; } message SensorPrivacySensorProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; enum Sensor { UNKNOWN = 0; MICROPHONE = 1; CAMERA = 2; } optional int32 sensor = 1; repeated SensorPrivacyIndividualEnabledSensorProto toggles = 2; } message SensorPrivacyIndividualEnabledSensorProto { option (android.msg_privacy).dest = DEST_AUTOMATIC; enum ToggleType { SOFTWARE = 1; HARDWARE = 2; } enum StateType { ENABLED = 1; DISABLED = 2; } // DEPRECATED enum Sensor { UNKNOWN = 0; Loading @@ -63,8 +104,17 @@ message SensorPrivacyIndividualEnabledSensorProto { // Sensor for which privacy might be enabled optional Sensor sensor = 1; // If sensor privacy is enabled for this sensor // DEPRECATED optional bool is_enabled = 2; // Timestamp of the last time the sensor was changed optional int64 last_change = 3; // The toggle type for this state optional ToggleType toggle_type = 4; // If sensor privacy state for this sensor optional StateType state_type = 5; } message SensorPrivacyToggleSourceProto { Loading
services/core/java/com/android/server/OWNERS +0 −3 Original line number Diff line number Diff line Loading @@ -10,9 +10,6 @@ per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com # Userspace reboot per-file UserspaceRebootLogger.java = ioffe@google.com, dvander@google.com # Sensor Privacy per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS # ServiceWatcher per-file ServiceWatcher.java = sooniln@google.com Loading
services/core/java/com/android/server/sensorprivacy/AllSensorStateController.java 0 → 100644 +155 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.sensorprivacy; import android.annotation.NonNull; import android.os.Environment; import android.os.Handler; import android.util.AtomicFile; import android.util.Log; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.Xml; 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.IoThread; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Objects; class AllSensorStateController { private static final String LOG_TAG = AllSensorStateController.class.getSimpleName(); private static final String SENSOR_PRIVACY_XML_FILE = "sensor_privacy.xml"; private static final String XML_TAG_SENSOR_PRIVACY = "all-sensor-privacy"; private static final String XML_TAG_SENSOR_PRIVACY_LEGACY = "sensor-privacy"; private static final String XML_ATTRIBUTE_ENABLED = "enabled"; private static AllSensorStateController sInstance; private final AtomicFile mAtomicFile = new AtomicFile(new File(Environment.getDataSystemDirectory(), SENSOR_PRIVACY_XML_FILE)); private boolean mEnabled; private SensorPrivacyStateController.AllSensorPrivacyListener mListener; private Handler mListenerHandler; static AllSensorStateController getInstance() { if (sInstance == null) { sInstance = new AllSensorStateController(); } return sInstance; } private AllSensorStateController() { if (!mAtomicFile.exists()) { return; } try (FileInputStream inputStream = mAtomicFile.openRead()) { TypedXmlPullParser parser = Xml.resolvePullParser(inputStream); while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { String tagName = parser.getName(); if (XML_TAG_SENSOR_PRIVACY.equals(tagName)) { mEnabled |= XmlUtils .readBooleanAttribute(parser, XML_ATTRIBUTE_ENABLED, false); break; } if (XML_TAG_SENSOR_PRIVACY_LEGACY.equals(tagName)) { mEnabled |= XmlUtils .readBooleanAttribute(parser, XML_ATTRIBUTE_ENABLED, false); } if ("user".equals(tagName)) { // Migrate from mic/cam toggles format int user = XmlUtils.readIntAttribute(parser, "id", -1); if (user == 0) { mEnabled |= XmlUtils.readBooleanAttribute(parser, XML_ATTRIBUTE_ENABLED); } } XmlUtils.nextElement(parser); } } catch (IOException | XmlPullParserException e) { Log.e(LOG_TAG, "Caught an exception reading the state from storage: ", e); mEnabled = false; } } public boolean getAllSensorStateLocked() { return mEnabled; } public void setAllSensorStateLocked(boolean enabled) { if (mEnabled != enabled) { mEnabled = enabled; if (mListener != null && mListenerHandler != null) { mListenerHandler.sendMessage( PooledLambda.obtainMessage(mListener::onAllSensorPrivacyChanged, enabled)); } } } void setAllSensorPrivacyListenerLocked(Handler handler, SensorPrivacyStateController.AllSensorPrivacyListener listener) { Objects.requireNonNull(handler); Objects.requireNonNull(listener); if (mListener != null) { throw new IllegalStateException("Listener is already set"); } mListener = listener; mListenerHandler = handler; } public void schedulePersistLocked() { IoThread.getHandler().sendMessage(PooledLambda.obtainMessage(this::persist, mEnabled)); } private void persist(boolean enabled) { FileOutputStream outputStream = null; try { outputStream = mAtomicFile.startWrite(); TypedXmlSerializer serializer = Xml.resolveSerializer(outputStream); serializer.startDocument(null, true); serializer.startTag(null, XML_TAG_SENSOR_PRIVACY); serializer.attributeBoolean(null, XML_ATTRIBUTE_ENABLED, enabled); serializer.endTag(null, XML_TAG_SENSOR_PRIVACY); serializer.endDocument(); mAtomicFile.finishWrite(outputStream); } catch (IOException e) { Log.e(LOG_TAG, "Caught an exception persisting the sensor privacy state: ", e); mAtomicFile.failWrite(outputStream); } } void resetForTesting() { mListener = null; mListenerHandler = null; mEnabled = false; } void dumpLocked(@NonNull DualDumpOutputStream dumpStream) { // TODO stub } }
services/core/java/com/android/server/sensorprivacy/OWNERS 0 → 100644 +1 −0 Original line number Diff line number Diff line include platform/frameworks/native:/libs/sensorprivacy/OWNERS No newline at end of file