版本信息:
Linux 3.10
Android 4.4
http://blog.csdn.net/u013686019/article/details/53691879
Android休眠在framework的处理涉及两个系统服务,InputManagerService和PowerManagerService。InputManagerService负责处理PowerKey产生的Input事件,根据事件类型调用PowerManagerService的休眠、唤醒接口:
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
if (wmActions & WM_ACTION_GO_TO_SLEEP) {
ALOGD("handleInterceptActions: Going to sleep.");
android_server_PowerManagerService_goToSleep(when);
}
if (wmActions & WM_ACTION_WAKE_UP) {
ALOGD("handleInterceptActions: Waking up.");
android_server_PowerManagerService_wakeUp(when);
}
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}
PowerManagerService执行具体的休眠、唤醒动作:
private void goToSleepInternal(long eventTime, int reason) {
Slog.i(TAG, "goToSleepInternal, reason: " + reason);
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason)) {
updatePowerStateLocked();
}
}
}
}
private void updatePowerStateLocked() {
// Phase 0: Basic state updates.
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
// Phase 2: Update dreams and display power state.
// Phase 3: Send notifications, if needed.
// Phase 4: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
updateSuspendBlockerLocked();
}
它们之间关系如下图:
由于这两个服务涉及framework最核心的功能且其代码实现繁复,这里只贴出其处理流程,具体细节其他篇幅再续。本篇目的:始知此事要躬行,如果有意弄清流程,提供一个参照。
1、InputManagerService服务加载:
SystemServer.java (frameworks\base\services\java\com\android\server)
InputManagerService inputManager = null;
inputManager = new InputManagerService(context, wmHandler);
inputManager.start();
InputManagerService.java (frameworks\base\services\java\com\android\server\input)
public class InputManagerService {
public InputManagerService(Context context, Handler handler) {
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
}
}
com_android_server_input_InputManagerService.cpp (frameworks\base\services\jni)
static jint nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast(im);
}
NativeInputManager::NativeInputManager(jobject contextObj,jobject serviceObj, const sp& looper) :
mLooper(looper) {
mInputManager = new InputManager(eventHub, this, this);
}
InputManager.cpp (frameworks\base\services\input)
InputManager::InputManager(
const sp& eventHub,
const sp& readerPolicy,
const sp& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
// InputReaderThread:事件读取
// InputDispatcherThread:事件分发
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
return OK;
}
InputReader.cpp (frameworks\base\services\input)
InputReaderThread::InputReaderThread(const sp& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputDispatcher.cpp (frameworks\base\services\input)
InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
InputReader.cpp (frameworks\base\services\input)
void InputReader::loopOnce() {
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
if (count) {
processEventsLocked(mEventBuffer, count);
}
} // release lock
}
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
ALOGD("BatchSize: %d Count: %d", batchSize, count);
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
}
}
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
InputDevice* device = mDevices.valueAt(deviceIndex);
device->process(rawEvents, count);
}
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
ALOGD("InputDevice::process");
size_t numMappers = mMappers.size();
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld",
rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value,
rawEvent->when);
if (mDropUntilNextSync) {
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
} else {
ALOGD("InputDevice::process else");
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
}
}
}
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
ALOGI("KeyboardInputMapper::process");
switch (rawEvent->type) {
case EV_KEY: {// #define EV_KEY 0x01
int32_t scanCode = rawEvent->code;
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) {
int32_t keyCode;
uint32_t flags;
processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
}
break;
}
}
}
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
int32_t scanCode, uint32_t policyFlags) {
// processkey, down=1, keyCode=26, policyFlags=1
ALOGI("processkey, down=%d, keyCode=%d, policyFlags=%d, ", down, keyCode, policyFlags);
if (down) {
// Rotate key codes according to orientation if needed.
}
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
getListener()->notifyKey(&args);
}
InputListener.cpp (frameworks\base\services\input)
void NotifyKeyArgs::notify(const sp& listener) const {
ALOGD("notify");
listener->notifyKey(this);
}
InputDispatcher.cpp (frameworks\base\services\input)
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
args->eventTime, args->deviceId, args->source, args->policyFlags,
args->action, args->flags, args->keyCode, args->scanCode,
args->metaState, args->downTime);
if (!validateKeyEvent(args->action)) {
return;
}
uint32_t policyFlags = args->policyFlags;
int32_t flags = args->flags;
int32_t metaState = args->metaState;
KeyEvent event;
event.initialize(args->deviceId, args->source, args->action,
flags, args->keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
}
com_android_server_input_InputManagerService.cpp (frameworks\base\services\jni)
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
ALOGD("interceptKeyBeforeQueueing: policyFlags = %d\n", policyFlags);
if ((policyFlags & POLICY_FLAG_TRUSTED)) {
nsecs_t when = keyEvent->getEventTime();
bool isScreenOn = this->isScreenOn();
bool isScreenBright = this->isScreenBright();
JNIEnv* env = jniEnv();
jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
jint wmActions;
if (keyEventObj) {
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj, policyFlags, isScreenOn);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
android_view_KeyEvent_recycle(env, keyEventObj);
env->DeleteLocalRef(keyEventObj);
}
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
}
}
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
if (wmActions & WM_ACTION_GO_TO_SLEEP) {
ALOGD("handleInterceptActions: Going to sleep.");
android_server_PowerManagerService_goToSleep(when);
}
if (wmActions & WM_ACTION_WAKE_UP) {
ALOGD("handleInterceptActions: Waking up.");
android_server_PowerManagerService_wakeUp(when);
}
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
ALOGD("handleInterceptActions: Not passing key to user.");
}
}
com_android_server_power_PowerManagerService.cpp (frameworks\base\services\jni)
void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
if (gPowerManagerServiceObj) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->CallVoidMethod(gPowerManagerServiceObj,
gPowerManagerServiceClassInfo.goToSleepFromNative,
nanoseconds_to_milliseconds(eventTime), 0);
checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
}
}
PowerManagerService.java (frameworks\base\services\java\com\android\server\power)
private void goToSleepFromNative(long eventTime, int reason) {
Slog.i(TAG, "goToSleepFromNative, reason: " + reason);
if (reason != PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN
&& reason != PowerManager.GO_TO_SLEEP_REASON_TIMEOUT) {
if (mDisplayManager.isWfdConnect()) {
mHandler.sendEmptyMessage(MSG_DISABLE_WIFI_FOR_WIFIP2P);
return;
}
}
goToSleepInternal(eventTime, reason);
}
private void goToSleepInternal(long eventTime, int reason) {
Slog.i(TAG, "goToSleepInternal, reason: " + reason);
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason)) {
updatePowerStateLocked();
}
}
}
}
/**
* This is the main function that performs power state transitions.
* We centralize them here so that we can recompute the power state completely
* each time something important changes, and ensure that we do it the same
* way each time. The point is to gather all of the transition logic here.
*/
private void updatePowerStateLocked() {
// Phase 0: Basic state updates.
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
// Phase 2: Update dreams and display power state.
// Phase 3: Send notifications, if needed.
// Phase 4: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
updateSuspendBlockerLocked();
}
/**
* Updates the suspend blocker that keeps the CPU alive.
*/
private void updateSuspendBlockerLocked() {
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.acquire();
mHoldingWakeLockSuspendBlocker = true;
}
if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.acquire();
mHoldingDisplaySuspendBlocker = true;
}
// Then release suspend blockers if needed.
if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
mWakeLockSuspendBlocker.release();
mHoldingWakeLockSuspendBlocker = false;
}
if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
}
至于锁释放是如何和内核交互的,参见: