SensorService.java revision 4df2423a947bcd3f024cc3d3a1a315a8dc428598
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.ParcelFileDescriptor;
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 ParcelFileDescriptor getDataChanel() 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 ParcelFileDescriptor _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