[Android 13]Input系列--InputFlinger的启动

这篇具有很好参考价值的文章主要介绍了[Android 13]Input系列--InputFlinger的启动。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

hongxi.zhu 2023-7-11
Android T

服务的启动

frameworks/base/services/java/com/android/server/SystemServer.java

    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
        t.traceBegin("startOtherServices");
        ...
        WindowManagerService wm = null;
    	InputManagerService inputManager = null;

        try {
        	//1. 获取InputManagerService,并走初始化inputManager流程
        	...
    	    t.traceBegin("StartInputManagerService");
            inputManager = new InputManagerService(context);
            t.traceEnd();
			...
			//2. WindowManagerService服务持有inputManager对象
            t.traceBegin("StartWindowManagerService");
            wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
                    new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
           	...
           	//3. 向ServiceManager注册java层ims服务,name = "input",(native层的服务name = "inputflinger")
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
                    /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            t.traceEnd();

			...
			//4. 启动inputflinger,处理输入事件
            t.traceBegin("StartInputManager");
            inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
            inputManager.start();
            t.traceEnd();
            ...
        } catch (Throwable e) {
			...
        }
  1. 获取InputManagerService,并走初始化inputManager(java层和native层)流程
  2. WindowManagerService服务构造时传入inputManager对象,用户wms和ims交互
  3. 向ServiceManager注册java层ims服务
  4. 启动inputflinger,处理输入事件

我们重点看下1和4

1. 初始化InputFlinger

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

    public InputManagerService(Context context) {
        this(new Injector(context, DisplayThread.get().getLooper()));
    }

    @VisibleForTesting
    InputManagerService(Injector injector) {
		...
        mContext = injector.getContext();
        mHandler = new InputManagerHandler(injector.getLooper());  //创建一个handle(使用DisplayThread,这个线程用户wms,display,input三个服务使用,对延迟敏感)
        mNative = injector.getNativeService(this);  //创建native input服务(NativeInputManagerService)
		...
        injector.registerLocalService(new LocalService());  //将InputManagerService中的InputManagerInternal实现类加入LocalServices,供同进程其他服务调用相关功能
    }

    @VisibleForTesting
    static class Injector {
        private final Context mContext;
        private final Looper mLooper;

        Injector(Context context, Looper looper) {
            mContext = context;
            mLooper = looper;
        }

        Context getContext() {
            return mContext;
        }

        Looper getLooper() {
            return mLooper;
        }
		//创建native层对应的service
        NativeInputManagerService getNativeService(InputManagerService service) {
            return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue());
        }
		//将InputManagerService中的InputManagerInternal实现类加入LocalServices,供同进程其他服务调用相关功能
        void registerLocalService(InputManagerInternal localService) {
            LocalServices.addService(InputManagerInternal.class, localService);
        }
    }

NativeInputManagerService.NativeImpl

public interface NativeInputManagerService {
	...
    class NativeImpl implements NativeInputManagerService {
        /** Pointer to native input manager service object, used by native code. */
        @SuppressWarnings({"unused", "FieldCanBeLocal"})
        private final long mPtr;

        NativeImpl(InputManagerService service, Context context, MessageQueue messageQueue) {
            mPtr = init(service, context, messageQueue);  //初始化native层服务并返回该服务的对象指针到java层
        }

        private native long init(InputManagerService service, Context context,
                MessageQueue messageQueue);
        ...
	}
	...
}

nativeInit

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static const JNINativeMethod gInputManagerMethods[] = {
        /* name, signature, funcPtr */
        {"init",
         "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/"
         "MessageQueue;)J",
         (void*)nativeInit},  //init(java)->nativeInit(native)
        ...
};

static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
	...
	// 创建native层NativeInputManager,保存java层的context对象、ims对象、msgqueue
    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);  //NativeInputManager对象强引用 + 1
    return reinterpret_cast<jlong>(im);  //将native层NativeInputManager对象地址返回给java层,这个地址可以在native层获取出同一个对象
}

