diff options
author | 2021-02-10 14:10:53 +0100 | |
---|---|---|
committer | 2021-02-15 10:46:15 +0100 | |
commit | af91a91c5cce1263895ee804e961975ad7aab3a2 (patch) | |
tree | 4bd2fccba8511ec8fb7a9ea8c0abbca0d03455a2 | |
parent | 5b2a141aa6849f841196d4a7d89253a0d4849f07 (diff) |
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
-rw-r--r-- | services/sensorservice/SensorDirectConnection.cpp | 8 | ||||
-rw-r--r-- | services/sensorservice/SensorDirectConnection.h | 1 | ||||
-rw-r--r-- | services/sensorservice/SensorEventConnection.cpp | 35 | ||||
-rw-r--r-- | services/sensorservice/SensorEventConnection.h | 2 | ||||
-rw-r--r-- | services/sensorservice/SensorService.cpp | 73 | ||||
-rw-r--r-- | services/sensorservice/SensorService.h | 18 |
6 files changed, 133 insertions, 4 deletions
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp index e4c33dafcb..b3be72d9b6 100644 --- a/services/sensorservice/SensorDirectConnection.cpp +++ b/services/sensorservice/SensorDirectConnection.cpp @@ -32,6 +32,7 @@ SensorService::SensorDirectConnection::SensorDirectConnection(const sp<SensorSer : 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 @@ int32_t SensorService::SensorDirectConnection::configureChannel(int handle, int 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 4181b65b7d..526e66f49d 100644 --- a/services/sensorservice/SensorDirectConnection.h +++ b/services/sensorservice/SensorDirectConnection.h @@ -92,6 +92,7 @@ private: 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 6810c1b781..90e33a9134 100644 --- a/services/sensorservice/SensorEventConnection.cpp +++ b/services/sensorservice/SensorEventConnection.cpp @@ -44,6 +44,7 @@ SensorService::SensorEventConnection::SensorEventConnection( 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 SensorService::SensorEventConnection::enableDisable( 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 @@ status_t SensorService::SensorEventConnection::enableDisable( 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 9487a39a92..7c8c4f34b4 100644 --- a/services/sensorservice/SensorEventConnection.h +++ b/services/sensorservice/SensorEventConnection.h @@ -137,10 +137,10 @@ private: // 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 8f25bdba4f..cd1521da18 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 @@ AppOpsManager SensorService::sAppOpsManager; #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 @@ bool SensorService::isUidActive(uid_t uid) { 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 @@ SensorService::ConnectionSafeAutolock SensorService::SensorConnectionHolder::loc 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 50c7c2f383..a884a42381 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 @@ public: 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 @@ private: // 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(); |