android整体框架相关

image

Q:进程与应用生命周期之间的关系

  1. 前台进程
    • 它正在用户的互动屏幕上运行一个 Activity(其 onResume() 方法已被调用)。
    • 它有一个 BroadcastReceiver 目前正在运行(其 BroadcastReceiver.onReceive() 方法正在执行)。
    • 它有一个 Service 目前正在执行其某个回调(Service.onCreate()、Service.onStart() 或 Service.onDestroy())中的代码。
  2. 可见进程
    • 它正在运行的 Activity 在屏幕上对用户可见,但不在前台(其 onPause() 方法已被调用)。举例来说,如果前台 Activity 显示为一个对话框,而这个对话框允许在其后面看到上一个 Activity,则可能会出现这种情况。
    • 它有一个 Service 正在通过 Service.startForeground()(要求系统将该服务视为用户知晓或基本上对用户可见的服务)作为前台服务运行。
    • 系统正在使用其托管的服务实现用户知晓的特定功能,例如动态壁纸、输入法服务等。
  3. 服务进程
    • 服务流程包含一个已使用 startService() 方法启动的 Service
  4. 缓存进程
    • 目前不需要的进程,通常包含用户当前不可见的一个或多个 Activity 实例(onStop() 方法已被调用并返回)

Q:系统是如何管理这些进程的?

这些进程保存在伪 LRU 列表中,列表中的最后一个进程是为了回收内存而终止的第一个进程。此列表的确切排序政策是平台的实现细节,但它通常会先尝试保留更多有用的进程(比如托管用户的主屏幕应用、用户最后看到的 Activity 的进程等),再保留其他类型的进程。

Q:activity启动中都涉及到了哪些类?分别有什么作用?

  • Instrumentation:Android Instrumentation是Android系统中的一套控制方法或者“钩子”,这些钩子可以在正常的生命周期(正常是由操作系统控制的)之外控制Android控件的运行,app->instrumentation->ams->app,自动化测试可以通过Instrumentation来操作Activity
  • ActivityThread:ActivityThread不是线程类(Thread),只不过它会跑在ActivityThread.main()方法中,根据Activity管理者的请求调度和执行activities、broadcasts及其相关的操作,每一个新启动的 Activity,其对象实例通过 Class 类的 newInstance 方法创建后,被包裹在一个 ActivityClientRecord 对象中然后添加到进程唯一的 ActivityThread 对象的成员变量 mActivitys 里
  • ActivityManagerService:Android中最核心的服务,主要负责系统中四大组件的启动、切换、调度及应用程序的管理和调度等工作。
  • ActivityManager:该类提供与Activity、Service和Process相关的信息以及交互方法, 可以被看作是ActivityManagerService的辅助类
  • ActivityStackSupervisor:负责所有Activity栈的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈,其中,mHomeStack管理的是Launcher相关的Activity栈;mFocusedStack管理的是当前显示在前台Activity的Activity栈;mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈,负责activiy中launchMode的处理
  • ActivityStack:ActivityStack负责“Activity栈”的状态和管理,ActivityStack内部包含了多个任务栈(TaskRecord),TaskRecord内部维护了一个ArrayList用来保存和管理ActivityRecord,ActivityRecord包含了一个Activity的所有信息

Q:一个Activity是如何启动的?

image image

  1. Launcher通知AMS启动App的启动页Activity,AMS记录要启动的Activity信息,并且通知Launcher进入pause状态。Launcher进入pause状态后,通知AMS已经paused了,可以启动App了

  2. 如果App未开启过,AMS发送创建进程请求,Zogyte进程接受AMS请求并孵化应用进程,应用进程调用ActivityThread并调用mian()方法,并且main()方法中创建ActivityThread对象,activityThread.attach()方法中进行绑定(应用进程绑定到AMS),传入applicationThread以便通讯。

  3. AMS通知App绑定Application(bindApplication)并启动Activity,并且创建和关联Context,最后调用onCreate等方法。

performLaunchActivity方法主要完成几个事情:

  • 1.从ActivityClientRecord中获取待启动的Activity的组件信息

  • 2.通过Instrumentation的newActivity方法使用类加载器创建Activity对象

  • 3.通过LoadedApk的makeApplication方法来尝试创建Application对象(注意没有创建,有了不创建,一个应有只有一个)

  • 4.创建Contextimpl对象并通过Activity的attach方法完成一些重要数据的初始化

  • 5.调用Activity的onCreate方法