//NativeInputManager类声明,实现了三个重要接口抽象类
/*class NativeInputManager : public virtual RefBase,
    public virtual InputReaderPolicyInterface,
    public virtual InputDispatcherPolicyInterface,
    public virtual PointerControllerPolicyInterface {
    */
    
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper), mInteractive(true) {
    JNIEnv* env = jniEnv();  //获取虚拟机环境指针

    mServiceObj = env->NewGlobalRef(serviceObj);  //将java层的ims对象保存为全局引用

    {
        AutoMutex _l(mLock);
        mLocked.systemUiLightsOut = false;
        mLocked.pointerSpeed = 0;
        mLocked.pointerAcceleration = android::os::IInputConstants::DEFAULT_POINTER_ACCELERATION;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
    }
    mInteractive = true;

    InputManager* im = new InputManager(this, this);  //创建native层InputManager
    mInputManager = im;
    defaultServiceManager()->addService(String16("inputflinger"), im);  //向ServiceManager注册native层inputflinger服务
}

new InputManager

frameworks/native/services/inputflinger/InputManager.cpp

/**
 * The event flow is via the "InputListener" interface, as follows:
 * InputReader -> UnwantedInteractionBlocker -> InputClassifier -> InputDispatcher
 */
InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = createInputDispatcher(dispatcherPolicy);
    mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
    mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
    mReader = createInputReader(readerPolicy, *mBlocker);
}

创建并初始化四个event flow中的重要对象, 事件从前到后传递,前面的对象依次持有下一个阶段的对象引用
event flow: InputReader -> UnwantedInteractionBlocker -> InputClassifier -> InputDispatcher

createInputDispatcher

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

std::unique_ptr<InputDispatcherInterface> createInputDispatcher(
        const sp<InputDispatcherPolicyInterface>& policy) {
    return std::make_unique<android::inputdispatcher::InputDispatcher>(policy);
}

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
      : InputDispatcher(policy, STALE_EVENT_TIMEOUT) {}

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
                                 std::chrono::nanoseconds staleEventTimeout)
      : mPolicy(policy),  //将接口实现对象传进来,用户和wms服务交互
	 ...//一些成员变量初始化,太多了不列出
	 {
	 
    mLooper = new Looper(false);  //用于InputDispatcher线程
    mReporter = createInputReporter();
	//注册SurfaceComposer监听,当window状态改变时回调此接口onWindowInfosChanged通知inputflinger
    mWindowInfoListener = new DispatcherWindowListener(*this);
    SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);

    mKeyRepeatState.lastKeyEntry = nullptr;

    policy->getDispatcherConfiguration(&mConfig);
}

InputClassifier

frameworks/native/services/inputflinger/InputClassifier.cpp

//构建InputClassifier,传入mQueuedListener = listener 这个就是mDispatcher对象,这样就可以回调mDispatcher的方法
InputClassifier::InputClassifier(InputListenerInterface& listener) : mQueuedListener(listener) {}

UnwantedInteractionBlocker

//UnwantedInteractionBlocker是所有输入事件都会经历的一个阶段
//inputReader通过它notifyXXX方法向InputDispatcher传递对应事件
//其中对于触摸事件,如果支持手掌误触等功能,则会在这里有特殊处理
UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener)
      : UnwantedInteractionBlocker(listener, isPalmRejectionEnabled()){};
//isPalmRejectionEnabled 检测是否开始手掌误触功能
UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener,
                                                       bool enablePalmRejection)
      : mQueuedListener(listener), mEnablePalmRejection(enablePalmRejection) {}

InputReader

frameworks/native/services/inputflinger/reader/InputReader.cpp

std::unique_ptr<InputReaderInterface> createInputReader(
        const sp<InputReaderPolicyInterface>& policy, InputListenerInterface& listener) {
    return std::make_unique<InputReader>(std::make_unique<EventHub>(), policy, listener);
}

InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
                         const sp<InputReaderPolicyInterface>& policy,
                         InputListenerInterface& listener)
      : mContext(this),
        mEventHub(eventHub), //1.初始化EventHub
        mPolicy(policy),
        mQueuedListener(listener),  //2. 传入UnwantedInteractionBlocker对象
        mGlobalMetaState(AMETA_NONE),
        mLedMetaState(AMETA_NONE),
        mGeneration(1),
        mNextInputDeviceId(END_RESERVED_ID),
        mDisableVirtualKeysTimeout(LLONG_MIN),
        mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    refreshConfigurationLocked(0);
    updateGlobalMetaStateLocked();
}

InputReader最重要就是:

  1. 创建并初始化EventHub, 通过它向驱动获取上报的事件
  2. 注册UnwantedInteractionBlocker listener, 通过它向inputDispater传递事件

EventHub

frameworks/native/services/inputflinger/reader/EventHub.cpp

EventHub::EventHub(void)
      : mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
        mNextDeviceId(1),
        mControllerNumbers(),
        mNeedToSendFinishedDeviceScan(false),
        mNeedToReopenDevices(false),
        mNeedToScanDevices(true),
        mPendingEventCount(0),
        mPendingEventIndex(0),
        mPendingINotify(false) {
    ensureProcessCanBlockSuspend();
	//初始化epoll (用于监听文件描述符上的事件,用于监听具体/dev/input/eventX的fd的事件)
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);
    LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
	//初始化inotify (用于监听文件和目录的变化,这里主要时用于监听/dev/input/下面的目录变化)
    mINotifyFd = inotify_init1(IN_CLOEXEC);

    std::error_code errorCode;
    bool isDeviceInotifyAdded = false;
    //检测 "/dev/input" 文件节点是否存在
    if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
    	//如果当前"/dev/input" 文件节点存在则将这个路径加入Inotify监听
        addDeviceInputInotify();
    } else {
    	//如果当前"/dev/input" 文件节点不存在,则先将这个路径"/dev"加入Inotify监听(监听dev所有节点)
    	//因为有些嵌入式设备不一定一直存在输入设备,那么仅当/dev/input出现时(插入输入设备)才添加对/dev/input内容的监听, 
        addDeviceInotify();
        isDeviceInotifyAdded = true;
    }
    
	//V4L视频设备相关
    if (isV4lScanningEnabled() && !isDeviceInotifyAdded) {
        addDeviceInotify();
    } else {
        ALOGI("Video device scanning disabled");
    }

    struct epoll_event eventItem = {};
    eventItem.events = EPOLLIN | EPOLLWAKEUP; //设置监听epoll事件类型
    eventItem.data.fd = mINotifyFd;//要处理的事件相关的文件描述符
    
    //将mINotifyFd加入epoll监听的fd池子
    int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);


	//创建一个管道
    int wakeFds[2];
    result = pipe2(wakeFds, O_CLOEXEC);

    mWakeReadPipeFd = wakeFds[0];  //0为读端
    mWakeWritePipeFd = wakeFds[1];  //1为写端

    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);

    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);

    eventItem.data.fd = mWakeReadPipeFd;  //将mWakeReadPipeFd设置到eventItem.data.fd,当epoll有event到来会
    //将管道读端fd加入epoll监听的fd池子,当管道写端写入数据时,读端就换监听到epoll事件
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
}

到这里初始化InputFlinger就完成了

2. 启动inputflinger,处理输入事件

前面SystemServer的1、2、3步都完成后,会往下执行

	//4. 启动inputflinger,处理输入事件
          t.traceBegin("StartInputManager");
          //ims也注册wms的回调,用于通知wms一些事件发生
          inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
          inputManager.start();  //启动ims,开始处理输入事件
          t.traceEnd();

start()

frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

    public void start() {
        Slog.i(TAG, "Starting input manager");
        mNative.start();  //到native中的方法

        // Add ourselves to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this); //加入Watchdog的检测列表中

		//一系列对settings中开关的状态值监听
		...
    }

nativeStart

frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static void nativeStart(JNIEnv* env, jobject nativeImplObj) {
    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
    
    status_t result = im->getInputManager()->start();
}

InputManager::start()

status_t InputManager::start() {
    status_t result = mDispatcher->start();
    result = mReader->start();

    return OK;
}

分别调用inputDispatcherinputReaderstart方法

InputDispatcher::start()

status_t InputDispatcher::start() {

	//创建线程InputDispatcher,线程体函数dispatchOnce(), 线程唤醒函数mLooper->wake()
    mThread = std::make_unique<InputThread>(
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
    return OK;
}

InputThread继承与Thead类
frameworks/native/services/inputflinger/InputThread.cpp

InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
      : mName(name), mThreadWake(wake) {
    mThread = new InputThreadImpl(loop);
    mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);  //启动线程,线程优先级很高
}

class InputThreadImpl : public Thread {
public:
    explicit InputThreadImpl(std::function<void()> loop)
          : Thread(/* canCallJava */ true), mThreadLoop(loop) {}

    ~InputThreadImpl() {}

private:
    std::function<void()> mThreadLoop;

    bool threadLoop() override {
        mThreadLoop();
        return true;
    }
};


创建一个线程,用于分发事件,线程执行体dispatchOnce()

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);  //处理事件的分发
        }

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptable()) {  //处理命令队列中的命令
            nextWakeupTime = LONG_LONG_MIN;
        }

        // If we are still waiting for ack on some events,
        // we might have to wake up earlier to check if an app is anr'ing.
        const nsecs_t nextAnrCheck = processAnrsLocked();  //处理input ANR相关
        nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

        // We are about to enter an infinitely long sleep, because we have no commands or
        // pending or queued events
        if (nextWakeupTime == LONG_LONG_MAX) {
            mDispatcherEnteredIdle.notify_all();  //线程进入idle状态
        }
    } // release lock

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);  //再次进入阻塞等待中
}

InputReader::start()

status_t InputReader::start() {

    //创建线程InputReader,线程体函数loopOnce(), 线程唤醒函数mEventHub->wake()(调用EventHub的wake方法来唤醒)
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    std::vector<InputDeviceInfo> inputDevices;
	...
	//调用EventHub的getEvents获取输入事件
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        std::scoped_lock _l(mLock);
        mReaderIsAliveCondition.notify_all();

        if (count) {
            processEventsLocked(mEventBuffer, count);
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
                if (DEBUG_RAW_EVENTS) {
                    ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
                }
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }

        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            inputDevices = getInputDevicesLocked();
        }
    } // release lock

    // Send out a message that the describes the changed input devices.
    //如果输入设备有变化,通知其他服务
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    mQueuedListener.flush();
}

线程在循环从mEventHub->getEvents获取输入事件(这个方法会引起阻塞),如果获取到事件,EventHub会唤醒此线程,返回后会刷新mQueuedListener的事件队列, 唤醒InputDispatcher线程来消费。
到这里inputflinger的启动就完成,开始正常等待输入事件的上报并处理。文章来源地址https://www.toymoban.com/news/detail-548147.html

