Throttle sensor sampling rates at 200Hz.
Only sensors of the following types are throttled: accelerometer, gyroscope and magnetometer.
Both direct and non-direct connections are throttled, as follows:
- If the microphone toggle is on: all apps are throttled at 200Hz, regardless of their targetSDK.
- If the microphone toggle is off:
+ If apps target SDK <= R, no throttling.
+ If apps target SDK >= S and has the HIGH_SAMPLING_RATE_SENSORS permission, no throttling.
+ If apps target SDK >= S and does not have the HIGH_SAMPLING_RATE_SENSORS permission:
+ Sampling rates are throttled at 200 Hz.
+ If run in debug mode, a SecurityException is thrown.
Test: atest CtsSensorTestCases CtsSensorRatePermissionTestCases
Bug: 136069189
Change-Id: Idd3ba874eee34859b3f090af59def0a939688c07
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index e4c33da..b3be72d 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -32,6 +32,7 @@
: mService(service), mUid(uid), mMem(*mem),
mHalChannelHandle(halChannelHandle),
mOpPackageName(opPackageName), mDestroyed(false) {
+ mIsRateCappedBasedOnPermission = mService->isRateCappedBasedOnPermission(mOpPackageName);
ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection");
}
@@ -157,6 +158,13 @@
return INVALID_OPERATION;
}
+ if (mService->isSensorInCappedSet(s.getType()) && rateLevel != SENSOR_DIRECT_RATE_STOP) {
+ status_t err = mService->adjustRateLevelBasedOnMicAndPermission(&rateLevel, mOpPackageName);
+ if (err != OK) {
+ return err;
+ }
+ }
+
struct sensors_direct_cfg_t config = {
.rate_level = rateLevel
};
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 4181b65..526e66f 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -92,6 +92,7 @@
std::unordered_map<int, int> mActivated;
std::unordered_map<int, int> mActivatedBackup;
+ std::atomic_bool mIsRateCappedBasedOnPermission;
mutable Mutex mDestroyLock;
bool mDestroyed;
};
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 6810c1b7..90e33a9 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -44,6 +44,7 @@
mCacheSize(0), mMaxCacheSize(0), mTimeOfLastEventDrop(0), mEventsDropped(0),
mPackageName(packageName), mOpPackageName(opPackageName), mTargetSdk(kTargetSdkUnknown),
mDestroyed(false) {
+ mIsRateCappedBasedOnPermission = mService->isRateCappedBasedOnPermission(mOpPackageName);
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
@@ -684,6 +685,21 @@
status_t err;
if (enabled) {
+ bool isSensorCapped = false;
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr) {
+ const Sensor& s = si->getSensor();
+ if (mService->isSensorInCappedSet(s.getType())) {
+ isSensorCapped = true;
+ }
+ }
+ if (isSensorCapped) {
+ err = mService->adjustSamplingPeriodBasedOnMicAndPermission(&samplingPeriodNs,
+ String16(mOpPackageName));
+ if (err != OK) {
+ return err;
+ }
+ }
err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
reservedFlags, mOpPackageName);
@@ -693,14 +709,27 @@
return err;
}
-status_t SensorService::SensorEventConnection::setEventRate(
- int handle, nsecs_t samplingPeriodNs)
-{
+status_t SensorService::SensorEventConnection::setEventRate(int handle, nsecs_t samplingPeriodNs) {
if (mDestroyed) {
android_errorWriteLog(0x534e4554, "168211968");
return DEAD_OBJECT;
}
+ bool isSensorCapped = false;
+ sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
+ if (si != nullptr) {
+ const Sensor& s = si->getSensor();
+ if (mService->isSensorInCappedSet(s.getType())) {
+ isSensorCapped = true;
+ }
+ }
+ if (isSensorCapped) {
+ status_t err = mService->adjustSamplingPeriodBasedOnMicAndPermission(&samplingPeriodNs,
+ String16(mOpPackageName));
+ if (err != OK) {
+ return err;
+ }
+ }
return mService->setEventRate(this, handle, samplingPeriodNs, mOpPackageName);
}
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 9487a39..7c8c4f3 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -137,10 +137,10 @@
// Call noteOp for the sensor if the sensor requires a permission
bool noteOpIfRequired(const sensors_event_t& event);
-
sp<SensorService> const mService;
sp<BitTube> mChannel;
uid_t mUid;
+ std::atomic_bool mIsRateCappedBasedOnPermission;
mutable Mutex mConnectionLock;
// Number of events from wake up sensors which are still pending and haven't been delivered to
// the corresponding application. It is incremented by one unit for each write to the socket.
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8f25bdb..cd1521d 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <android-base/strings.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/util/ProtoOutputStream.h>
#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
@@ -88,6 +89,8 @@
#define SENSOR_SERVICE_SCHED_FIFO_PRIORITY 10
// Permissions.
+static const String16 sAccessHighSensorSamplingRatePermission(
+ "android.permission.HIGH_SAMPLING_RATE_SENSORS");
static const String16 sDumpPermission("android.permission.DUMP");
static const String16 sLocationHardwarePermission("android.permission.LOCATION_HARDWARE");
static const String16 sManageSensorsPermission("android.permission.MANAGE_SENSORS");
@@ -2024,6 +2027,63 @@
return mUidPolicy->isUidActive(uid);
}
+bool SensorService::isRateCappedBasedOnPermission(const String16& opPackageName) {
+ int targetSdk = getTargetSdkVersion(opPackageName);
+ bool hasSamplingRatePermission = PermissionCache::checkCallingPermission(
+ sAccessHighSensorSamplingRatePermission);
+ if (targetSdk < __ANDROID_API_S__ ||
+ (targetSdk >= __ANDROID_API_S__ && hasSamplingRatePermission)) {
+ return false;
+ }
+ return true;
+}
+
+bool SensorService::isSensorInCappedSet(int sensorType) {
+ return (sensorType == SENSOR_TYPE_ACCELEROMETER
+ || sensorType == SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED
+ || sensorType == SENSOR_TYPE_GYROSCOPE
+ || sensorType == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED
+ || sensorType == SENSOR_TYPE_MAGNETIC_FIELD
+ || sensorType == SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED);
+}
+
+status_t SensorService::adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
+ const String16& opPackageName) {
+
+ bool shouldCapBasedOnPermission = isRateCappedBasedOnPermission(opPackageName);
+ if (*requestedPeriodNs >= SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS) {
+ return OK;
+ }
+ if (shouldCapBasedOnPermission) {
+ *requestedPeriodNs = SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS;
+ if (isPackageDebuggable(opPackageName)) {
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
+ // Condition based on mic toggle is added later.
+ return OK;
+}
+
+status_t SensorService::adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
+ const String16& opPackageName) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ bool shouldCapBasedOnPermission = isRateCappedBasedOnPermission(opPackageName);
+
+ if (*requestedRateLevel <= SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL) {
+ return OK;
+ }
+ if (shouldCapBasedOnPermission) {
+ *requestedRateLevel = SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL;
+ if (isPackageDebuggable(opPackageName)) {
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
+ // Condition based on mic toggle is added later.
+ return OK;
+}
+
void SensorService::SensorPrivacyPolicy::registerSelf() {
SensorPrivacyManager spm;
mSensorPrivacyEnabled = spm.isSensorPrivacyEnabled();
@@ -2109,4 +2169,17 @@
return ConnectionSafeAutolock(*this, mutex);
}
+bool SensorService::isPackageDebuggable(const String16& opPackageName) {
+ bool debugMode = false;
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("package_native"));
+ if (binder != nullptr) {
+ sp<content::pm::IPackageManagerNative> packageManager =
+ interface_cast<content::pm::IPackageManagerNative>(binder);
+ if (packageManager != nullptr) {
+ binder::Status status = packageManager->isPackageDebuggable(
+ opPackageName, &debugMode);
+ }
+ }
+ return debugMode;
+}
} // namespace android
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 50c7c2f..a884a42 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -61,6 +61,15 @@
#define SENSOR_REGISTRATIONS_BUF_SIZE 200
+// Apps that targets S+ and do not have HIGH_SAMPLING_RATE_SENSORS permission will be capped
+// at 200 Hz. The cap also applies to all requests when the mic toggle is flipped, regardless of
+// their target SDKs and permission.
+// Capped sampling periods for apps that have non-direct sensor connections.
+#define SENSOR_SERVICE_CAPPED_SAMPLING_PERIOD_NS (5 * 1000 * 1000)
+// Capped sampling rate level for apps that have direct sensor connections.
+// The enum SENSOR_DIRECT_RATE_NORMAL corresponds to a rate value of at most 110 Hz.
+#define SENSOR_SERVICE_CAPPED_SAMPLING_RATE_LEVEL SENSOR_DIRECT_RATE_NORMAL
+
namespace android {
// ---------------------------------------------------------------------------
class SensorInterface;
@@ -95,6 +104,8 @@
status_t flushSensor(const sp<SensorEventConnection>& connection,
const String16& opPackageName);
+ // Returns true if a sensor should be throttled according to our rate-throttling rules.
+ static bool isSensorInCappedSet(int sensorType);
virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
@@ -346,6 +357,13 @@
// whitelisted). mLock must be held to invoke this method.
bool isOperationRestrictedLocked(const String16& opPackageName);
+ status_t adjustSamplingPeriodBasedOnMicAndPermission(nsecs_t* requestedPeriodNs,
+ const String16& opPackageName);
+ status_t adjustRateLevelBasedOnMicAndPermission(int* requestedRateLevel,
+ const String16& opPackageName);
+ bool isRateCappedBasedOnPermission(const String16& opPackageName);
+ bool isPackageDebuggable(const String16& opPackageName);
+
// Reset the state of SensorService to NORMAL mode.
status_t resetToNormalMode();
status_t resetToNormalModeLocked();