学习参考文档:https://www.cnblogs.com/haiming/p/3318614.html
handler: https://www.jianshu.com/p/2e431a870ba5
1.抓log看到以下以下关键字–‘‘SAFE MODE ENABLED’’
源码位置如下:
路径:framework/base/services/core/java/com/android/server/wm/WindowManagerService.java
int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
KeyEvent.KEYCODE_MENU);
int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
KeyEvent.KEYCODE_DPAD_CENTER);
int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
InputManagerService.BTN_MOUSE);
int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
KeyEvent.KEYCODE_VOLUME_DOWN);
mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
|| volumeDownState > 0;
try {
if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0
|| SystemProperties.getInt(ShutdownThread.RO_SAFEMODE_PROPERTY, 0) != 0) {
mSafeMode = true;
SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
}
} catch (IllegalArgumentException e) {
}
if (mSafeMode) {
Log.i(TAG_WM, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
+ " dpad=" + dpadState + " trackball=" + trackballState + ")");
SystemProperties.set(ShutdownThread.RO_SAFEMODE_PROPERTY, "1");
} else {
Log.i(TAG_WM, "SAFE MODE not enabled");
}
未进入safe mode会打印如下log:
02-05 12:46:23.792758 709 709 I WindowManager: SAFE MODE not enabled
流程分析:
SAFE MODE ENABLED (menu=1 ...导致进入了safemode ,
- menuState 的值由此方法获取
public static final int SOURCE_ANY = 0xffffff00;
frameworks/base/core/java/android/view/KeyEvent.java:271: public static final int KEYCODE_MENU = 82;
int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
KeyEvent.KEYCODE_MENU);
1.frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
mInputManager.getKeyCodeState() -
2.frameworks/base/service/core/java/com/android/server/input/InputManagerServer.java
/**
* Gets the current state of a key or button by key code.
* @param deviceId The input device id, or -1 to consult all devices.
* @param sourceMask The input sources to consult, or {@link InputDevice#SOURCE_ANY} to
* consider all input sources. An input device is consulted if at least one of its
* non-class input source bits matches the specified source mask.
* @param keyCode The key code to check.
* @return The key state.
*/
public int getKeyCodeState(int deviceId, int sourceMask, int keyCode) {
return nativeGetKeyCodeState(mPtr, deviceId, sourceMask, keyCode);
}
3.frameworks/base/service/core/jni/com_android_server_input_InputManagerServer.cpp
static jint nativeGetKeyCodeState(JNIEnv* /* env */, jclass /* clazz */,
jlong ptr, jint deviceId, jint sourceMask, jint keyCode) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
return (jint) im->getInputManager()->getReader()->getKeyCodeState(
deviceId, uint32_t(sourceMask), keyCode);
}
4.frameworks/native/service/inputflinger/InputManager.java
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
sp<InputReaderInterface> InputManager::getReader() {
return mReader;
}
5.frameworks/native/service/inputflinger/InputRead.java
int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
int32_t keyCode) {
AutoMutex _l(mLock);
return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState);
}
//当fd 小于0时,会遍历所有设备
int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code,
GetStateFunc getStateFunc) {
int32_t result = AKEY_STATE_UNKNOWN;
if (deviceId >= 0) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex >= 0) {
InputDevice* device = mDevices.valueAt(deviceIndex);
if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
result = (device->*getStateFunc)(sourceMask, code);
}
}
} else {
size_t numDevices = mDevices.size();
for (size_t i = 0; i < numDevices; i++) {
InputDevice* device = mDevices.valueAt(i);
if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
// If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
// value. Otherwise, return AKEY_STATE_UP as long as one device reports it.
int32_t currentResult = (device->*getStateFunc)(sourceMask, code);
if (currentResult >= AKEY_STATE_DOWN) {
return currentResult;
} else if (currentResult == AKEY_STATE_UP) {
result = currentResult;
}
}
}
}
return result;
}
题外基础知识补充:
------
Handler 用于消息接收,eg:安卓的UI更新只允许在主线程(ui线程)中更新,子线程通过消息发送给主线程的handler接收以达到更新ui的目的
InputFlinger-> inputDevice 用来描述这个device是kayboard还是touch
InputDevice* device
//frameworks/base/services/java/com/android/server/SystemServer.java
1.实例化inputManagerService
2.调用InputManagerService.start->inputflinger中 InputManager.start->启动inputflinger下Inputdispatcher和InputReadder线程
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);
traceEnd();
.....
traceBeginAndSlog("StartInputManager");
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();
traceEnd();
//frameworks/base/services/core/java/com/android/server/input/InputManagerService.jav
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
return reinterpret_cast<jlong>(im); //强转nativeInputManager实例
}
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
mLocked.pointerCapture = false;
}
mInteractive = true;
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
//frameworks/native/services/inputflinger/EventHub.cpp
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(0), mClosingDevices(0),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
mEpollFd = epoll_create(EPOLL_SIZE_HINT); //创建epoll
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno);
mINotifyFd = inotify_init(); //创建notify fd
int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);//指定notify fd监听的路径
LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d",
DEVICE_PATH, errno);
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
eventItem.data.u32 = EPOLL_ID_INOTIFY;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);//讲notify fd放入epoll中监听
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
int wakeFds[2];
result = pipe(wakeFds); //创建管道
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
eventItem.data.u32 = EPOLL_ID_WAKE;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);//监听匿名管道读取的fd
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
int major, minor;
getLinuxRelease(&major, &minor);//获取linux版本
// EPOLLWAKEUP was introduced in kernel 3.5
mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
//frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager( //走了三个参数的构造函数
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
InputManager::InputManager(
const sp<InputReaderInterface>& reader,
const sp<InputDispatcherInterface>& dispatcher) :
mReader(reader),
mDispatcher(dispatcher) {
initialize();
}
//实例化这两个线程
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
//frameworks/native/services/inputflinger/InputDispatcher.cpp
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
/// M:PerfBoost init @{
void *handle, *func;
/// @}
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
/// M:PerfBoost init @{
handle = dlopen(LIB_FULL_NAME, RTLD_NOW);
func = dlsym(handle, "PowerHal_TouchBoost");
powerTouchBoost = reinterpret_cast<boost>(func);
if (powerTouchBoost == NULL) {
ALOGE("PowerHal_TouchBoost init fail!");
}
/// @}
}
inputDispatcher回调com_android_server_input_InputManagerService--------->
从代码上看,只是从java层获取keyrepeattime 和 keyrepeatdelay两个参数
//frameworks/base/service/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
jint keyRepeatTimeout = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getKeyRepeatTimeout);
if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);
}
jint keyRepeatDelay = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getKeyRepeatDelay);
if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
}
}
com_android_server_input_InputManagerService.cpp回调InputManagerService.java--------->
// Native callback.
private int getKeyRepeatTimeout() {
return ViewConfiguration.getKeyRepeatTimeout();
}
// Native callback.
private int getKeyRepeatDelay() {
return ViewConfiguration.getKeyRepeatDelay();
}
// --- InputDispatcherThread ---
InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
//frameworks/native/services/inputflinger/InputReader.cpp
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
void InputReader::refreshConfigurationLocked(uint32_t changes) {
mPolicy->getReaderConfiguration(&mConfig);
mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
if (changes) { //first time params is 0,不做任何事
ALOGI("Reconfiguring input devices. changes=0x%08x", changes);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
mEventHub->requestReopenDevices();
} else {
for (size_t i = 0; i < mDevices.size(); i++) {
InputDevice* device = mDevices.valueAt(i);
device->configure(now, &mConfig, changes);
}
}
}
}
//初始化mExcludedDevices
void EventHub::setExcludedDevices(const Vector<String8>& devices) {
AutoMutex _l(mLock);
mExcludedDevices = devices;
}
------>InputRead回调com_android_server_input_InputManagerService.java获取一些参数
void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outConfig) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
jint virtualKeyQuietTime = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getVirtualKeyQuietTimeMillis);
if (!checkAndClearExceptionFromCallback(env, "getVirtualKeyQuietTimeMillis")) {
outConfig->virtualKeyQuietTime = milliseconds_to_nanoseconds(virtualKeyQuietTime);
}
outConfig->excludedDeviceNames.clear();
jobjectArray excludedDeviceNames = jobjectArray(env->CallObjectMethod(mServiceObj,
gServiceClassInfo.getExcludedDeviceNames));
if (!checkAndClearExceptionFromCallback(env, "getExcludedDeviceNames") && excludedDeviceNames) {
jsize length = env->GetArrayLength(excludedDeviceNames);
for (jsize i = 0; i < length; i++) {
jstring item = jstring(env->GetObjectArrayElement(excludedDeviceNames, i));
const char* deviceNameChars = env->GetStringUTFChars(item, NULL);
outConfig->excludedDeviceNames.add(String8(deviceNameChars));
env->ReleaseStringUTFChars(item, deviceNameChars);
env->DeleteLocalRef(item);
}
env->DeleteLocalRef(excludedDeviceNames);
}
jint hoverTapTimeout = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getHoverTapTimeout);
if (!checkAndClearExceptionFromCallback(env, "getHoverTapTimeout")) {
jint doubleTapTimeout = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getDoubleTapTimeout);
if (!checkAndClearExceptionFromCallback(env, "getDoubleTapTimeout")) {
jint longPressTimeout = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getLongPressTimeout);
if (!checkAndClearExceptionFromCallback(env, "getLongPressTimeout")) {
outConfig->pointerGestureTapInterval = milliseconds_to_nanoseconds(hoverTapTimeout);
// We must ensure that the tap-drag interval is significantly shorter than
// the long-press timeout because the tap is held down for the entire duration
// of the double-tap timeout.
jint tapDragInterval = max(min(longPressTimeout - 100,
doubleTapTimeout), hoverTapTimeout);
outConfig->pointerGestureTapDragInterval =
milliseconds_to_nanoseconds(tapDragInterval);
}
}
}
jint hoverTapSlop = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getHoverTapSlop);
if (!checkAndClearExceptionFromCallback(env, "getHoverTapSlop")) {
outConfig->pointerGestureTapSlop = hoverTapSlop;
}
{ // acquire lock
AutoMutex _l(mLock);
outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed
* POINTER_SPEED_EXPONENT);
outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled;
outConfig->showTouches = mLocked.showTouches;
outConfig->pointerCapture = mLocked.pointerCapture;
outConfig->setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL,
mLocked.internalViewport);
outConfig->setPhysicalDisplayViewport(ViewportType::VIEWPORT_EXTERNAL,
mLocked.externalViewport);
outConfig->setVirtualDisplayViewports(mLocked.virtualViewports);
outConfig->disabledDevices = mLocked.disabledInputDevices;
} // release lock
}
void InputReader::updateGlobalMetaStateLocked() {
mGlobalMetaState = 0;
for (size_t i = 0; i < mDevices.size(); i++) {
InputDevice* device = mDevices.valueAt(i);
mGlobalMetaState |= device->getMetaState();
}
}
// --- InputReaderThread ---
InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}