In restricted mode, only CTS tests can register for sensors or call flush() on them. The requests
from other applications will be ignored.
Change-Id: Ieb923df3e0cfe3390fe2d052af776da79589744b
class Sensor;
class ISensorEventConnection;
+class String8;
class ISensorServer : public IInterface
{
DECLARE_META_INTERFACE(SensorServer);
virtual Vector<Sensor> getSensorList() = 0;
- virtual sp<ISensorEventConnection> createSensorEventConnection() = 0;
+ virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName) = 0;
};
// ----------------------------------------------------------------------------
class ISensorServer;
class Sensor;
class SensorEventQueue;
-
+class String8;
// ----------------------------------------------------------------------------
class SensorManager :
ssize_t getSensorList(Sensor const* const** list) const;
Sensor const* getDefaultSensor(int type);
- sp<SensorEventQueue> createEventQueue();
+ sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""));
private:
// DeathRecipient interface
return v;
}
- virtual sp<ISensorEventConnection> createSensorEventConnection()
+ virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName)
{
Parcel data, reply;
data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
+ data.writeString8(packageName);
remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
}
}
case CREATE_SENSOR_EVENT_CONNECTION: {
CHECK_INTERFACE(ISensorServer, data, reply);
- sp<ISensorEventConnection> connection(createSensorEventConnection());
+ String8 packageName = data.readString8();
+ sp<ISensorEventConnection> connection(createSensorEventConnection(packageName));
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
return NULL;
}
-sp<SensorEventQueue> SensorManager::createEventQueue()
+sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName)
{
sp<SensorEventQueue> queue;
Mutex::Autolock _l(mLock);
while (assertStateLocked() == NO_ERROR) {
sp<ISensorEventConnection> connection =
- mSensorServer->createSensorEventConnection();
+ mSensorServer->createSensorEventConnection(packageName);
if (connection == NULL) {
// SensorService just died.
ALOGE("createEventQueue: connection is NULL. SensorService died.");
Mutex::Autolock _l(mLock);
for (size_t i=0 ; i<size_t(count) ; i++) {
const Info& info = mActivationCount.valueFor(list[i].handle);
+ if (info.batchParams.isEmpty()) continue;
result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle,
info.batchParams.size());
for (size_t j = 0; j < info.batchParams.size(); j++) {
if (enabled) {
ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident));
+ if (isClientDisabledLocked(ident)) {
+ return INVALID_OPERATION;
+ }
+
if (info.batchParams.indexOfKey(ident) >= 0) {
- if (info.batchParams.size() == 1) {
+ if (info.numActiveClients() == 1) {
// This is the first connection, we need to activate the underlying h/w sensor.
actuateHardware = true;
}
ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
if (info.removeBatchParamsForIdent(ident) >= 0) {
- if (info.batchParams.size() == 0) {
+ if (info.numActiveClients() == 0) {
// This is the last connection, we need to de-activate the underlying h/w sensor.
actuateHardware = true;
} else {
} else {
// sensor wasn't enabled for this ident
}
+
+ if (isClientDisabledLocked(ident)) {
+ return NO_ERROR;
+ }
}
if (actuateHardware) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
+ enabled);
err = mSensorDevice->activate(
reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled);
ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
}
// On older devices which do not support batch, call setDelay().
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.batchParams.size() > 0) {
+ if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle,
info.bestBatchParams.batchDelay);
mSensorDevice->setDelay(
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
Mutex::Autolock _l(mLock);
+ if (isClientDisabledLocked(ident)) return INVALID_OPERATION;
Info& info( mActivationCount.editValueFor(handle) );
// If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
// Calling setDelay() in batch mode is an invalid operation.
int SensorDevice::getHalDeviceVersion() const {
if (!mSensorDevice) return -1;
-
return mSensorDevice->common.version;
}
if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
return INVALID_OPERATION;
}
+ if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return mSensorDevice->flush(mSensorDevice, handle);
}
+bool SensorDevice::isClientDisabled(void* ident) {
+ Mutex::Autolock _l(mLock);
+ return isClientDisabledLocked(ident);
+}
+
+bool SensorDevice::isClientDisabledLocked(void* ident) {
+ return mDisabledClients.indexOf(ident) >= 0;
+}
+
+void SensorDevice::enableAllSensors() {
+ Mutex::Autolock _l(mLock);
+ mDisabledClients.clear();
+ const int halVersion = getHalDeviceVersion();
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ Info& info = mActivationCount.editValueAt(i);
+ if (info.batchParams.isEmpty()) continue;
+ info.selectBatchParams();
+ const int sensor_handle = mActivationCount.keyAt(i);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
+ sensor_handle);
+ status_t err(NO_ERROR);
+ if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
+ err = mSensorDevice->batch(mSensorDevice, sensor_handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+
+ if (err == NO_ERROR) {
+ err = mSensorDevice->activate(
+ reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+ sensor_handle, 1);
+ ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+
+ if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) {
+ err = mSensorDevice->setDelay(
+ reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+ sensor_handle, info.bestBatchParams.batchDelay);
+ ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err));
+ }
+ }
+}
+
+void SensorDevice::disableAllSensors() {
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ const Info& info = mActivationCount.valueAt(i);
+ // Check if this sensor has been activated previously and disable it.
+ if (info.batchParams.size() > 0) {
+ const int sensor_handle = mActivationCount.keyAt(i);
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
+ sensor_handle);
+ mSensorDevice->activate(
+ reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
+ sensor_handle, 0);
+ // Add all the connections that were registered for this sensor to the disabled
+ // clients list.
+ for (int j = 0; j < info.batchParams.size(); ++j) {
+ mDisabledClients.add(info.batchParams.keyAt(j));
+ }
+ }
+ }
+}
+
// ---------------------------------------------------------------------------
+int SensorDevice::Info::numActiveClients() {
+ SensorDevice& device(SensorDevice::getInstance());
+ int num = 0;
+ for (size_t i = 0; i < batchParams.size(); ++i) {
+ if (!device.isClientDisabledLocked(batchParams.keyAt(i))) {
+ ++num;
+ }
+ }
+ return num;
+}
+
status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs) {
}
void SensorDevice::Info::selectBatchParams() {
- BatchParams bestParams(-1, -1, -1);
-
- if (batchParams.size() > 0) {
- BatchParams params = batchParams.valueAt(0);
- bestParams = params;
- }
+ BatchParams bestParams(0, -1, -1);
+ SensorDevice& device(SensorDevice::getInstance());
- for (size_t i = 1; i < batchParams.size(); ++i) {
+ for (size_t i = 0; i < batchParams.size(); ++i) {
+ if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
BatchParams params = batchParams.valueAt(i);
- if (params.batchDelay < bestParams.batchDelay) {
+ if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) {
bestParams.batchDelay = params.batchDelay;
}
- if (params.batchTimeout < bestParams.batchTimeout) {
+ if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) {
bestParams.batchTimeout = params.batchTimeout;
}
}
// Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from
// batch call. For continous mode clients, maxBatchReportLatency is set to zero.
struct BatchParams {
+ // TODO: Get rid of flags parameter everywhere.
int flags;
nsecs_t batchDelay, batchTimeout;
BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {}
// requested by the client.
KeyedVector<void*, BatchParams> batchParams;
- Info() : bestBatchParams(-1, -1, -1) {}
+ Info() : bestBatchParams(0, -1, -1) {}
// Sets batch parameters for this ident. Returns error if this ident is not already present
// in the KeyedVector above.
status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs,
// Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of
// the removed ident. If index >=0, ident is present and successfully removed.
ssize_t removeBatchParamsForIdent(void* ident);
+
+ int numActiveClients();
};
DefaultKeyedVector<int, Info> mActivationCount;
+ // Use this vector to determine which client is activated or deactivated.
+ SortedVector<void *> mDisabledClients;
SensorDevice();
+
+ bool isClientDisabled(void* ident);
+ bool isClientDisabledLocked(void* ident);
public:
ssize_t getSensorList(sensor_t const** list);
status_t initCheck() const;
// Call batch with timeout zero instead of calling setDelay() for newer devices.
status_t setDelay(void* ident, int handle, int64_t ns);
status_t flush(void* ident, int handle);
+ void disableAllSensors();
+ void enableAllSensors();
void autoDisable(void *ident, int handle);
void dump(String8& result);
};
mSensorEventBuffer = new sensors_event_t[minBufferSize];
mSensorEventScratch = new sensors_event_t[minBufferSize];
mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize];
+ mMode = NORMAL;
mAckReceiver = new SensorEventAckReceiver(this);
mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY);
static const String16 sDump("android.permission.DUMP");
-status_t SensorService::dump(int fd, const Vector<String16>& /*args*/)
+status_t SensorService::dump(int fd, const Vector<String16>& args)
{
String8 result;
if (!PermissionCache::checkCallingPermission(sDump)) {
"can't dump SensorService from pid=%d, uid=%d\n",
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
+ } else if (args.size() > 0) {
+ if (args.size() > 1) {
+ return INVALID_OPERATION;
+ }
+ Mutex::Autolock _l(mLock);
+ SensorDevice& dev(SensorDevice::getInstance());
+ if (args[0] == String16("restrict") && mMode == NORMAL) {
+ mMode = RESTRICTED;
+ dev.disableAllSensors();
+ // Clear all pending flush connections for all active sensors. If one of the active
+ // connections has called flush() and the underlying sensor has been disabled before a
+ // flush complete event is returned, we need to remove the connection from this queue.
+ for (size_t i=0 ; i< mActiveSensors.size(); ++i) {
+ mActiveSensors.valueAt(i)->clearAllPendingFlushConnections();
+ }
+ } else if (args[0] == String16("enable") && mMode == RESTRICTED) {
+ mMode = NORMAL;
+ dev.enableAllSensors();
+ }
+ return status_t(NO_ERROR);
} else {
Mutex::Autolock _l(mLock);
result.append("Sensor List:\n");
result.appendFormat("Socket Buffer size = %d events\n",
mSocketBufferSize/sizeof(sensors_event_t));
result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held");
+ result.appendFormat("Mode :");
+ switch(mMode) {
+ case NORMAL:
+ result.appendFormat(" NORMAL\n");
+ break;
+ case RESTRICTED:
+ result.appendFormat(" RESTRICTED\n");
+ break;
+ case DATA_INJECTION:
+ result.appendFormat(" DATA_INJECTION\n");
+ }
result.appendFormat("%zd active connections\n", mActiveConnections.size());
for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
}
}
-
bool SensorService::isWakeLockAcquired() {
Mutex::Autolock _l(mLock);
return mWakeLockAcquired;
return sensor != NULL && sensor->getSensor().isWakeUpSensor();
}
-
SensorService::SensorRecord * SensorService::getSensorRecord(int handle) {
return mActiveSensors.valueFor(handle);
}
return accessibleSensorList;
}
-sp<ISensorEventConnection> SensorService::createSensorEventConnection()
+sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName)
{
uid_t uid = IPCThreadState::self()->getCallingUid();
- sp<SensorEventConnection> result(new SensorEventConnection(this, uid));
+ sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName));
return result;
}
}
status_t SensorService::enable(const sp<SensorEventConnection>& connection,
- int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags)
+ int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags)
{
if (mInitCheck != NO_ERROR)
return mInitCheck;
}
Mutex::Autolock _l(mLock);
+ if (mMode == RESTRICTED && !isWhiteListedPackage(connection->getPackageName())) {
+ return INVALID_OPERATION;
+ }
+
SensorRecord* rec = mActiveSensors.valueFor(handle);
if (rec == 0) {
rec = new SensorRecord(connection);
"rate=%" PRId64 " timeout== %" PRId64"",
handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs);
- status_t err = sensor->batch(connection.get(), handle, reservedFlags, samplingPeriodNs,
+ status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs,
maxBatchReportLatencyNs);
// Call flush() before calling activate() on the sensor. Wait for a first flush complete
}
}
+bool SensorService::isWhiteListedPackage(const String8& packageName) {
+ // TODO: Come up with a list of packages.
+ return (packageName.find(".cts.") != -1);
+}
+
// ---------------------------------------------------------------------------
SensorService::SensorRecord::SensorRecord(
const sp<SensorEventConnection>& connection)
return NULL;
}
+void SensorService::SensorRecord::clearAllPendingFlushConnections() {
+ mPendingFlushConnections.clear();
+}
+
// ---------------------------------------------------------------------------
SensorService::SensorEventConnection::SensorEventConnection(
- const sp<SensorService>& service, uid_t uid)
+ const sp<SensorService>& service, uid_t uid, String8 packageName)
: mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
- mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0) {
+ mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName) {
mChannel = new BitTube(mService->mSocketBufferSize);
#if DEBUG_CONNECTIONS
mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
void SensorService::SensorEventConnection::dump(String8& result) {
Mutex::Autolock _l(mConnectionLock);
- result.appendFormat("\t WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n",
- mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize);
+ result.appendFormat("\t%s | WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n",
+ mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize);
for (size_t i = 0; i < mSensorInfo.size(); ++i) {
const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n",
return false;
}
+String8 SensorService::SensorEventConnection::getPackageName() const {
+ return mPackageName;
+}
+
void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle,
bool value) {
Mutex::Autolock _l(mConnectionLock);
#include <utils/AndroidThreads.h>
#include <utils/RefBase.h>
#include <utils/Looper.h>
+#include <utils/String8.h>
#include <binder/BinderService.h>
{
friend class BinderService<SensorService>;
+ enum Mode {
+ // The regular operating mode where any application can register/unregister/call flush on
+ // sensors.
+ NORMAL = 0,
+ // This mode is used only for testing sensors. Each sensor can be tested in isolation with
+ // the required sampling_rate and maxReportLatency parameters without having to think about
+ // the data rates requested by other applications. End user devices are always expected to be
+ // in NORMAL mode. When this mode is first activated, all active sensors from all connections
+ // are disabled. Calling flush() will return an error. In this mode, only the requests from
+ // selected apps whose package names are whitelisted are allowed (typically CTS apps). Only
+ // these apps can register/unregister/call flush() on sensors. If SensorService switches to
+ // NORMAL mode again, all sensors that were previously registered to are activated with the
+ // corresponding paramaters if the application hasn't unregistered for sensors in the mean
+ // time.
+ // NOTE: Non whitelisted app whose sensors were previously deactivated may still receive
+ // events if a whitelisted app requests data from the same sensor.
+ RESTRICTED,
+ // TODO: This mode hasn't been implemented yet.
+ DATA_INJECTION
+ };
+
static const char* WAKE_LOCK_NAME;
static char const* getServiceName() ANDROID_API { return "sensorservice"; }
// ISensorServer interface
virtual Vector<Sensor> getSensorList();
- virtual sp<ISensorEventConnection> createSensorEventConnection();
+ virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName);
virtual status_t dump(int fd, const Vector<String16>& args);
class SensorEventConnection : public BnSensorEventConnection, public LooperCallback {
// connection FD may be added to the Looper. The flags to set are determined by the internal
// state of the connection. FDs are added to the looper when wake-up sensors are registered
// (to poll for acknowledgements) and when write fails on the socket when there are too many
- // events (to poll when the FD is available for writing). FDs are removed when there is an
// error and the other end hangs up or when this client unregisters for this connection.
void updateLooperRegistration(const sp<Looper>& looper);
void updateLooperRegistrationLocked(const sp<Looper>& looper);
KeyedVector<int, FlushInfo> mSensorInfo;
sensors_event_t *mEventCache;
int mCacheSize, mMaxCacheSize;
+ String8 mPackageName;
#if DEBUG_CONNECTIONS
int mEventsReceived, mEventsSent, mEventsSentFromCache;
#endif
public:
- SensorEventConnection(const sp<SensorService>& service, uid_t uid);
+ SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName);
status_t sendEvents(sensors_event_t const* buffer, size_t count,
sensors_event_t* scratch,
void dump(String8& result);
bool needsWakeLock();
void resetWakeLockRefCount();
+ String8 getPackageName() const;
uid_t getUid() const { return mUid; }
};
void addPendingFlushConnection(const sp<SensorEventConnection>& connection);
void removeFirstPendingFlushConnection();
SensorEventConnection * getFirstPendingFlushConnection();
+ void clearAllPendingFlushConnections();
};
class SensorEventAckReceiver : public Thread {
// to the output vector.
void populateActiveConnections(SortedVector< sp<SensorEventConnection> >* activeConnections);
+ // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are
+ // allowed to register for or call flush on sensors. Typically only cts test packages are
+ // allowed.
+ bool isWhiteListedPackage(const String8& packageName);
+
// constants
Vector<Sensor> mSensorList;
Vector<Sensor> mUserSensorListDebug;
bool mWakeLockAcquired;
sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
SensorEventConnection const **mMapFlushEventsToConnections;
+ Mode mMode;
// The size of this vector is constant, only the items are mutable
KeyedVector<int32_t, sensors_event_t> mLastEventSeen;