Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af91a91c authored by Anh Pham's avatar Anh Pham
Browse files

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
parent 5b2a141a
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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
    };
+1 −0
Original line number Diff line number Diff line
@@ -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;
};
+32 −3
Original line number Diff line number Diff line
@@ -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);
}

+1 −1
Original line number Diff line number Diff line
@@ -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.
+73 −0
Original line number Diff line number Diff line
@@ -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
Loading