| /* |
| * Copyright (C) 2008 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. |
| */ |
| |
| package com.android.server; |
| |
| import android.content.Context; |
| import android.hardware.ISensorService; |
| import android.os.Binder; |
| import android.os.Bundle; |
| import android.os.RemoteException; |
| import android.os.IBinder; |
| import android.util.Config; |
| import android.util.Log; |
| |
| import java.util.ArrayList; |
| |
| import com.android.internal.app.IBatteryStats; |
| import com.android.server.am.BatteryStatsService; |
| |
| |
| /** |
| * Class that manages the device's sensors. It register clients and activate |
| * the needed sensors. The sensor events themselves are not broadcasted from |
| * this service, instead, a file descriptor is provided to each client they |
| * can read events from. |
| */ |
| |
| class SensorService extends ISensorService.Stub { |
| static final String TAG = SensorService.class.getSimpleName(); |
| private static final boolean DEBUG = false; |
| private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; |
| private static final int SENSOR_DISABLE = -1; |
| |
| /** |
| * Battery statistics to be updated when sensors are enabled and disabled. |
| */ |
| final IBatteryStats mBatteryStats = BatteryStatsService.getService(); |
| |
| private final class Listener implements IBinder.DeathRecipient { |
| final IBinder mToken; |
| |
| int mSensors = 0; |
| int mDelay = 0x7FFFFFFF; |
| |
| Listener(IBinder token) { |
| mToken = token; |
| } |
| |
| void addSensor(int sensor, int delay) { |
| mSensors |= (1<<sensor); |
| if (mDelay > delay) |
| mDelay = delay; |
| } |
| |
| void removeSensor(int sensor) { |
| mSensors &= ~(1<<sensor); |
| } |
| |
| boolean hasSensor(int sensor) { |
| return ((mSensors & (1<<sensor)) != 0); |
| } |
| |
| public void binderDied() { |
| if (localLOGV) Log.d(TAG, "sensor listener died"); |
| synchronized(mListeners) { |
| mListeners.remove(this); |
| mToken.unlinkToDeath(this, 0); |
| // go through the lists of sensors used by the listener that |
| // died and deactivate them. |
| for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) { |
| if (hasSensor(sensor)) { |
| removeSensor(sensor); |
| try { |
| deactivateIfUnusedLocked(sensor); |
| } catch (RemoteException e) { |
| Log.w(TAG, "RemoteException in binderDied"); |
| } |
| } |
| } |
| if (mListeners.size() == 0) { |
| _sensors_control_wake(); |
| _sensors_control_close(); |
| } |
| mListeners.notify(); |
| } |
| } |
| } |
| |
| @SuppressWarnings("unused") |
| public SensorService(Context context) { |
| if (localLOGV) Log.d(TAG, "SensorService startup"); |
| _sensors_control_init(); |
| } |
| |
| public Bundle getDataChannel() throws RemoteException { |
| // synchronize so we do not require sensor HAL to be thread-safe. |
| synchronized(mListeners) { |
| return _sensors_control_open(); |
| } |
| } |
| |
| public boolean enableSensor(IBinder binder, String name, int sensor, int enable) |
| throws RemoteException { |
| if (localLOGV) Log.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable); |
| |
| // Inform battery statistics service of status change |
| int uid = Binder.getCallingUid(); |
| long identity = Binder.clearCallingIdentity(); |
| if (enable == SENSOR_DISABLE) { |
| mBatteryStats.noteStopSensor(uid, sensor); |
| } else { |
| mBatteryStats.noteStartSensor(uid, sensor); |
| } |
| Binder.restoreCallingIdentity(identity); |
| |
| if (binder == null) { |
| Log.w(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")"); |
| return false; |
| } |
| |
| synchronized(mListeners) { |
| if (enable!=SENSOR_DISABLE && !_sensors_control_activate(sensor, true)) { |
| Log.w(TAG, "could not enable sensor " + sensor); |
| return false; |
| } |
| |
| Listener l = null; |
| int minDelay = enable; |
| for (Listener listener : mListeners) { |
| if (binder == listener.mToken) { |
| l = listener; |
| } |
| if (minDelay > listener.mDelay) |
| minDelay = listener.mDelay; |
| } |
| |
| if (l == null && enable!=SENSOR_DISABLE) { |
| l = new Listener(binder); |
| binder.linkToDeath(l, 0); |
| mListeners.add(l); |
| mListeners.notify(); |
| } |
| |
| if (l == null) { |
| // by construction, this means we're disabling a listener we |
| // don't know about... |
| Log.w(TAG, "listener with binder " + binder + |
| ", doesn't exist (sensor=" + name + ", id=" + sensor + ")"); |
| return false; |
| } |
| |
| if (minDelay >= 0) { |
| _sensors_control_set_delay(minDelay); |
| } |
| |
| if (enable != SENSOR_DISABLE) { |
| l.addSensor(sensor, enable); |
| } else { |
| l.removeSensor(sensor); |
| deactivateIfUnusedLocked(sensor); |
| if (l.mSensors == 0) { |
| mListeners.remove(l); |
| binder.unlinkToDeath(l, 0); |
| mListeners.notify(); |
| } |
| } |
| |
| if (mListeners.size() == 0) { |
| _sensors_control_wake(); |
| _sensors_control_close(); |
| } |
| } |
| return true; |
| } |
| |
| private void deactivateIfUnusedLocked(int sensor) throws RemoteException { |
| int size = mListeners.size(); |
| for (int i=0 ; i<size ; i++) { |
| if (mListeners.get(i).hasSensor(sensor)) |
| return; |
| } |
| _sensors_control_activate(sensor, false); |
| } |
| |
| private ArrayList<Listener> mListeners = new ArrayList<Listener>(); |
| |
| private static native int _sensors_control_init(); |
| private static native Bundle _sensors_control_open(); |
| private static native int _sensors_control_close(); |
| private static native boolean _sensors_control_activate(int sensor, boolean activate); |
| private static native int _sensors_control_set_delay(int ms); |
| private static native int _sensors_control_wake(); |
| } |