Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server;
     18 
     19 import android.content.Context;
     20 import android.hardware.ISensorService;
     21 import android.os.Binder;
     22 import android.os.Bundle;
     23 import android.os.RemoteException;
     24 import android.os.IBinder;
     25 import android.util.Config;
     26 import android.util.Slog;
     27 import android.util.PrintWriterPrinter;
     28 import android.util.Printer;
     29 
     30 import java.io.FileDescriptor;
     31 import java.io.PrintWriter;
     32 import java.util.ArrayList;
     33 
     34 import com.android.internal.app.IBatteryStats;
     35 import com.android.server.am.BatteryStatsService;
     36 
     37 
     38 /**
     39  * Class that manages the device's sensors. It register clients and activate
     40  * the needed sensors. The sensor events themselves are not broadcasted from
     41  * this service, instead, a file descriptor is provided to each client they
     42  * can read events from.
     43  */
     44 
     45 class SensorService extends ISensorService.Stub {
     46     static final String TAG = SensorService.class.getSimpleName();
     47     private static final boolean DEBUG = false;
     48     private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
     49     private static final int SENSOR_DISABLE = -1;
     50     private int mCurrentDelay = 0;
     51 
     52     /**
     53      * Battery statistics to be updated when sensors are enabled and disabled.
     54      */
     55     final IBatteryStats mBatteryStats = BatteryStatsService.getService();
     56 
     57     private final class Listener implements IBinder.DeathRecipient {
     58         final IBinder mToken;
     59         final int mUid;
     60 
     61         int mSensors = 0;
     62         int mDelay = 0x7FFFFFFF;
     63 
     64         Listener(IBinder token, int uid) {
     65             mToken = token;
     66             mUid = uid;
     67         }
     68 
     69         void addSensor(int sensor, int delay) {
     70             mSensors |= (1<<sensor);
     71             if (delay < mDelay)
     72             	mDelay = delay;
     73         }
     74 
     75         void removeSensor(int sensor) {
     76             mSensors &= ~(1<<sensor);
     77         }
     78 
     79         boolean hasSensor(int sensor) {
     80             return ((mSensors & (1<<sensor)) != 0);
     81         }
     82 
     83         public void binderDied() {
     84             if (localLOGV) Slog.d(TAG, "sensor listener died");
     85             synchronized(mListeners) {
     86                 mListeners.remove(this);
     87                 mToken.unlinkToDeath(this, 0);
     88                 // go through the lists of sensors used by the listener that
     89                 // died and deactivate them.
     90                 for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) {
     91                     if (hasSensor(sensor)) {
     92                         removeSensor(sensor);
     93                         deactivateIfUnusedLocked(sensor);
     94                         try {
     95                             mBatteryStats.noteStopSensor(mUid, sensor);
     96                         } catch (RemoteException e) {
     97                             // oops. not a big deal.
     98                         }
     99                     }
    100                 }
    101                 if (mListeners.size() == 0) {
    102                     _sensors_control_wake();
    103                     _sensors_control_close();
    104                 } else {
    105                     // TODO: we should recalculate the delay, since removing
    106                     // a listener may increase the overall rate.
    107                 }
    108                 mListeners.notify();
    109             }
    110         }
    111     }
    112 
    113     @SuppressWarnings("unused")
    114     public SensorService(Context context) {
    115         if (localLOGV) Slog.d(TAG, "SensorService startup");
    116         _sensors_control_init();
    117     }
    118 
    119     public Bundle getDataChannel() throws RemoteException {
    120         // synchronize so we do not require sensor HAL to be thread-safe.
    121         synchronized(mListeners) {
    122             return _sensors_control_open();
    123         }
    124     }
    125 
    126     public boolean enableSensor(IBinder binder, String name, int sensor, int enable)
    127             throws RemoteException {
    128 
    129         if (localLOGV) Slog.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable);
    130 
    131         if (binder == null) {
    132             Slog.e(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")");
    133             return false;
    134         }
    135 
    136         if (enable < 0 && (enable != SENSOR_DISABLE)) {
    137             Slog.e(TAG, "invalid enable parameter (enable=" + enable +
    138                     ", sensor=" + name + ", id=" + sensor + ")");
    139             return false;
    140         }
    141 
    142         boolean res;
    143         int uid = Binder.getCallingUid();
    144         synchronized(mListeners) {
    145             res = enableSensorInternalLocked(binder, uid, name, sensor, enable);
    146             if (res == true) {
    147                 // Inform battery statistics service of status change
    148                 long identity = Binder.clearCallingIdentity();
    149                 if (enable == SENSOR_DISABLE) {
    150                     mBatteryStats.noteStopSensor(uid, sensor);
    151                 } else {
    152                     mBatteryStats.noteStartSensor(uid, sensor);
    153                 }
    154                 Binder.restoreCallingIdentity(identity);
    155             }
    156         }
    157         return res;
    158     }
    159 
    160     private boolean enableSensorInternalLocked(IBinder binder, int uid,
    161             String name, int sensor, int enable) throws RemoteException {
    162 
    163         // check if we have this listener
    164         Listener l = null;
    165         for (Listener listener : mListeners) {
    166             if (binder == listener.mToken) {
    167                 l = listener;
    168                 break;
    169             }
    170         }
    171 
    172         if (enable != SENSOR_DISABLE) {
    173             // Activate the requested sensor
    174             if (_sensors_control_activate(sensor, true) == false) {
    175                 Slog.w(TAG, "could not enable sensor " + sensor);
    176                 return false;
    177             }
    178 
    179             if (l == null) {
    180                 /*
    181                  * we don't have a listener for this binder yet, so
    182                  * create a new one and add it to the list.
    183                  */
    184                 l = new Listener(binder, uid);
    185                 binder.linkToDeath(l, 0);
    186                 mListeners.add(l);
    187                 mListeners.notify();
    188             }
    189 
    190             // take note that this sensor is now used by this client
    191             l.addSensor(sensor, enable);
    192 
    193         } else {
    194 
    195             if (l == null) {
    196                 /*
    197                  *  This client isn't in the list, this usually happens
    198                  *  when enabling the sensor failed, but the client
    199                  *  didn't handle the error and later tries to shut that
    200                  *  sensor off.
    201                  */
    202                 Slog.w(TAG, "listener with binder " + binder +
    203                         ", doesn't exist (sensor=" + name +
    204                         ", id=" + sensor + ")");
    205                 return false;
    206             }
    207 
    208             // remove this sensor from this client
    209             l.removeSensor(sensor);
    210 
    211             // see if we need to deactivate this sensors=
    212             deactivateIfUnusedLocked(sensor);
    213 
    214             // if the listener doesn't have any more sensors active
    215             // we can get rid of it
    216             if (l.mSensors == 0) {
    217                 // we won't need this death notification anymore
    218                 binder.unlinkToDeath(l, 0);
    219                 // remove the listener from the list
    220                 mListeners.remove(l);
    221                 // and if the list is empty, turn off the whole sensor h/w
    222                 if (mListeners.size() == 0) {
    223                     _sensors_control_wake();
    224                     _sensors_control_close();
    225                 }
    226                 mListeners.notify();
    227             }
    228         }
    229 
    230         // calculate and set the new delay
    231         int minDelay = 0x7FFFFFFF;
    232         for (Listener listener : mListeners) {
    233             if (listener.mDelay < minDelay)
    234                 minDelay = listener.mDelay;
    235         }
    236         if (minDelay != 0x7FFFFFFF) {
    237             mCurrentDelay = minDelay;
    238             _sensors_control_set_delay(minDelay);
    239         }
    240 
    241         return true;
    242     }
    243 
    244     private void deactivateIfUnusedLocked(int sensor) {
    245         int size = mListeners.size();
    246         for (int i=0 ; i<size ; i++) {
    247             if (mListeners.get(i).hasSensor(sensor)) {
    248                 // this sensor is still in use, don't turn it off
    249                 return;
    250             }
    251         }
    252         if (_sensors_control_activate(sensor, false) == false) {
    253             Slog.w(TAG, "could not disable sensor " + sensor);
    254         }
    255     }
    256 
    257     @Override
    258     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    259         synchronized (mListeners) {
    260             Printer pr = new PrintWriterPrinter(pw);
    261             int c = 0;
    262             pr.println(mListeners.size() + " listener(s), delay=" + mCurrentDelay + " ms");
    263             for (Listener l : mListeners) {
    264                 pr.println("listener[" + c + "] " +
    265                         "sensors=0x" + Integer.toString(l.mSensors, 16) +
    266                         ", uid=" + l.mUid +
    267                         ", delay=" +
    268                         l.mDelay + " ms");
    269                 c++;
    270             }
    271         }
    272     }
    273 
    274     private ArrayList<Listener> mListeners = new ArrayList<Listener>();
    275 
    276     private static native int _sensors_control_init();
    277     private static native Bundle _sensors_control_open();
    278     private static native int _sensors_control_close();
    279     private static native boolean _sensors_control_activate(int sensor, boolean activate);
    280     private static native int _sensors_control_set_delay(int ms);
    281     private static native int _sensors_control_wake();
    282 }
    283