到了这里,关于[Android 13]Input系列--InputFlinger的启动的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Android Framework | AOSP源码下载及编译指南(基于Android13)

    Android Framework | AOSP源码下载及编译指南(基于Android13)

    AOSP(Android Open Source Project)是Android操作系统的开源项目,通过下载和编译AOSP源码,您可以获得原始的Android系统,并进行定制和开发。本教程将向您介绍如何下载AOSP源码并进行编译的步骤。 如何只是浏览查看AOSP源码,则没必要下载源码,可以使用google提供的Code Search工具进

    2024年01月16日
    浏览(21)
  • Android Framework 之 启动流程

    Android 系统的启动流程 Android 系统的启动流程可以分为以下几个主要步骤: 引导加载器(Bootloader)启动 :当你打开一个 Android 设备时,首先启动的是引导加载器。引导加载器负责启动 Android 的核心操作系统。 Linux 内核启动 :引导加载器加载并启动 Linux 内核。Linux 内核负责

    2024年02月14日
    浏览(11)
  • Android13 adb input 调试命令使用和源码解析

    Android13 adb input 调试命令使用和源码解析

    目录 一、概述 二、常用命令 2.1 输入文本 2.2 模拟按键 2.3 模拟点击 2.4 模拟滑动 2.5 模拟长按 2.6 模拟滚动 三、进阶用法 3.1 组合按键的用法 3.2 长按power键 3.3 输入中文 3.4 代码模拟发送按键 1. 方法1: 2. 方法2: 3. 方法3: 四、注意事项 五、源码解析 六、总结 好了 本篇作为And

    2024年01月20日
    浏览(19)
  • 【Android】Android Framework系列---CarPower电源管理

    【Android】Android Framework系列---CarPower电源管理

    智能座舱通常包括中控系统、仪表系统、IVI系统 、后排娱乐、HUD、车联网等。这些系统需要由汽车电源进行供电。由于汽车自身的特殊供电环境(相比手机方便的充电环境,汽车的蓄电池如果没有电是需要专业人士操作的),其电源状态会比较复杂,既要满足车内的座舱系统

    2024年02月07日
    浏览(31)
  • android framework之Applicataion启动流程分析

    android framework之Applicataion启动流程分析

    Application启动流程框架分析 启动方式一:通过Launcher启动app 启动方式二:在某一个app里启动第二个app的Activity. 以上两种方式均可触发app进程的启动。但无论哪种方式,最终通过通过调用AMS的startActivity()来启动application的。    根据上图分析, 要启动一个Application,需要涉及五

    2024年02月11日
    浏览(11)
  • Android Framework学习之Activity启动原理

    Android Framework学习之Activity启动原理

    Android 13.0 Activity启动原理逻辑流程图如下:

    2024年02月05日
    浏览(14)
  • 【Android】Android Framework系列---CarPower深度睡眠STR

    【Android】Android Framework系列---CarPower深度睡眠STR

    之前博客说了CarPower的开机启动流程 这里分析一下,Android CarPower实现深度睡眠的流程。 首先, 什么是深度睡眠(Deep Sleep) ? Android进入Deep Sleep后, 关闭屏幕、关闭CPU的电源,保持RAM的电源(激活状态) 。深度睡眠会进行 Suspend-to-RAM 挂起到内存( 做车载的经常会听到的STR )。

    2024年02月05日
    浏览(12)
  • android framework之AMS的启动管理与职责

    AMS是什么? AMS管理着activity,Service, Provide, BroadcastReceiver android10后:出现ATMS,ActivityTaskManagerService:ATMS是从AMS中抽出来,单独管理着原来AMS中的Activity组件 。 现在我们对AMS的分析,也就包含对ATMS的分析了。 AMS如何被别人管理?---被SystemServer的SystemServiceManager所管理 AMS如何被人

    2024年02月10日
    浏览(12)
  • Android WiFi Service启动-Android13

    Android WiFi Service启动-Android13

    Android WiFi基础概览 AOSP 文档 心主题 WiFi概览 编译生成对应的jar包: \\\"/apex/com.android.wifi/javalib/service-wifi.jar\\\" 相关WiFi服务: WifiService 、 WifiScanningService 、 RttService 、 WifiAwareService 、 WifiP2pService frameworks/base/services/java/com/android/server/SystemServer.java WifiInjector.java : WiFi依赖性注入器。

    2024年01月21日
    浏览(10)
  • Android Framework 常见解决方案(24)屏蔽FallbackHome,去除 Android正在启动,直接进入Launcher

    开机以后,设备会有一个“android正在启动”这样的弹框,这个界面是一个叫FallbackHome的Activity来展示的。FallbackHome机制是Android系统启动过程中的一种降级处理机制。当系统启动时,如果默认的Launcher应用无法正常加载或出现错误,系统会自动启用FallbackHome来替代默认Launcher。

    2024年01月24日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包