Q:AMS,Zogyte,App进程,Launcher之间是如何通信的?

  • App进程与AMS交互:AMS所在的进程和应用进程在通过Binder互相通信时,实际上都是通过两者的代理类进行通信的,在ActivityThread.attach(false)方法中,AMS绑定ApplicationThread对象,即应用进程绑定到AMS,通过调用AMS的attachApplication来将ActivityThread的内部类ApplicationThread对象绑定至AMS,这样AMS就可以通过这个代理对象来控制应用进程
  • AMS与Launcher交互:Launcher也是一个App,调用startActivity方法,然后调用的是Instrumentation的execStartActivity方法,
  • Zygote与AMS交互:AMS和Zygote建立Socket连接,然后发送创建应用进程的请求

Q:为啥Activity启动流程中,大部分都是用Binder通讯,为啥跟Zygote通信的时候要用socket呢?

  1. 因为他们两个都是 init 进程启动的,两者启动顺序不确定,就算先启动 service manager,也不能保存 zygote 起来的时候 service manger 就已经初始化好了(这就需要额外的同步,太麻烦)
  2. 这个 socket 的所有者是 root,group 是 system,只有系统权限的用户才能读写,这又多了一个安全保障(注意,这个 socket 是 Unix 域 socket,不是 internet 域 socket)

Q:Android启动流程?

image

  1. swapper进程是系统第一个进程,用于初始化进程管理、内存管理、加载各种driver等
  2. init进程是所有用户进程的鼻祖 会孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程;\n init进程还启动servicemanager(binder服务管家)、bootanim(开机动画)等重要服务\n init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程(即虚拟机进程),Zygote是所有Java进程的父进程,Zygote进程本身是由init进程孵化而来的
  3. System Server是Zygote孵化的第一个进程\n Zygote进程孵化出的第一个App进程是Launcher\n 所有的App进程都是由Zygote进程fork生成的\n 在Zygote启动时会有一个虚拟机注册过程,会注册一些诸如binder注册等的jni事件

Q:ioctl是啥,android哪里用到了?

ioctl函数是驱动程序里的,用来对设备i/o通道进行管理:对设备的特性进行控制 android中与binder交互用到了ioctl

Q:StartActivity的流程?哪里可以做的插件化?

image lauchModle 检测: ActivityStarter.startActivityUnchecked()

绕过AndroidManifest检测:

  1. 瞒天过海:使用代理Activity替换原来的Activity 拿到ActivityManagerNative里面的IActivityManager对象动态代理拦截startActivity函数,获取原来的srcIntent,重新new一个代理Activity的newIntent,newIntent.putExtra(EXTRA_ORIGIN_INTENT,originIntent),然后用newIntent替换原来的srcIntent
  2. 借尸还魂: 在Activity实例化之前(laucherActivity的时候),判断intent里面有没有EXTRA_ORIGIN_INTENT字段,如果有的话取出来替换即可拿到ActivityThread对象里面的Handler对象mH,然后拿到new一个Handler的callback,然后适进去,在这个callback里面处理自己的回归需求。(设置callback的原因是因为我们只处理lauchActivy,不影响其他的操作)。这里注意AppCompatActivity需要兼容,先拿到ActivityThread里面的IPackageManager,然后动态代理拦截getActivityInfo()函数的ComponentName替换为代理Activity的 ComponentName

image image

Q:startService的启动流程?

image 造成ANR可能的原因有Binder full{step 7, 12}, MessageQueue(step 10), AMS Lock (step 13).

image

Q:BindService是什么?为什么 bindService 能和 Activity 的生命周期联动?

image 蓝色代表的是Client进程(发起端), 红色代表的是system_server进程, 黄色代表的是target进程(service所在进程);

image bindService 方法执行时,LoadedApk 会记录 ServiceConnection 信息 Activity 执行 finish 方法时,会通过 LoadedApk 检查 Activity 是否存在未注销/解绑的 BroadcastReceiver 和 ServiceConnection,如果有,那么会通知 AMS 注销/解绑对应的 BroadcastReceiver 和 Service,并打印异常信息,告诉用户应该主动执行注销/解绑的操作

Q:sendBroadcast原理?什么时候回发生ANR?

