ActivityManager原理认识笔记

本文详细介绍了WindowManager和Window的工作原理,包括Window的创建过程、Window的层级管理、WindowManager如何通过IPC与其他组件交互等内容。此外,还探讨了不同类型Window(如Activity、Dialog和Toast)的创建流程。

ActivityManager原理认识笔记

(1)Window是抽象类,具体实现是PhoneWindow,通过WindowManager就可以创建WindowWindowManager是外界访问Window的入口,但是Window的具体实现是在WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。所有的视图例如ActivityDialogToast都是附加在Window上的。

(2)通过WindowManager添加View的过程:将一个Button添加到屏幕坐标为(100,300)的位置上

mFloatingButton = new Button(this);
mFloatingButton.setText("test button");
mLayoutParams = new WindowManager.LayoutParams(
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0,
        PixelFormat.TRANSPARENT);//0,0 分别是type和flags参数,在后面分别配置了
mLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
        | LayoutParams.FLAG_NOT_FOCUSABLE
        | LayoutParams.FLAG_SHOW_WHEN_LOCKED;
mLayoutParams.type = LayoutParams.TYPE_SYSTEM_ERROR;
mLayoutParams.gravity = Gravity.LEFT | Gravity.TOP;
mLayoutParams.x = 100;
mLayoutParams.y = 300;
mFloatingButton.setOnTouchListener(this);
mWindowManager.addView(mFloatingButton, mLayoutParams);

flags参数解析:

FLAG_NOT_FOCUSABLE:表示window不需要获取焦点,也不需要接收各种输入事件。此标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传递给下层的具有焦点的window;

FLAG_NOT_TOUCH_MODAL:在此模式下,系统会将window区域外的单击事件传递给底层的window,当前window区域内的单击事件则自己处理,一般都需要开启这个标记;

FLAG_SHOW_WHEN_LOCKED:开启此模式可以让Window显示在锁屏的界面上。 [奇怪的是我删除这个标记还是在锁屏看到了添加的组件orz]

type参数表示window的类型,window共有三种类型:应用window,子window和系统window。应用window对应着一个Activity,子window不能独立存在,需要附属在特定的父window之上,比如Dialog就是子window。系统window是需要声明权限才能创建的window,比如Toast和系统状态栏这些都是系统window,需要声明的权限是

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

(3)window是分层的,每个window都对应着z-ordered,层级大的会覆盖在层级小的上面,应用window的层级范围是1~99,子window的层级范围是1000~1999,系统window的层级范围是2000~2999。
[注意,应用window的层级范围并不是1~999哟]

(4)WindowManager继承自ViewManager,常用的只有三个方法:addViewupdateViewremoveView

8.2 Window的内部机制

(1)Window是一个抽象的概念,不是实际存在的,它也是以View的形式存在。在实际使用中无法直接访问Window,只能通过WindowManager才能访问Window。每个Window都对应着一个View和一个ViewRootImplWindowView通过ViewRootImpl来建立联系。

(2)Window的添加、删除和更新过程都是IPC过程,以Window的添加为例,WindowManager的实现类对于addViewupdateViewremoveView方法都是委托给WindowManagerGlobal类,该类保存了很多数据列表,例如所有window对应的view集合mViews、所有window对应的ViewRootImpl的集合mRoots等,之后添加操作交给了ViewRootImpl来处理,接着会通过WindowSession来完成Window的添加过程,这个过程是一个IPC调用,因为最终是通过WindowManagerService来完成window的添加的。

8.3 Window的创建过程

(1)Activity的window创建过程

1.Activity的启动过程很复杂,最终会由ActivityThread中的performLaunchActivity来完成整个启动过程,在这个方法内部会通过类加载器创建Activity的实例对象,并调用它的attach方法为其关联运行过程中所依赖的一系列上下文环境变量;

2.Activity实现了Window的Callback接口,当window接收到外界的状态变化时就会回调Activity的方法,例如onAttachedToWindow、onDetachedFromWindow、dispatchTouchEvent等;

3.Activity的Window是由PolicyManager来创建的,它的真正实现是Policy类,它会新建一个PhoneWindow对象,Activity的setContentView的实现是由PhoneWindow来实现的;

4.Activity的顶级View是DecorView,它本质上是一个FrameLayout。如果没有DecorView,那么PhoneWindow会先创建一个DecorView,然后加载具体的布局文件并将view添加到DecorView的mContentParent中,最后就是回调Activity的onContentChanged通知Activity视图已经发生了变化;

5.还有一个步骤是让WindowManager能够识别DecorView,在ActivityThread调用handleResumeActivity方法时,首先会调用Activity的onResume方法,然后会调用makeVisible方法,这个方法中DecorView真正地完成了添加和显示过程。

