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 17package com.android.server; 18 19import android.content.Context; 20import android.hardware.ISensorService; 21import android.os.Binder; 22import android.os.Bundle; 23import android.os.RemoteException; 24import android.os.IBinder; 25import android.util.Config; 26import android.util.Log; 27 28import java.util.ArrayList; 29 30import com.android.internal.app.IBatteryStats; 31import com.android.server.am.BatteryStatsService; 32 33 34/** 35 * Class that manages the device's sensors. It register clients and activate 36 * the needed sensors. The sensor events themselves are not broadcasted from 37 * this service, instead, a file descriptor is provided to each client they 38 * can read events from. 39 */ 40 41class SensorService extends ISensorService.Stub { 42 static final String TAG = SensorService.class.getSimpleName(); 43 private static final boolean DEBUG = false; 44 private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; 45 private static final int SENSOR_DISABLE = -1; 46 47 /** 48 * Battery statistics to be updated when sensors are enabled and disabled. 49 */ 50 final IBatteryStats mBatteryStats = BatteryStatsService.getService(); 51 52 private final class Listener implements IBinder.DeathRecipient { 53 final IBinder mToken; 54 55 int mSensors = 0; 56 int mDelay = 0x7FFFFFFF; 57 58 Listener(IBinder token) { 59 mToken = token; 60 } 61 62 void addSensor(int sensor, int delay) { 63 mSensors |= (1<<sensor); 64 if (mDelay > delay) 65 mDelay = delay; 66 } 67 68 void removeSensor(int sensor) { 69 mSensors &= ~(1<<sensor); 70 } 71 72 boolean hasSensor(int sensor) { 73 return ((mSensors & (1<<sensor)) != 0); 74 } 75 76 public void binderDied() { 77 if (localLOGV) Log.d(TAG, "sensor listener died"); 78 synchronized(mListeners) { 79 mListeners.remove(this); 80 mToken.unlinkToDeath(this, 0); 81 // go through the lists of sensors used by the listener that 82 // died and deactivate them. 83 for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) { 84 if (hasSensor(sensor)) { 85 removeSensor(sensor); 86 try { 87 deactivateIfUnused(sensor); 88 } catch (RemoteException e) { 89 Log.w(TAG, "RemoteException in binderDied"); 90 } 91 } 92 } 93 mListeners.notify(); 94 } 95 } 96 } 97 98 @SuppressWarnings("unused") 99 public SensorService(Context context) { 100 if (localLOGV) Log.d(TAG, "SensorService startup"); 101 _sensors_control_init(); 102 } 103 104 public Bundle getDataChannel() throws RemoteException { 105 return _sensors_control_open(); 106 } 107 108 public boolean enableSensor(IBinder binder, String name, int sensor, int enable) 109 throws RemoteException { 110 if (localLOGV) Log.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable); 111 112 // Inform battery statistics service of status change 113 int uid = Binder.getCallingUid(); 114 long identity = Binder.clearCallingIdentity(); 115 if (enable == SENSOR_DISABLE) { 116 mBatteryStats.noteStopSensor(uid, sensor); 117 } else { 118 mBatteryStats.noteStartSensor(uid, sensor); 119 } 120 Binder.restoreCallingIdentity(identity); 121 122 if (binder == null) { 123 Log.w(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")"); 124 return false; 125 } 126 127 synchronized(mListeners) { 128 if (enable!=SENSOR_DISABLE && !_sensors_control_activate(sensor, true)) { 129 Log.w(TAG, "could not enable sensor " + sensor); 130 return false; 131 } 132 133 Listener l = null; 134 int minDelay = enable; 135 for (Listener listener : mListeners) { 136 if (binder == listener.mToken) { 137 l = listener; 138 } 139 if (minDelay > listener.mDelay) 140 minDelay = listener.mDelay; 141 } 142 143 if (l == null && enable!=SENSOR_DISABLE) { 144 l = new Listener(binder); 145 binder.linkToDeath(l, 0); 146 mListeners.add(l); 147 mListeners.notify(); 148 } 149 150 if (l == null) { 151 // by construction, this means we're disabling a listener we 152 // don't know about... 153 Log.w(TAG, "listener with binder " + binder + 154 ", doesn't exist (sensor=" + name + ", id=" + sensor + ")"); 155 return false; 156 } 157 158 if (minDelay >= 0) { 159 _sensors_control_set_delay(minDelay); 160 } 161 162 if (enable != SENSOR_DISABLE) { 163 l.addSensor(sensor, enable); 164 } else { 165 l.removeSensor(sensor); 166 deactivateIfUnused(sensor); 167 if (l.mSensors == 0) { 168 mListeners.remove(l); 169 binder.unlinkToDeath(l, 0); 170 mListeners.notify(); 171 } 172 } 173 174 if (mListeners.size() == 0) { 175 _sensors_control_wake(); 176 } 177 } 178 return true; 179 } 180 181 void deactivateIfUnused(int sensor) throws RemoteException { 182 int size = mListeners.size(); 183 for (int i=0 ; i<size ; i++) { 184 if (mListeners.get(i).hasSensor(sensor)) 185 return; 186 } 187 _sensors_control_activate(sensor, false); 188 } 189 190 ArrayList<Listener> mListeners = new ArrayList<Listener>(); 191 192 private static native int _sensors_control_init(); 193 private static native Bundle _sensors_control_open(); 194 private static native boolean _sensors_control_activate(int sensor, boolean activate); 195 private static native int _sensors_control_set_delay(int ms); 196 private static native int _sensors_control_wake(); 197} 198