Merge "Add dumpsys and shell cmd for sensor_privacy"
This commit is contained in:
committed by
Android (Google) Code Review
commit
f52311f658
@@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.service.SensorPrivacyIndividualEnabledSensorProto;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -43,18 +44,23 @@ import java.lang.annotation.RetentionPolicy;
|
||||
public final class SensorPrivacyManager {
|
||||
|
||||
/** Microphone */
|
||||
public static final int INDIVIDUAL_SENSOR_MICROPHONE = 1;
|
||||
public static final int INDIVIDUAL_SENSOR_MICROPHONE =
|
||||
SensorPrivacyIndividualEnabledSensorProto.MICROPHONE;
|
||||
|
||||
/** Camera */
|
||||
public static final int INDIVIDUAL_SENSOR_CAMERA = 2;
|
||||
public static final int INDIVIDUAL_SENSOR_CAMERA =
|
||||
SensorPrivacyIndividualEnabledSensorProto.CAMERA;
|
||||
|
||||
/**
|
||||
* Individual sensors not listed in {@link Sensor}
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = "INDIVIDUAL_SENSOR_", value = {
|
||||
INDIVIDUAL_SENSOR_MICROPHONE,
|
||||
INDIVIDUAL_SENSOR_CAMERA
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
/** Individual sensors not listed in {@link Sensor} */
|
||||
@interface IndividualSensor {}
|
||||
public @interface IndividualSensor {}
|
||||
|
||||
/**
|
||||
* A class implementing this interface can register with the {@link
|
||||
|
||||
@@ -18,11 +18,10 @@ package com.android.internal.util.dump;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
50
core/proto/android/hardware/sensorprivacy.proto
Normal file
50
core/proto/android/hardware/sensorprivacy.proto
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
package android.service;
|
||||
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "SensorPrivacyServiceProto";
|
||||
|
||||
import "frameworks/base/core/proto/android/privacy.proto";
|
||||
|
||||
message SensorPrivacyServiceDumpProto {
|
||||
option (android.msg_privacy).dest = DEST_AUTOMATIC;
|
||||
|
||||
// Is global sensor privacy enabled
|
||||
optional bool is_enabled = 1;
|
||||
|
||||
// Per sensor privacy enabled
|
||||
repeated SensorPrivacyIndividualEnabledSensorProto individual_enabled_sensor = 2;
|
||||
}
|
||||
|
||||
message SensorPrivacyIndividualEnabledSensorProto {
|
||||
option (android.msg_privacy).dest = DEST_AUTOMATIC;
|
||||
|
||||
enum Sensor {
|
||||
UNKNOWN = 0;
|
||||
|
||||
MICROPHONE = 1;
|
||||
CAMERA = 2;
|
||||
}
|
||||
|
||||
// Sensor for which privacy might be enabled
|
||||
optional Sensor sensor = 1;
|
||||
|
||||
// If sensor privacy is enabled for this sensor
|
||||
optional bool is_enabled = 2;
|
||||
}
|
||||
@@ -17,36 +17,55 @@
|
||||
package com.android.server;
|
||||
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
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.content.Context;
|
||||
import android.hardware.ISensorPrivacyListener;
|
||||
import android.hardware.ISensorPrivacyManager;
|
||||
import android.hardware.SensorPrivacyManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.ShellCommand;
|
||||
import android.service.SensorPrivacyIndividualEnabledSensorProto;
|
||||
import android.service.SensorPrivacyServiceDumpProto;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.TypedXmlPullParser;
|
||||
import android.util.TypedXmlSerializer;
|
||||
import android.util.Xml;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
import com.android.internal.util.dump.DualDumpOutputStream;
|
||||
import com.android.internal.util.function.pooled.PooledLambda;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
|
||||
/** @hide */
|
||||
public final class SensorPrivacyService extends SystemService {
|
||||
@@ -239,6 +258,170 @@ public final class SensorPrivacyService extends SystemService {
|
||||
}
|
||||
mHandler.removeListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
Objects.requireNonNull(fd);
|
||||
|
||||
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
|
||||
|
||||
int opti = 0;
|
||||
boolean dumpAsProto = false;
|
||||
while (opti < args.length) {
|
||||
String opt = args[opti];
|
||||
if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
|
||||
break;
|
||||
}
|
||||
opti++;
|
||||
if ("--proto".equals(opt)) {
|
||||
dumpAsProto = true;
|
||||
} else {
|
||||
pw.println("Unknown argument: " + opt + "; use -h for help");
|
||||
}
|
||||
}
|
||||
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (dumpAsProto) {
|
||||
dump(new DualDumpOutputStream(new ProtoOutputStream(fd)));
|
||||
} else {
|
||||
pw.println("SENSOR PRIVACY MANAGER STATE (dumpsys "
|
||||
+ Context.SENSOR_PRIVACY_SERVICE + ")");
|
||||
|
||||
dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")));
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump state to {@link DualDumpOutputStream}.
|
||||
*
|
||||
* @param dumpStream The destination to dump to
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
dumpStream.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string into a {@link SensorPrivacyManager.IndividualSensor id}.
|
||||
*
|
||||
* @param sensor The name to convert
|
||||
*
|
||||
* @return The id corresponding to the name
|
||||
*/
|
||||
private @SensorPrivacyManager.IndividualSensor int sensorStrToId(@Nullable String sensor) {
|
||||
if (sensor == null) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
switch (sensor) {
|
||||
case "microphone":
|
||||
return MICROPHONE;
|
||||
case "camera":
|
||||
return CAMERA;
|
||||
default: {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShellCommand(FileDescriptor in, FileDescriptor out,
|
||||
FileDescriptor err, String[] args, ShellCallback callback,
|
||||
ResultReceiver resultReceiver) {
|
||||
(new ShellCommand() {
|
||||
@Override
|
||||
public int onCommand(String cmd) {
|
||||
if (cmd == null) {
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
switch (cmd) {
|
||||
case "enable" : {
|
||||
int sensor = sensorStrToId(getNextArg());
|
||||
if (sensor == UNKNOWN) {
|
||||
pw.println("Invalid sensor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
setIndividualSensorPrivacy(sensor, true);
|
||||
}
|
||||
break;
|
||||
case "disable" : {
|
||||
int sensor = sensorStrToId(getNextArg());
|
||||
if (sensor == UNKNOWN) {
|
||||
pw.println("Invalid sensor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
setIndividualSensorPrivacy(sensor, false);
|
||||
}
|
||||
break;
|
||||
case "reset": {
|
||||
int sensor = sensorStrToId(getNextArg());
|
||||
if (sensor == UNKNOWN) {
|
||||
pw.println("Invalid sensor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
enforceSensorPrivacyPermission();
|
||||
|
||||
synchronized (mLock) {
|
||||
mIndividualEnabled.delete(sensor);
|
||||
persistSensorPrivacyState();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
|
||||
pw.println("Sensor privacy manager (" + Context.SENSOR_PRIVACY_SERVICE
|
||||
+ ") commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Print this help text.");
|
||||
pw.println("");
|
||||
pw.println(" enable SENSOR");
|
||||
pw.println(" Enable privacy for a certain sensor.");
|
||||
pw.println("");
|
||||
pw.println(" disable SENSOR");
|
||||
pw.println(" Disable privacy for a certain sensor.");
|
||||
pw.println("");
|
||||
pw.println(" reset SENSOR");
|
||||
pw.println(" Reset privacy state for a certain sensor.");
|
||||
pw.println("");
|
||||
}
|
||||
}).exec(this, in, out, err, args, callback, resultReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user