说到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.java public 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 },
};