ViewManager vm = getWindowManager();
vm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;

(2)Dialog的Window创建过程

1.过程与Activity的Window创建过程类似,普通的Dialog的有一个特别之处,即它必须采用Activity的Context,如果采用Application的Context会报错。原因是Application没有应用token,应用token一般是Activity拥有的。[service貌似也有token?]

(3)Toast的Window创建过程

1.Toast属于系统Window,它内部的视图由两种方式指定:一种是系统默认的演示;另一种是通过setView方法来指定一个自定义的View。

2.Toast具有定时取消功能,所以系统采用了Handler。Toast的显示和隐藏是IPC过程,都需要NotificationManagerService来实现。在Toast和NMS进行IPC过程时,NMS会跨进程回调Toast中的TN类中的方法,TN类是一个Binder类,运行在Binder线程池中,所以需要通过Handler将其切换到当前发送Toast请求所在的线程,所以Toast无法在没有Looper的线程中弹出。

3.对于非系统应用来说,mToastQueue最多能同时存在50个ToastRecord,这样做是为了防止DOS(Denial of Service,拒绝服务)。因为如果某个应用弹出太多的Toast会导致其他应用没有机会弹出Toast。

### 解决PreloadForLauncher.java中ActivityManagerService无法解析的错误 在Android框架开发中,`ActivityManagerService`是系统服务的核心组件之一,负责管理应用程序的生命周期、内存分配以及其他资源调度任务。如果在`PreloadForLauncher.java`文件中遇到`ActivityManagerService`未解析的错误,可能的原因包括以下几个方面: #### 1. 导入路径问题 确保正确导入了`ActivityManagerService`所在的包路径。通常情况下,`ActivityManagerService`位于`android.app`或`com.android.server.am`包中。如果路径不正确,编译器将无法识别该类。 ```java import com.android.server.am.ActivityManagerService; // 确保导入正确的路径[^1] ``` #### 2. 编译环境配置 如果使用的是AOSP(Android Open Source Project)源码环境,确保已正确设置编译环境。例如,确认`lunch`命令选择了适当的设备目标,并且所有依赖项均已正确构建。 ```bash source build/envsetup.sh lunch aosp_arm64-eng make -j$(nproc) ``` 如果缺少某些模块或依赖项,可能会导致`ActivityManagerService`无法解析。通过运行以下命令检查是否有未解决的依赖项: ```bash mmma frameworks/base/services/core/java/com/android/server/am/ ``` #### 3. 访问权限问题 `ActivityManagerService`是一个系统级服务,通常需要特定权限才能访问。如果代码尝试从非系统应用中调用该服务,可能会因为权限不足而导致未解析错误。确保当前模块具有适当权限,例如`SYSTEM_CORE`或`SYSTEM_SERVER`。 ```xml <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> ``` #### 4. 服务初始化问题 在某些情况下,`ActivityManagerService`可能尚未完成初始化,导致其对象不可用。可以通过检查服务是否已启动来避免此类问题。 ```java if (ActivityManagerService.isSystemReady()) { // 执行相关逻辑 } ``` #### 5. 替代方法 如果直接引用`ActivityManagerService`存在困难,可以尝试通过`Context`获取服务实例。这种方法适用于大多数场景,并能有效避免直接引用带来的问题。 ```java ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); if (activityManager != null) { // 使用ActivityManager执行相关操作 } ``` #### 6. 源码修改 如果上述方法均无效,可以检查`PreloadForLauncher.java`文件中对`ActivityManagerService`的具体调用方式。确保调用逻辑与`ActivityManagerService`的实际实现保持一致。例如,某些方法可能已被标记为`@hide`,需要通过反射调用。 ```java try { Method method = ActivityManagerService.class.getMethod("methodName", parameterTypes); Object result = method.invoke(null, arguments); } catch (Exception e) { Log.e("PreloadForLauncher", "Failed to invoke ActivityManagerService method", e); } ``` --- ### 示例代码 以下是一个完整的示例,展示如何安全地访问`ActivityManagerService`并处理潜在的异常情况: ```java public class PreloadForLauncher { public static void preloadServices(Context context) { if (context == null) { throw new IllegalArgumentException("Context cannot be null"); } try { ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); if (activityManager != null) { List<ActivityManager.RunningAppProcessInfo> processes = activityManager.getRunningAppProcesses(); if (processes != null && !processes.isEmpty()) { for (ActivityManager.RunningAppProcessInfo process : processes) { Log.d("PreloadForLauncher", "Process: " + process.processName); } } } } catch (SecurityException e) { Log.e("PreloadForLauncher", "Permission denied while accessing ActivityManager", e); } catch (Exception e) { Log.e("PreloadForLauncher", "Error while preloading services", e); } } } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值