说到sensor就不得不说下电源管理,power是如此神奇,没了他所有电子产品就是一堆垃圾。
1) power(此部分参考了http://www.byywee.com/page/M0/S633/633654.html)
// Framework layer
// frameworks/base/core/java/android/os/PowerManager.java
/** * Makes sure the device is on at the level you asked when you created * the wake lock. */ public void acquire() { synchronized (mToken) { if (!mRefCounted || mCount++ == 0) { try { mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource); } catch (RemoteException e) { } mHeld = true; } } }通过binder IPC调用 ==》
// frameworks/base/services/java/com/android/server/PowerManagerService.java
public void acquireWakeLock(int flags, IBinder lock, String tag, WorkSource ws) { int uid = Binder.getCallingUid(); int pid = Binder.getCallingPid(); if (uid != Process.myUid()) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); } if (ws != null) { enforceWakeSourcePermission(uid, pid); } long ident = Binder.clearCallingIdentity(); try { synchronized (mLocks) { acquireWakeLockLocked(flags, lock, uid, pid, tag, ws); } } finally { Binder.restoreCallingIdentity(ident); } }
public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag, WorkSource ws) { if (mSpew) { Slog.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag); } if (ws != null && ws.size() == 0) { ws = null; } int index = mLocks.getIndex(lock); WakeLock wl; boolean newlock; boolean diffsource; WorkSource oldsource; if (index < 0) { wl = new WakeLock(flags, lock, tag, uid, pid); switch (wl.flags & LOCK_MASK) { case PowerManager.FULL_WAKE_LOCK: if (mUseSoftwareAutoBrightness && !FEATURE_ALIGN_BKL_ENABLED) { wl.minState = SCREEN_BRIGHT; } else { wl.minState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT); } break; case PowerManager.SCREEN_BRIGHT_WAKE_LOCK: wl.minState = SCREEN_BRIGHT; break; case PowerManager.SCREEN_DIM_WAKE_LOCK: wl.minState = SCREEN_DIM; break; case PowerManager.PARTIAL_WAKE_LOCK: case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK: break; default: // just log and bail. we're in the server, so don't // throw an exception. Slog.e(TAG, "bad wakelock type for lock '" + tag + "' " + " flags=" + flags); return; } mLocks.addLock(wl); if (ws != null) { wl.ws = new WorkSource(ws); } newlock = true; diffsource = false; oldsource = null; } else { wl = mLocks.get(index); newlock = false; oldsource = wl.ws; if (oldsource != null) { if (ws == null) { wl.ws = null; diffsource = true; } else { diffsource = oldsource.diff(ws); } } else if (ws != null) { diffsource = true; } else { diffsource = false; } if (diffsource) { wl.ws = new WorkSource(ws); } } if (isScreenLock(flags)) { // if this causes a wakeup, we reactivate all of the locks and // set it to whatever they want. otherwise, we modulate that // by the current state so we never turn it more on than // it already is. if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) { mProximityWakeLockCount++; if (mProximityWakeLockCount == 1) { enableProximityLockLocked(); } } else { if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) { int oldWakeLockState = mWakeLockState; mWakeLockState = mLocks.reactivateScreenLocksLocked(); if (mSpew) { Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState) + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState) + " previous wakeLockState=0x" + Integer.toHexString(oldWakeLockState)); } } else { if (mSpew) { Slog.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState) + " mLocks.gatherState()=0x" + Integer.toHexString(mLocks.gatherState()) + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)); } mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState(); } setPowerState(mWakeLockState | mUserState); } } else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) { if (newlock) { mPartialCount++; if (mPartialCount == 1) { if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 1, tag); } } Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME); } if (diffsource) { // If the lock sources have changed, need to first release the // old ones. noteStopWakeLocked(wl, oldsource); } if (newlock || diffsource) { noteStartWakeLocked(wl, ws); } //Add for WakeLockDebugTool if (mIsWakeLockBGDbgModeRunning) { getDynamicWakeLockLocked(wl, true); } }
通过Power.acquireWakeLock调用JNINativerMethod.
// JNI layer
//frameworks/base/core/jni/android_os_Power.cpp
static void acquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj) { if (idObj == NULL) { throw_NullPointerException(env, "id is null"); return ; } const char *id = env->GetStringUTFChars(idObj, NULL); acquire_wake_lock(lock, id); env->ReleaseStringUTFChars(idObj, id); }
static JNINativeMethod method_table[] = { { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock }, { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock }, { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout }, { "setScreenState", "(Z)I", (void*)setScreenState }, { "shutdown", "()V", (void*)android_os_Power_shutdown }, { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot }, };以上数据结构可以参照 Android JNI 使用的数据结构JNINativeMethod详解
// HAL layer
//hardware/libhardware_legacy/power/power.c
int acquire_wake_lock(int lock, const char* id) { initialize_fds(); // LOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id); if (g_error) return g_error; int fd; if (lock == PARTIAL_WAKE_LOCK) { fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK]; } else { return EINVAL; } return write(fd, id, strlen(id)); }
const char * const OLD_PATHS[] = { "/sys/android_power/acquire_partial_wake_lock", "/sys/android_power/release_wake_lock", "/sys/android_power/request_state" }; const char * const NEW_PATHS[] = { "/sys/power/wake_lock", "/sys/power/wake_unlock", "/sys/power/state" }; static inline void initialize_fds(void) { // XXX: should be this: //pthread_once(&g_initialized, open_file_descriptors); // XXX: not this: if (g_initialized == 0) { if(open_file_descriptors(NEW_PATHS) < 0) { open_file_descriptors(OLD_PATHS); on_state = "wake"; off_state = "standby"; } g_initialized = 1; } }
//kernel layer
//kernel/kernel/power/power.h
#define power_attr(_name) \ static struct kobj_attribute _name##_attr = { \ .attr = { \ .name = __stringify(_name), \ .mode = 0644, \ }, \ .show = _name##_show, \ .store = _name##_store, \ }
//kernel/kernel/power/main.c
power_attr(wake_lock);
static struct attribute * g[] = { &state_attr.attr, #ifdef CONFIG_PM_TRACE &pm_trace_attr.attr, #endif #ifdef CONFIG_PM_SLEEP &pm_async_attr.attr, #ifdef CONFIG_PM_DEBUG &pm_test_attr.attr, #endif #ifdef CONFIG_USER_WAKELOCK &wake_lock_attr.attr, &wake_unlock_attr.attr, #endif #endif NULL, }; static struct attribute_group attr_group = { .attrs = g, };
static int __init pm_init(void) { int error = pm_start_workqueue(); if (error) return error; power_kobj = kobject_create_and_add("power", NULL); if (!power_kobj) return -ENOMEM; return sysfs_create_group(power_kobj, &attr_group); } core_initcall(pm_init);看到没,电源管理的初始化就是在这里开始的core_initcall
//kernel/kernel/power/userwakelock.c
ssize_t wake_lock_store( struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { long timeout; struct user_wake_lock *l; mutex_lock(&tree_lock); // We allocate it l = lookup_wake_lock_name(buf, 1, &timeout); if (IS_ERR(l)) { n = PTR_ERR(l); goto bad_name; } if (Userwakelock_debug_mask & DEBUG_ACCESS) pr_info("[wake_lock_store]: %s, timeout %ld\n", l->name, timeout); // check if timeout wakelock or infinit wake lock if (timeout) wake_lock_timeout(&l->wake_lock, timeout); else wake_lock(&l->wake_lock); bad_name: mutex_unlock(&tree_lock); return n; }
可以看出无论是wake_lock_timeout抑或是wake_lock都会调用wake_lock_internal.
void wake_lock(struct wake_lock *lock) { wake_lock_internal(lock, 0, 0); } EXPORT_SYMBOL(wake_lock); void wake_lock_timeout(struct wake_lock *lock, long timeout) { if (wakelock_debug_mask & DEBUG_WAKE_LOCK) pr_info("[wake_lock_timeout] wakeup wake lock: %s timeout: %d\n", lock->name, (int)timeout); wake_lock_internal(lock, timeout, 1); } EXPORT_SYMBOL(wake_lock_timeout);
static void wake_lock_internal( struct wake_lock *lock, long timeout, int has_timeout) { int type; unsigned long irqflags; long expire_in; spin_lock_irqsave(&list_lock, irqflags); type = lock->flags & WAKE_LOCK_TYPE_MASK; BUG_ON(type >= WAKE_LOCK_TYPE_COUNT); BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED)); #ifdef CONFIG_WAKELOCK_STAT if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) { if (wakelock_debug_mask & DEBUG_WAKEUP) pr_info("[wake_lock_internal] wakeup wake lock: %s\n", lock->name); wait_for_wakeup = 0; lock->stat.wakeup_count++; } if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) && (long)(lock->expires - jiffies) <= 0) { wake_unlock_stat_locked(lock, 0); lock->stat.last_time = ktime_get(); } #endif if (!(lock->flags & WAKE_LOCK_ACTIVE)) { lock->flags |= WAKE_LOCK_ACTIVE; #ifdef CONFIG_WAKELOCK_STAT lock->stat.last_time = ktime_get(); #endif } list_del(&lock->link); // acquire a timeout wakelock if (has_timeout) { if (wakelock_debug_mask & DEBUG_WAKE_LOCK) pr_info("[wake_lock_internal]: %s, type %d, timeout %ld.%03lu\n", lock->name, type, timeout / HZ, (timeout % HZ) * MSEC_PER_SEC / HZ); lock->expires = jiffies + timeout; lock->flags |= WAKE_LOCK_AUTO_EXPIRE; list_add_tail(&lock->link, &active_wake_locks[type]); } // acquire a non-timeout wakelock else { if (wakelock_debug_mask & DEBUG_WAKE_LOCK) pr_info("[wake_lock_internal]: %s, type %d\n", lock->name, type); lock->expires = LONG_MAX; lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE; list_add(&lock->link, &active_wake_locks[type]); } if (type == WAKE_LOCK_SUSPEND) { current_event_num++; #ifdef CONFIG_WAKELOCK_STAT if (lock == &main_wake_lock) update_sleep_wait_stats_locked(1); else if (!wake_lock_active(&main_wake_lock)) update_sleep_wait_stats_locked(0); #endif if (has_timeout) expire_in = has_wake_lock_locked(type); else expire_in = -1; if (expire_in > 0) { if (debug_mask & DEBUG_EXPIRE) pr_info("wake_lock: %s, start expire timer, " "%ld\n", lock->name, expire_in); //modify the time wakelock is expired mod_timer(&expire_timer, jiffies + expire_in); } else { if (del_timer(&expire_timer)) if (debug_mask & DEBUG_EXPIRE) pr_info("wake_lock: %s, stop expire timer\n", lock->name); if (expire_in == 0) { pr_info("[wake_lock]: suspend_work_queue suspend_work\n "); queue_work(suspend_work_queue, &suspend_work); } } } spin_unlock_irqrestore(&list_lock, irqflags); }
看到这里调用个suspend_work,其实就是就是调用
#define DECLARE_WORK(n, f) \ struct work_struct n = __WORK_INITIALIZER(n, f)
#define __WORK_INITIALIZER(n, f) { \ .data = WORK_DATA_STATIC_INIT(), \ .entry = { &(n).entry, &(n).entry }, \ .func = (f), \ __WORK_INIT_LOCKDEP_MAP(#n, &(n)) \ }
static void suspend(struct work_struct *work) { int ret; int entry_event_num; // there are still some wakelock if (has_wake_lock(WAKE_LOCK_SUSPEND)) { if (wakelock_debug_mask & DEBUG_SUSPEND) pr_info("[suspend]: abort suspend\n"); return; } entry_event_num = current_event_num; sys_sync(); if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: enter suspend\n"); ret = pm_suspend(requested_suspend_state); if (debug_mask & DEBUG_EXIT_SUSPEND) { struct timespec ts; struct rtc_time tm; getnstimeofday(&ts); rtc_time_to_tm(ts.tv_sec, &tm); pr_info("suspend: exit suspend, ret = %d " "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec); } if (current_event_num == entry_event_num) { if (debug_mask & DEBUG_SUSPEND) pr_info("suspend: pm_suspend returned with no event\n"); wake_lock_timeout(&unknown_wakeup, HZ / 2); } } static DECLARE_WORK(suspend_work, suspend);
2) sensor(此部分参考http://blog.csdn.net/qianjin0703/article/details/7568641,啧啧,这类图画得真赞)
下面以距离传感器来分析:
//App layer
// packages\apps\CIT\src\sim\android\cit\ProximitySenor.java
@Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.test_proximitysenor); initAllControl(); mtv_pro_info.setText(strPromityinfo); mSensorManager = (SensorManager) getSystemService("sensor"); mProimitySensor = mSensorManager.getDefaultSensor(8); }
/** * Use this method to get the default sensor for a given type. Note that the * returned sensor could be a composite sensor, and its data could be * averaged or filtered. If you need to access the raw sensors use * {@link SensorManager#getSensorList(int) getSensorList}. * * @param type * of sensors requested * * @return the default sensors matching the asked type. * * @see #getSensorList(int) * @see Sensor */ public Sensor getDefaultSensor(int type) { // TODO: need to be smarter, for now, just return the 1st sensor List<Sensor> l = getSensorList(type); return l.isEmpty() ? null : l.get(0); }//framework layer
// 看看SensorManage的构造函数(JAVA里面是这么称呼?)
//frameworks/base/core/java/android/hardware/SensorManager.javapublic SensorManager(Looper mainLooper) { mMainLooper = mainLooper; synchronized(sListeners) { if (!sSensorModuleInitialized) { sSensorModuleInitialized = true; nativeClassInit(); sWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService("window")); if (sWindowManager != null) { // if it's null we're running in the system process // which won't get the rotated values try { sRotation = sWindowManager.watchRotation( new IRotationWatcher.Stub() { public void onRotationChanged(int rotation) { SensorManager.this.onRotationChanged(rotation); } } ); } catch (RemoteException e) { } } // initialize the sensor list sensors_module_init(); final ArrayList<Sensor> fullList = sFullSensorsList; int i = 0; do { Sensor sensor = new Sensor(); i = sensors_module_get_next_sensor(sensor, i); if (i>=0) { //Log.d(TAG, "found sensor: " + sensor.getName() + // ", handle=" + sensor.getHandle()); sensor.setLegacyType(getLegacySensorType(sensor.getType())); fullList.add(sensor); sHandleToSensor.append(sensor.getHandle(), sensor); } } while (i>0); sSensorThread = new SensorThread(); } } }
这里调用了==》JNINative方法
//HAL layer
/* * The method below are not thread-safe and not intended to be */ static jint sensors_module_init(JNIEnv *env, jclass clazz) { SensorManager::getInstance(); return 0; } static jint sensors_module_get_next_sensor(JNIEnv *env, jobject clazz, jobject sensor, jint next) { SensorManager& mgr(SensorManager::getInstance()); Sensor const* const* sensorList; size_t count = mgr.getSensorList(&sensorList); if (size_t(next) >= count) return -1; Sensor const* const list = sensorList[next]; const SensorOffsets& sensorOffsets(gSensorOffsets); jstring name = env->NewStringUTF(list->getName().string()); jstring vendor = env->NewStringUTF(list->getVendor().string()); env->SetObjectField(sensor, sensorOffsets.name, name); env->SetObjectField(sensor, sensorOffsets.vendor, vendor); env->SetIntField(sensor, sensorOffsets.version, 1); env->SetIntField(sensor, sensorOffsets.handle, list->getHandle()); env->SetIntField(sensor, sensorOffsets.type, list->getType()); env->SetFloatField(sensor, sensorOffsets.range, list->getMaxValue()); env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution()); env->SetFloatField(sensor, sensorOffsets.power, list->getPowerUsage()); env->SetIntField(sensor, sensorOffsets.minDelay, list->getMinDelay()); next++; return size_t(next) < count ? next : 0; } //---------------------------------------------------------------------------- static jint sensors_create_queue(JNIEnv *env, jclass clazz) { SensorManager& mgr(SensorManager::getInstance()); sp<SensorEventQueue> queue(mgr.createEventQueue()); queue->incStrong(clazz); return reinterpret_cast<int>(queue.get()); } static void sensors_destroy_queue(JNIEnv *env, jclass clazz, jint nativeQueue) { sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue)); if (queue != 0) { queue->decStrong(clazz); } } static jboolean sensors_enable_sensor(JNIEnv *env, jclass clazz, jint nativeQueue, jstring name, jint sensor, jint delay) { sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue)); if (queue == 0) return JNI_FALSE; status_t res; if (delay >= 0) { res = queue->enableSensor(sensor, delay); } else { res = queue->disableSensor(sensor); } return res == NO_ERROR ? true : false; } static jint sensors_data_poll(JNIEnv *env, jclass clazz, jint nativeQueue, jfloatArray values, jintArray status, jlongArray timestamp) { sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue)); if (queue == 0) return -1; status_t res; ASensorEvent event; res = queue->read(&event, 1); if (res == -EAGAIN) { res = queue->waitForEvent(); if (res != NO_ERROR) return -1; res = queue->read(&event, 1); } if (res < 0) return -1; jint accuracy = event.vector.status; env->SetFloatArrayRegion(values, 0, 3, event.vector.v); env->SetIntArrayRegion(status, 0, 1, &accuracy); env->SetLongArrayRegion(timestamp, 0, 1, &event.timestamp); return event.sensor; } static void nativeClassInit (JNIEnv *_env, jclass _this) { jclass sensorClass = _env->FindClass("android/hardware/Sensor"); SensorOffsets& sensorOffsets = gSensorOffsets; sensorOffsets.name = _env->GetFieldID(sensorClass, "mName", "Ljava/lang/String;"); sensorOffsets.vendor = _env->GetFieldID(sensorClass, "mVendor", "Ljava/lang/String;"); sensorOffsets.version = _env->GetFieldID(sensorClass, "mVersion", "I"); sensorOffsets.handle = _env->GetFieldID(sensorClass, "mHandle", "I"); sensorOffsets.type = _env->GetFieldID(sensorClass, "mType", "I"); sensorOffsets.range = _env->GetFieldID(sensorClass, "mMaxRange", "F"); sensorOffsets.resolution = _env->GetFieldID(sensorClass, "mResolution","F"); sensorOffsets.power = _env->GetFieldID(sensorClass, "mPower", "F"); sensorOffsets.minDelay = _env->GetFieldID(sensorClass, "mMinDelay", "I"); } static JNINativeMethod gMethods[] = { {"nativeClassInit", "()V", (void*)nativeClassInit }, {"sensors_module_init","()I", (void*)sensors_module_init }, {"sensors_module_get_next_sensor","(Landroid/hardware/Sensor;I)I", (void*)sensors_module_get_next_sensor }, {"sensors_create_queue", "()I", (void*)sensors_create_queue }, {"sensors_destroy_queue", "(I)V", (void*)sensors_destroy_queue }, {"sensors_enable_sensor", "(ILjava/lang/String;II)Z", (void*)sensors_enable_sensor }, {"sensors_data_poll", "(I[F[I[J)I", (void*)sensors_data_poll }, };