image ANR时机:只有串行广播才需要考虑超时,因为接收者是串行处理的,前一个receiver处理慢,会影响后一个receiver;并行广播 通过一个循环一次性向所有的receiver分发广播事件,所以不存在彼此影响的问题,则没有广播超时;

  • 串行广播超时情况1:某个广播总处理时间 > 2* receiver总个数 * mTimeoutPeriod, 其中mTimeoutPeriod,前台队列默认为10s,后台队列默认为60s;
  • 串行广播超时情况2:某个receiver的执行时间超过mTimeoutPeriod;

JobScheduler是什么?有什么用?

任务调度JobScheduler,它能做的工作就是可以在你所规定的要求下进行自动任务执行。比如规定时间、网络为WIFI情况、设备空闲、充电时等各种情况下后台自动运行

//创建jobService
public class MyJobService extends JobService {

    @Override
    public boolean onStartJob(JobParameters params) {
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }
}  
//注册jobService
<service android:name=".MyJobService"
    android:permission="android.permission.BIND_JOB_SERVICE" />
//执行任务
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);  
 ComponentName jobService = new ComponentName(this, MyJobService.class);
 JobInfo jobInfo = new JobInfo.Builder(ID, jobService) 
         .setMinimumLatency(5000)// 任务最少延迟时间 
         .setOverrideDeadline(60000)// 任务deadline,当到期没达到指定条件也会开始执行 
         .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)// 网络条件,默认值NETWORK_TYPE_NONE
         .setRequiresCharging(true)// 是否充电 
         .setRequiresDeviceIdle(false)// 设备是否空闲
         .setPersisted(true) //设备重启后是否继续执行
         .setBackoffCriteria(3000JobInfo.BACKOFF_POLICY_LINEAR) //设置退避/重试策略
         .build();  
 scheduler.schedule(jobInfo);

JobSchedulerService是在SystemServer中启动的服务,然后会遍历没有完成的任务,通过Binder找到对应的JobService,执行onStartJob方法,完成任务

Q:说说WorkManager

WorkManager 是一个 API,可供您轻松调度那些即使在退出应用或重启设备后仍应运行的可延期异步任务。

Q:ANR有哪些场景会发生?

  1. 当前主线程正在调用的消息耗时严重
  2. 已调度的消息发生单点耗时严重
  3. 连续多个消息耗时严重
  4. 相同消息高频执行
  5. 应用进程or系统负载严重

Q:用MultiDex解决何事?其根本原因在于?Dex如何优化?主Dex放哪些东西?主Dex和其他Dex调用、关联?Odex优化点在于什么?

  • MultiDex解决方法数65535的限制问题,即方法数不能超过65535个;方法id是short类型2个字节来存储的,所以数目范围应在0-2^16即0-65535
  • 主dex中:应用启动就必须加载的类,有一个keep文件来控制;其他dex文件都是通过主dex加载进来的
  • 提取出apk包中的classes.dex对其进行优化,生成.odex文件,原先apk包中的classes.dex将被删除
  • ODEX的用途是分离程序资源和可执行文件、以及做预编译处理,达到加快软件加载速度和开机速度的目的

Q:在打包过程中如何产生多个的DEX包?

打开mutliDex开关,在main-dex-list中设置dex分包

Q:如果做到动态加载,怎么决定哪些DEX动态加载呢?

dexClassLoader

Q:如果启动后在工作线程中做动态加载,如果没有加载完而用户进行页面操作需要使用到动态加载DEX中的class怎么办?

显示临时界面,待加载完成后跳转

Q:多渠道打包如何实现(Flavor、Dimension应用)?从母包生出渠道包实现方法?渠道标识替换原理?

productFlavors{
   v_1{
      dimetion:'version'
      applicationId:'v1'
   }
   v_2{
      dimetion:'version'
      applicationId:'v2'
   }
}

Q:Android打包哪些类型文件不能混淆?

jni方法不可混淆 反射用到的类不混淆 AndroidMainfest中的类不混淆 与服务端交互时,使用GSON、fastjson等框架解析服务端数据时,所写的JSON对象类不混淆 有用到WebView的JS调用也需要保证写的接口方法不混淆 Parcelable的子类和Creator静态成员变量不混淆

# 保持Parcelable不被混淆    
-keep class * implements Android.os.Parcelable {         
    public static final Android.os.Parcelable$Creator *;
}

enum类型时需要注意避免以下两个方法混淆

-keepclassmembers enum * {  
    public static **[] values();  
    public static ** valueOf(java.lang.String);  
}