分类 默认分类 下的文章

前言

终于算是忙完了一个阶段!!!从4月份开始,工作内容以及职务上都进行了较大的变动,最直接的就是从海外项目组调到了国内项目组。国内项目组目前有两个应用在同时跑着,而且还有几个马甲包也要维护,不知道大家发版的时候复杂不复杂,反正我们每次发版的时候都需要经历--打包、加固、对齐、重签名、打渠道包、上传云存储、生成渠道推广链接、生成内更SQL、上传Mapping文件等等步骤(xN),简直是折磨人啊。

所以首要任务就是做出一套自动化的基础设施来,最初直接考虑到的方案是【Jenkins+Docker+360命令行加固+VasDolly+Bugly等】的方案(下一篇文章会给大家分享该方案),整个过程下来基本能达到自动化的目的。就这么稳定的跑了一个多月,然而,在5月下旬的时候360加固发布了一个通知,大致内容就是免费版用户无法使用命令行的加固方式了,只能手动用工具加固。这就导致最初的方案直接垮掉,我花费了个把月学习Linux,Pipeline,Docker,还制作了各种镜像,结果突然不能用了,心塞。然而路还是要继续走下去的,在尽量不花钱的前提下,想到了开发桌面端工具的方案。

功能一览

接下来先给大家一览下桌面端工具的基本功能,我的电脑是Windows的,所以都是基于Windows平台下的build-tools相关工具进行开发的。首先大部分的功能都是基于jar或exe文件,那么在Java(Kotlin)中我们可以通过如下方式来调用这些外部程序,exec其实最终也是调用了ProcessBuilder,整体的原理就是如此:

//方式1
Runtime.getRuntime().exec(cmd)

//方式2
ProcessBuilder(cmd)

多渠道打包

这是该工具最基本的功能,使用VasDolly方案对APK文件进行多渠道打包(当然该APK文件需要是签名好的)。

多渠道包命令行工具即 VasDolly.jar,该文件可以在上述GitHub仓库中找到,常用的命令如下:

// 获取指定APK的签名方式
java -jar VasDolly.jar get -s [源apk地址]

// 获取指定APK的渠道信息
java -jar VasDolly.jar get -c [源apk地址]

// 删除指定APK的渠道信息
java -jar VasDolly.jar remove -c [源apk地址]

// 通过指定渠道字符串添加渠道信息
java -jar VasDolly.jar put -c "channel1,channel2" [源apk地址] [apk输出目录]

// 通过指定某个渠道字符串添加渠道信息到目标APK
java -jar VasDolly.jar put -c "channel1" [源apk地址] [输出apk地址]

// 通过指定渠道文件添加渠道信息
java -jar VasDolly.jar put -c channel.txt [源apk地址] [apk输出目录]

// 提供了FastMode,生成渠道包时不进行强校验,速度可提升10倍以上
java -jar VasDolly.jar put -c channel.txt -f [源apk地址] [apk输出目录]

对齐和签名

上传应用市场前,APK文件大部分会被市场要求进行加固,无论是使用腾讯乐固还是360加固等方式,加固后APK的签名信息总会被破坏,所以我们需要对加固后的APK文件重新进行签名。

配置签名

首先我们需要准备好应用的签名信息,该工具支持导入签名文件,并保存相应的StorePass、KeyAlias、KeyPass信息,如下:

当选择APK后,程序会判断选择的APK是否进行了签名,如果没有签名,那么就会弹窗提醒用户选择配置好的签名文件进行签名,签名之后才可进行多渠道打包的过程。

注:该功能现已升级,添加签名文件的时候绑定包名,选择apk后会自动获取到包名然后查找到对应的签名文件自动对齐签名处理,无需手动进行选择了。

对齐

签名的过程则需要用到Android SDK中的两个文件,以Windows系统为例,一个是处理对齐的【build-tools\版本号\zipalign.exe】文件,另一个则是用来签名的【build-tools\版本号\lib\apksigner.jar】文件。

我们先看下zipalign工具的官方说明:

zipalign is a zip archive alignment tool. It ensures that all uncompressed files in the archive are aligned relative to the start of the file. This allows those files to be accessed directly via mmap(2), removing the need to copy this data in RAM and reducing your app's memory usage. zipalign是一种zip归档对齐工具。它确保存档中所有未压缩的文件都与文件的开头对齐。这允许通过mmap直接访问这些文件,无需将这些数据复制到RAM中,并减少应用程序的内存使用。

zipalign should be used to optimize your APK file before distributing it to end-users. This is done automatically if you build with Android Studio. This documentation is for maintainers of custom build systems. 在将APK文件分发给用户之前,应使用zipalign优化APK文件。如果您使用Android Studio进行构建,这将自动完成。本文档面向定制构建系统的维护人员。

Google官方现在要求在使用apksigner对APK文件进行签名前需要先使用zipalign来优化APK文件,具体命令如下,以Windows下的zipalign.exe文件为例:

//对齐APK
zipalign.exe -p -f -v 4 [源apk路径] [输出apk路径]

//验证APK是否对齐
zipalign.exe -c -v 4 [源apk路径]

其他相关的内容可以参阅官网 zipalign

签名

当APK文件对齐后,就可以给对齐后的APK进行签名操作了,签名的方法有两种,我们这里单说使用--ks选项指定密钥库的方式,具体命令如下:

java -jar apksigner.jar sign 
    --verbose 
    --ks [KeyStore文件路径] 
    --ks-pass pass:[KeyStorePass]
    --ks-key-alias [KeyAlias]
    --key-pass pass:[KeyPass]
    --out [输出apk路径]
    [源apk路径]

命令本身很简单,别搞错参数就好,尤其是两个密码的参数,后面需要使用【pass:密码】。输入密码这里还支持其他格式,如果有需要请参阅官网 apksigner

加固、对齐、重签名后,这个apk就可以进行多渠道打包的处理了,然后即可发布到相关市场和渠道。

其他内容

在项目中还有很多其他的相关配置,比如发版的时候需要对APP进行应用内的更新通知。那么就需要我们填写发版的相关信息,版本名、版本号、更新日志等等内容都需要完善(可根据APK文件的命名来获取部分信息),然后通过这些信息生成应用内部更新的SQL语句,发送钉钉通知给相关后台人员处理。通知这一步又用到了钉钉的SDK,该工具支持配置钉钉机器人Webhook地址以及需要艾特的人员信息。

打出来的这些包都需要统一上传到云存储上面,这一步使用了AWS的云存储SDK,可以配置云存储桶地址等信息,免去人工手动上传apk的烦恼。上传完毕后会根据文件名生成相应的下载链接并通知到钉钉群,以便市场人员获取到渠道最新的推广链接等。

桌面端开发

接下来就说下桌面端的开发过程,至于Compose MultiPlatform的介绍,请参阅官网地址。本文主要就描述下一些针对桌面端的相关需求。

弹窗

关于弹窗,ComposeDesktop同样提供了Dialog可组合函数:

@Composable 
public fun Dialog(
    onCloseRequest: () -> kotlin.Unit, 
    state: androidx.compose.ui.window.DialogState, 
    visible: kotlin.Boolean, 
    title: kotlin.String, 
    icon: androidx.compose.ui.graphics.painter.Painter?, 
    undecorated: kotlin.Boolean, 
    transparent: kotlin.Boolean, 
    resizable: kotlin.Boolean, 
    enabled: kotlin.Boolean, 
    focusable: kotlin.Boolean, 
    onPreviewKeyEvent: (androidx.compose.ui.input.key.KeyEvent) -> kotlin.Boolean, 
    onKeyEvent: (androidx.compose.ui.input.key.KeyEvent) -> kotlin.Boolean, 
    content: @Composable() (DialogWindowScope.() -> kotlin.Unit)
    ): kotlin.Unit { /* compiled code */ }

大部分的参数都可以直接看出他的作用,主要看一下state参数,该参数可以控制弹窗的位置及大小,例如我们配置一个在屏幕中央,宽高为500*300dp的弹窗,那么示例代码如下:

state = DialogState(
            position = WindowPosition(Alignment.Center),
            size = DpSize(500.dp, 300.dp),
        )

不过这个弹窗没有阴影,如果想添加的话可以内部套一层Surface来做出阴影效果:

Surface(
    modifier = Modifier.fillMaxSize().padding(20.dp),
    elevation = 10.dp,
    shape = RoundedCornerShape(16.dp)
)

文件选择器

关于文件选择器这一块目前Compose还没有专门的函数,但是我们还是可以使用原有的方案:

  • javax.swing.JFileChooser
  • java.awt.FileDialog

个人还是更偏向于使用JFileChooser,因为使用第二种方案的话,在页面重组的情况下总是会莫名的弹出选择框来。一个简单的文件选择器如下所示:

private fun showFileSelector(
    suffixList: Array<String>,
    onFileSelected: (String) -> Unit
) {
    JFileChooser().apply {
        //设置页面风格
        try {
            val lookAndFeel = UIManager.getSystemLookAndFeelClassName()
            UIManager.setLookAndFeel(lookAndFeel)
            SwingUtilities.updateComponentTreeUI(this)
        } catch (e: Throwable) {
            e.printStackTrace()
        }

        fileSelectionMode = JFileChooser.FILES_ONLY
        isMultiSelectionEnabled = false
        fileFilter = FileNameExtensionFilter("文件过滤", *suffixList)

        val result = showOpenDialog(ComposeWindow())
        if (result == JFileChooser.APPROVE_OPTION) {
            val dir = this.currentDirectory
            val file = this.selectedFile
            println("Current apk dir: ${dir.absolutePath} ${dir.name}")
            println("Current apk name: ${file.absolutePath} ${file.name}")
            onFileSelected(file.absolutePath)
        }
    }
}

该方式在使用的过程中也有一定的缺陷,就是每次打开文件弹窗总是会卡顿一下,所以后续也是有了寻找其他高效选择文件方式的想法。

文件拖拽

选择文件除了上面的弹窗选择方式,还有另一种神奇的方式 - 拖拽选择,本来也是没有头绪,然而在Slack闲逛的时候发现了Jim Sproch推荐了一篇相关的文章:dev.to/tkuenneth/f… 。看完后也是恍然大悟,但是在Compose Desktop中,window是整个窗口,如何让某一个指定的区域响应我们的文件拖拽事件呢?

还记得在Android上有ComposeView吧,用来嵌套原来的那一套View体系。那么在这里我也是采用了类似的这么一种方式,实例一个空的JPanel控件然后给它安排到window中去。具体位置及大小的设置呢,在Compose中可以通过 onPlaced(onPlaced: (LayoutCoordinates) -> Unit) 修饰符来获取到,示例代码如下所示:

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun DropBoxPanel(
    modifier: Modifier,
    window: ComposeWindow,
    component: JPanel = JPanel(),
    onFileDrop: (List<String>) -> Unit
) {

    val dropBoundsBean = remember {
        mutableStateOf(DropBoundsBean())
    }

    Box(
        modifier = modifier.onPlaced {
            dropBoundsBean.value = DropBoundsBean(
                x = it.positionInWindow().x,
                y = it.positionInWindow().y,
                width = it.size.width,
                height = it.size.height
            )
        }) {
        LaunchedEffect(true) {
            component.setBounds(
                dropBoundsBean.value.x.roundToInt(),
                dropBoundsBean.value.y.roundToInt(),
                dropBoundsBean.value.width,
                dropBoundsBean.value.height
            )
            window.contentPane.add(component)

            val target = object : DropTarget(component, object : DropTargetAdapter() {
                override fun drop(event: DropTargetDropEvent) {

                    event.acceptDrop(DnDConstants.ACTION_REFERENCE)
                    val dataFlavors = event.transferable.transferDataFlavors
                    dataFlavors.forEach {
                        if (it == DataFlavor.javaFileListFlavor) {
                            val list = event.transferable.getTransferData(it) as List<*>

                            val pathList = mutableListOf<String>()
                            list.forEach { filePath ->
                                pathList.add(filePath.toString())
                            }
                            onFileDrop(pathList)
                        }
                    }
                    event.dropComplete(true)

                }
            }) {

            }
        }

        SideEffect {
            component.setBounds(
                dropBoundsBean.value.x.roundToInt(),
                dropBoundsBean.value.y.roundToInt(),
                dropBoundsBean.value.width,
                dropBoundsBean.value.height
            )
        }

        DisposableEffect(true) {
            onDispose {
                window.contentPane.remove(component)
            }
        }
    }
}

实际运行效果如下,个人感觉基本还是能达到目的的。

数据的保存

最开始的时候,功能很少,每个配置的数据都是使用了txt文件来一行行保存,但是到了后来功能越来越复杂,单纯的按行来处理貌似有点捉襟见肘了,所以考虑使用json来保存复杂的类型数据。

json数据的处理从原生JSON到FastJson,Gson,Moshi等都已经体验过了,于是乎便采用了之前未使用过的Jackson。然而不得不说,就目前为止,jackson是我用过最简洁、优雅的一款解析库。

假如我有一个List类型的列表数据,那么当我要把这个数据存储到文件的时候只需:

jacksonObjectMapper().writeValue(File, List<String>)

而从文件中读取数据也是简单的狠啊:

//方式1
val list = jacksonObjectMapper().readValue<List<String>>(jsonFile)

//方式2
val list : List<String> = jacksonObjectMapper().readValue(jsonFile)

这种简洁真的是深入我心。继续深入了解下Jackson,你会发现它的可扩展性以及可定制性都很强,简直相见恨晚啊。之前也是在一个舒适圈待习惯了,这次主动跳出来居然有了意想不到的收获。

但是呢,每个框架也会有它自己的注意点,比如jackson,属性命名不可以是is开头,否则序列化等就会报错。这点似乎在阿里巴巴JAVA手册中好像也有提到,具体原因请大家自行百度(Google)。

资源的拷贝

当我们使用[java -jar xxx.jar]命令执行jar文件的时候,需要明确指定 jar文件的地址,但是在Compose Desktop中我们要怎么存放并读取这个jar文件呢 ?我们可以从Compose Desktop中读取并展示图片的相关代码中得到启发,假如有一个sample.svg图标文件存放到了项目的 resources 文件夹下,那么我们在引用这张图片的时候就可以使用:

painterResource("sample.svg")

我们点进去这个方法看下:

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun painterResource(
    resourcePath: String
): Painter = painterResource(
    resourcePath,
    ResourceLoader.Default
)

@ExperimentalComposeUiApi
@Composable
fun painterResource(
    resourcePath: String,
    loader: ResourceLoader
): Painter = when (resourcePath.substringAfterLast(".")) {
    "svg" -> rememberSvgResource(resourcePath, loader)
    "xml" -> rememberVectorXmlResource(resourcePath, loader)
    else -> rememberBitmapResource(resourcePath, loader)
}

里面居然有个ResourceLoader类,这名字一听就有戏啊,大概率就是我们需要的内容,而传递的默认参数是ResourceLoader.Default,那么就看下Default的源码吧:

//==========Resources.desktop.kt文件==========
@ExperimentalComposeUiApi
interface ResourceLoader {
    companion object {
        /**
         * Resource loader which is capable to load resources from `resources` folder in an application's
         * project. Ability to load from dependent modules resources is not guaranteed in the future.
         * Use explicit `ClassLoaderResourceLoader` instance if such guarantee is needed.
         */
        @ExperimentalComposeUiApi
        val Default = ClassLoaderResourceLoader()
    }
    fun load(resourcePath: String): InputStream
}

@ExperimentalComposeUiApi
class ClassLoaderResourceLoader : ResourceLoader {
    override fun load(resourcePath: String): InputStream {
        // TODO(https://github.com/JetBrains/compose-jb/issues/618): probably we shouldn't use
        //  contextClassLoader here, as it is not defined in threads created by non-JVM
        val contextClassLoader = Thread.currentThread().contextClassLoader!!
        val resource = contextClassLoader.getResourceAsStream(resourcePath)
            ?: (::ClassLoaderResourceLoader.javaClass).getResourceAsStream(resourcePath)
        return requireNotNull(resource) { "Resource $resourcePath not found" }
    }
}

//==========ClassLoader类==========
public InputStream getResourceAsStream(String name) {
    Objects.requireNonNull(name);
    URL url = getResource(name);
    try {
        return url != null ? url.openStream() : null;
    } catch (IOException e) {
        return null;
    }
}

public URL getResource(String name) {
    Objects.requireNonNull(name);
    URL url;
    if (parent != null) {
        url = parent.getResource(name);
    } else {
        url = BootLoader.findResource(name);
    }
    if (url == null) {
        url = findResource(name);
    }
    return url;
}

上述源码的整个逻辑基本上就是两步,根据资源文件名获取到资源文件,然后获取资源文件的输入流。看到这里其实我们已经有两种方案了:

  • 方案一:直接拿到文件的URL然后获取到文件的路径
  • 方案二:根据文件的输入流,将文件重新保存到本机相关目录

然而事情并没有这么简单,如果我们使用方案一,那么在编译运行的时候完全没有问题,所有的资源文件会被保存到【\build\processedResources\jvm】下,此时我们直接可以通过文件的URL获取到文件路径,然后调用即可。但是,当我们打包成安装包后,例如在Windows下使用packageMsi命令打包出msi文件并安装到电脑上后,运行程序,这时候你就会发现资源文件所在的路径就很奇怪,例如我的工程下是【C:\Program Files\工程名\app\工程名-jvm-1.0-SNAPSHOT-xxxxxx.jar!/资源文件名】,也就是说所有的资源文件被打包进了这个快照文件,如果此时直接使用该路径运行java -jar 等命令,那么肯定就会报错了。

所以最稳妥的方式还是使用方案二,使用ResourceLoader获取到资源文件流然后重新保存到本机上的相关目录就好了,伪代码如下:

ResourceLoader.Default.load(resourcesPath)
    .use { inputStream ->
        val fos = FileOutputStream(file)
        val buffer = ByteArray(1024)
        var len: Int
            while (((inputStream.read(buffer).also { len = it })) != -1) {
                fos.write(buffer, 0, len)
                }
          fos.flush()
              inputStream.close()
              fos.close()
          }

打包MSI

在Windows环境下打包Msi格式安装包的时候,有一个downloadWix的Task,该Task涉及到了Wix资源的下载,如下 :

Task :downloadWix Download github.com/wixtoolset/…

在IDEA中下载可能会非常的缓慢,此时我们可以复制上述地址,登上梯子,然后直接去GitHub下载。下载完毕后直接放入【/build/wixToolset】目录下即可,再次编译速度就会起飞了。

总结

简直没想到啊,作为一个Android开发者,现在借助Compose Desktop开发起桌面端居然能这么的轻车熟路,我对Compose真是越来越喜欢了。

另外呢,跳出业务这一段时间来处理这些东西也让我对干预APK的打包等过程从理论迈出了实践的一步,同时对市场和运营同学的工作也有了更多了解,通过该工具帮助其处理了部分重复机械式的工作,部门间的感情也得到了进一步的增温(狗头滑稽)。

就编到这吧,桌面工具还需要持续的维护跟优化,基本是面向市场和运营同事编程了。关于开头说的Jenkins那一套其实早就写好了,是鄙人少有的万字长文,但是中间变故太大,一直也没发布出来,接下来会重新整理下并发布,还请大家多多指正。

作者:乐翁龙
链接:https://juejin.cn/post/7122645579439538183

原文链接:https://www.jianshu.com/p/3890895ab180

以下源码基于android-11.0.0_r1

启动一个Activity,通常有两种情况:第一种是不同进程的的根activity,比如laucnher启动app;第二种是同进程内部启动activity。这两种情况的启动流程类似,大致分为以下三个步骤:

  1. 调用进程的activity收集好信息后,向system_server进程的ActivityTaskManagerSrvice服务发起请求。
  2. ATMS向PKMS寻找启动的activity的信息和进程信息,如果启动的activity没有被创建,则创建新进程,之后管理activity栈,并回调启动activity所在进程的ApplicationThread类。
  3. ApplicationThread通过调用ActivityThread来反射创建并启动Activity。

以下就逐一讲解这三大过程:

一、从startActivity到ATMS

下图是调用进程向system_server进程发起请求的过程:


无论是startActivity还是startActivityForResult最终都是调用startActivityForResult

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback,
        AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {

    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        ...
        
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        // mParent 是Activity类型,是当前Activity的父类
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            // 调用Instrumentation.execStartActivity启动activity
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            ...
            
        } else {
            ...

        }
    }
}

startActivityForResult中继续调用Instrumentation.execStartActivity方法。Activity中的mInstrumentation是在attach()方法中初始化,由ActivityThread传入,其作用一是通过远程服务调用启动activity;二是连接ActivityThread与activity,处理activity生命周期回调。

// Instrumentation主要用来监控应用程序和系统的交互,比如调用ATMS启动activity,回调生命周期
public class Instrumentation {

    public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
        ...

        try {
            ...
            
            // 通过ATMS远程调用startActivity
            int result = ActivityTaskManager.getService().startActivity(whoThread,
                    who.getOpPackageName(), who.getAttributionTag(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()), token,
                    target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

    /**
     * 根据result判断当前能否启动activity,不能则抛出异常
     */
    public static void checkStartActivityResult(int res, Object intent) {
        if (!ActivityManager.isStartResultFatalError(res)) {
            return;
        }

        switch (res) {
            case ActivityManager.START_INTENT_NOT_RESOLVED:
            case ActivityManager.START_CLASS_NOT_FOUND:
                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
                    // 没有在manifest中声明
                    throw new ActivityNotFoundException(
                            "Unable to find explicit activity class "
                            + ((Intent)intent).getComponent().toShortString()
                            + "; have you declared this activity in your AndroidManifest.xml?");
                throw new ActivityNotFoundException(
                        "No Activity found to handle " + intent);
            case ActivityManager.START_PERMISSION_DENIED:
                throw new SecurityException("Not allowed to start activity "
                        + intent);
            case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
                throw new AndroidRuntimeException(
                        "FORWARD_RESULT_FLAG used while also requesting a result");
            case ActivityManager.START_NOT_ACTIVITY:
                throw new IllegalArgumentException(
                        "PendingIntent is not an activity");
            case ActivityManager.START_NOT_VOICE_COMPATIBLE:
                throw new SecurityException(
                        "Starting under voice control not allowed for: " + intent);
            case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
                throw new IllegalStateException(
                        "Session calling startVoiceActivity does not match active session");
            case ActivityManager.START_VOICE_HIDDEN_SESSION:
                throw new IllegalStateException(
                        "Cannot start voice activity on a hidden session");
            case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
                throw new IllegalStateException(
                        "Session calling startAssistantActivity does not match active session");
            case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
                throw new IllegalStateException(
                        "Cannot start assistant activity on a hidden session");
            case ActivityManager.START_CANCELED:
                throw new AndroidRuntimeException("Activity could not be started for "
                        + intent);
            default:
                throw new AndroidRuntimeException("Unknown error code "
                        + res + " when starting " + intent);
        }
    }
}
@SystemService(Context.ACTIVITY_TASK_SERVICE)
public class ActivityTaskManager {
    /**
     * IActivityTaskManager是一个Binder,用于和system_server进程中的ActivityTaskManagerService通信
     */
    public static IActivityTaskManager getService() {
        return IActivityTaskManagerSingleton.get();
    }

    private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
            new Singleton<IActivityTaskManager>() {
                @Override
                protected IActivityTaskManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
                    return IActivityTaskManager.Stub.asInterface(b);
                }
            };
}
  1. ActivityTaskManager.getService()获取ATMS的代理类,通过Binder跨进程通信,向ATMS发起startActivity请求。
  2. 向ATMS发起启动activity请求,获得启动结果result,根据result判断能否启动activity,不能则抛出异常,比如activity未在manifest中声明。

二、ATMS到ApplicationThread

下图为ATMS到ApplicationThread时序图:


// /frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
public class ActivityTaskManagerService extends IActivityTaskManager.Stub {

    public final int startActivity(IApplicationThread caller, String callingPackage,
      String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
      String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
      Bundle bOptions) {
      return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
              resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
              UserHandle.getCallingUserId());
    }

    private int startActivityAsUser(IApplicationThread caller, String callingPackage,
        @Nullable String callingFeatureId, Intent intent, String resolvedType,
        IBinder resultTo, String resultWho, int requestCode, int startFlags,
        ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
        assertPackageMatchesCallingUid(callingPackage);
        // 判断调用者进程是否被隔离
        enforceNotIsolatedCaller("startActivityAsUser");
        
        // 检查调用者权限
        userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
                Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");

        // TODO: Switch to user app stacks here.
        return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setCallingFeatureId(callingFeatureId)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setUserId(userId)
                .execute();
    }
}

ATMS通过一系列方法调用最终调到startActivityAsUser方法,该方法先检查调用者权限,再通过getActivityStartController().obtainStarter创建ActivityStarter类,把参数设置到ActivityStarter.Request类中,最后执行ActivityStarter. execute()方法。

// /frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/**
 * Controller for interpreting how and then launching an activity.
 *
 * This class collects all the logic for determining how an intent and flags should be turned into
 * an activity and associated task and stack.
 */
class ActivityStarter {

    /**
    * Resolve necessary information according the request parameters provided earlier, and execute
    * the request which begin the journey of starting an activity.
    * @return The starter result.
    */
    int execute() {
        try {
            ...


            int res;
            synchronized (mService.mGlobalLock) {
                ...
                
                res = executeRequest(mRequest);

                ...
            }
        } finally {
            onExecutionComplete();
        }
    }

    /**
    * Executing activity start request and starts the journey of starting an activity. Here
    * begins with performing several preliminary checks. The normally activity launch flow will
    * go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
    */
    private int executeRequest(Request request) {
        // 判断启动的理由不为空
        if (TextUtils.isEmpty(request.reason)) {
            throw new IllegalArgumentException("Need to specify a reason.");
        }

        // 获取调用的进程
        WindowProcessController callerApp = null;
        if (caller != null) {
          callerApp = mService.getProcessController(caller);
          if (callerApp != null) {
              // 获取调用进程的pid和uid并赋值
              callingPid = callerApp.getPid();
              callingUid = callerApp.mInfo.uid;
          } else {
              err = ActivityManager.START_PERMISSION_DENIED;
          }
        }

        final int userId = aInfo != null && aInfo.applicationInfo != null
              ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;

        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
          // 获取调用者所在的ActivityRecord
          sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);
          if (sourceRecord != null) {
              if (requestCode >= 0 && !sourceRecord.finishing) {
                  //requestCode = -1 则不进入
                  resultRecord = sourceRecord;
              }
          }
        }

        final int launchFlags = intent.getFlags();
        if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
         ... // activity执行结果的返回由源Activity转换到新Activity, 不需要返回结果则不会进入该分支
        }

        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
           // 从Intent中无法找到相应的Component
           err = ActivityManager.START_INTENT_NOT_RESOLVED;
        }

        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
           // 从Intent中无法找到相应的ActivityInfo
           err = ActivityManager.START_CLASS_NOT_FOUND;
        }

        ...

        //执行后resultStack = null
        final ActivityStack resultStack = resultRecord == null
              ? null : resultRecord.getRootTask();

        ... //权限检查

        // ActivityController不为空的情况,比如monkey测试过程
        if (mService.mController != null) {
            try {
                Intent watchIntent = intent.cloneFilter();
                abort |= !mService.mController.activityStarting(watchIntent,
                      aInfo.applicationInfo.packageName);
            } catch (RemoteException e) {
              mService.mController = null;
            }
        }

        if (abort) {
            ... //权限检查不满足,才进入该分支则直接返回;
            return START_ABORTED;
        

        if (aInfo != null) {
            if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
                  aInfo.packageName, userId)) {
                ...
                // 向PKMS获取启动Activity的ResolveInfo
                rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
                      computeResolveFilterUid(
                              callingUid, realCallingUid, request.filterCallingUid));
                // 向PKMS获取启动Activity的ActivityInfo
                aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
                      null /*profilerInfo*/);

            }
        }

        ...

        // 创建即将要启动的Activity的描述类ActivityRecord
        final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
              callingPackage, callingFeatureId, intent, resolvedType, aInfo,
              mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
              request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
              sourceRecord);
        mLastStartActivityRecord = r;

        ...

        // 调用 startActivityUnchecked
        mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
                request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
                restrictedBgActivity, intentGrants);

        if (request.outActivity != null) {
            request.outActivity[0] = mLastStartActivityRecord;
        }

        return mLastStartActivityResult;
    }
}

ActivityStarter中通过调用executeRequest方法,先做一系列检查,包括进程检查、intent检查、权限检查、向PKMS获取启动Activity的ActivityInfo等信息,然后调用startActivityUnchecked方法开始对要启动的activity做任务栈管理。

/**
 * Start an activity while most of preliminary checks has been done and caller has been
 * confirmed that holds necessary permissions to do so.
 * Here also ensures that the starting activity is removed if the start wasn't successful.
 */
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
            boolean restrictedBgActivity, NeededUriGrants intentGrants) {
    ...

    try {
        ...

        result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
    } finally {
        
        ...
    }

    ...

    return result;
}

ActivityRecord mStartActivity;

private ActivityStack mSourceStack;
private ActivityStack mTargetStack;
private Task mTargetTask;


// 主要处理栈管理相关的逻辑
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
                     IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                     int startFlags, boolean doResume, ActivityOptions options, Task inTask,
                     boolean restrictedBgActivity, NeededUriGrants intentGrants) {
    // 初始化启动Activity的各种配置,在初始化前会重置各种配置再进行配置,
    // 这些配置包括:ActivityRecord、Intent、Task和LaunchFlags(启动的FLAG)等等
    setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
          voiceInteractor, restrictedBgActivity);

    // 给不同的启动模式计算出mLaunchFlags
    computeLaunchingTaskFlags();

    // 主要作用是设置ActivityStack
    computeSourceStack();

    // 将mLaunchFlags设置给Intent
    mIntent.setFlags(mLaunchFlags);

    // 确定是否应将新活动插入现有任务。如果不是,则返回null,
    // 或者返回带有应将新活动添加到其中的任务的ActivityRecord。
    final Task reusedTask = getReusableTask();

    //...

    // 如果reusedTask为null,则计算是否存在可以使用的任务栈
    final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
    final boolean newTask = targetTask == null; // 启动Activity是否需要新创建栈
    mTargetTask = targetTask;

    computeLaunchParams(r, sourceRecord, targetTask);

    // 检查是否允许在给定任务或新任务上启动活动。
    int startResult = isAllowedToStart(r, newTask, targetTask);
    if (startResult != START_SUCCESS) {
        return startResult;
    }


    final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack();
    if (topStack != null) {
        // 检查正在启动的活动是否与当前位于顶部的活动相同,并且应该只启动一次
        startResult = deliverToCurrentTopIfNeeded(topStack, intentGrants);
        if (startResult != START_SUCCESS) {
            return startResult;
        }
    }

    if (mTargetStack == null) {
        // 复用或者创建堆栈
        mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, targetTask, mOptions);
    }
    if (newTask) {
        // 新建一个task
        final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
              ? mSourceRecord.getTask() : null;
        setNewTask(taskToAffiliate);
        if (mService.getLockTaskController().isLockTaskModeViolation(
              mStartActivity.getTask())) {
            Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
            return START_RETURN_LOCK_TASK_MODE_VIOLATION;
        }
    } else if (mAddingToTask) {
        // 复用之前的task
        addOrReparentStartingActivity(targetTask, "adding to task");
    }

    ...

    // 检查是否需要触发过渡动画和开始窗口
    mTargetStack.startActivityLocked(mStartActivity,
          topStack != null ? topStack.getTopNonFinishingActivity() : null, newTask,
          mKeepCurTransition, mOptions);


    if (mDoResume) {

        //...
        // 调用RootWindowContainer的resumeFocusedStacksTopActivities方法
        mRootWindowContainer.resumeFocusedStacksTopActivities(
              mTargetStack, mStartActivity, mOptions);
    }

    // ...

    return START_SUCCESS;
}

// 初始化状态
private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
                           boolean doResume, int startFlags, ActivityRecord sourceRecord,
                           IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                           boolean restrictedBgActivity) {

    reset(false /* clearRequest */); //重置状态
    mStartActivity = r; // 被启动的Activity
    mIntent = r.intent; //启动的intent
    mSourceRecord = sourceRecord; //发起启动的Activity
    mLaunchMode = r.launchMode; // 启动模式
    // 启动Flags
    mLaunchFlags = adjustLaunchFlagsToDocumentMode(
          r, LAUNCH_SINGLE_INSTANCE == mLaunchMode,
          LAUNCH_SINGLE_TASK == mLaunchMode, mIntent.getFlags());
    mInTask = inTask;
    // ...
}

// 根据不同启动模式计算出不同的mLaunchFlags
private void computeLaunchingTaskFlags() {
    if (mInTask == null) {
        if (mSourceRecord == null) {
            if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            }
        } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
        } else if (isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK)) {
            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
        }
    }
}

// 设置ActivityStack
private void computeSourceStack() {
    if (mSourceRecord == null) {
        mSourceStack = null;
        return;
    }
    if (!mSourceRecord.finishing) {
        mSourceStack = mSourceRecord.getRootTask();
        return;
    }

    if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
        mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
        mNewTaskInfo = mSourceRecord.info;

        final Task sourceTask = mSourceRecord.getTask();
        mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
    }
    mSourceRecord = null;
    mSourceStack = null;
}

private Task getReusableTask() {
    // If a target task is specified, try to reuse that one
    if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) {
        Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
        if (launchTask != null) {
            return launchTask;
        }
        return null;
    }

    //标志位,如果为true,说明要放入已经存在的栈,
    // 可以看出,如果是设置了FLAG_ACTIVITY_NEW_TASK 而没有设置 FLAG_ACTIVITY_MULTIPLE_TASK,
    // 或者设置了singleTask以及singleInstance
    boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
            (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
            || isLaunchModeOneOf(LAUNCH_SINGLE_INSTANCE, LAUNCH_SINGLE_TASK);
    // 重新检验
    putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
    ActivityRecord intentActivity = null;
    if (putIntoExistingTask) {
        if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
            //如果是 singleInstance,那么就找看看之前存在的该实例,找不到就为null
            intentActivity = mRootWindowContainer.findActivity(mIntent, mStartActivity.info,
                    mStartActivity.isActivityTypeHome());
        } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
            // For the launch adjacent case we only want to put the activity in an existing
            // task if the activity already exists in the history.
            intentActivity = mRootWindowContainer.findActivity(mIntent, mStartActivity.info,
                    !(LAUNCH_SINGLE_TASK == mLaunchMode));
        } else {
            // Otherwise find the best task to put the activity in.
            intentActivity =
                    mRootWindowContainer.findTask(mStartActivity, mPreferredTaskDisplayArea);
        }
    }

    if (intentActivity != null
            && (mStartActivity.isActivityTypeHome() || intentActivity.isActivityTypeHome())
            && intentActivity.getDisplayArea() != mPreferredTaskDisplayArea) {
        // Do not reuse home activity on other display areas.
        intentActivity = null;
    }

    return intentActivity != null ? intentActivity.getTask() : null;
}

// 计算启动的Activity的栈
private Task computeTargetTask() {
    if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
            && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
        // 返回null,应该新创建一个Task,而不是使用现有的Task
        return null;
    } else if (mSourceRecord != null) {
        // 使用源Activity的task
        return mSourceRecord.getTask();
    } else if (mInTask != null) {
        // 使用启动时传递的task
        return mInTask;
    } else {
        // 理论上的可能,不可能走到这里
        final ActivityStack stack = getLaunchStack(mStartActivity, mLaunchFlags,
                null /* task */, mOptions);
        final ActivityRecord top = stack.getTopNonFinishingActivity();
        if (top != null) {
            return top.getTask();
        } else {
            // Remove the stack if no activity in the stack.
            stack.removeIfPossible();
        }
    }
    return null;
}

startActivityInner方法中,根据启动模式计算出flag,再根据flag等条件判断要启动的activity的ActivityRecord是加入现有的Task栈中,还是创建新的Task栈。在未Activity准备好Task栈后,调用RootWindowContainer.resumeFocusedStacksTopActivities方法。

class RootWindowContainer extends WindowContainer<DisplayContent>
      implements DisplayManager.DisplayListener {

    boolean resumeFocusedStacksTopActivities(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

        //...
        boolean result = false;
        if (targetStack != null && (targetStack.isTopStackInDisplayArea()
                || getTopDisplayFocusedStack() == targetStack)) {
            // 调用ActivityStack.resumeTopActivityUncheckedLocked
            result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        //...
        return result;
    }
}

class ActivityStack extends Task {

    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
      if (mInResumeTopActivity) {
          // Don't even start recurscheduleTransactionsing.
          return false;
      }

      boolean result = false;
      try {
          mInResumeTopActivity = true;
          // 继续调用resumeTopActivityInnerLocked
          result = resumeTopActivityInnerLocked(prev, options);

          final ActivityRecord next = topRunningActivity(true /* focusableOnly */);
          if (next == null || !next.canTurnScreenOn()) {
              checkReadyForSleep();
          }
      } finally {
          mInResumeTopActivity = false;
      }

      return result;
  }

  private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {

      // Find the next top-most activity to resume in this stack that is not finishing and is
      // focusable. If it is not focusable, we will fall into the case below to resume the
      // top activity in the next focusable task.
      // 在当前Task栈中找到最上层正在运行的activity,如果这个activity没有获取焦点,那这个activity将会被重新启动
      ActivityRecord next = topRunningActivity(true /* focusableOnly */);
      final boolean hasRunningActivity = next != null;

      if (next.attachedToProcess()) {
          ...
      } else {
          ...
          // 调用StackSupervisor.startSpecificActivity
          mStackSupervisor.startSpecificActivity(next, true, true);
      }
      return true;
  }
}

ActivityStack的作用的用于单个活动栈的管理。最终调到ActivityStackSupervisor . startSpecificActivity

public class ActivityStackSupervisor implements RecentTasks.Callbacks {

    // 检查启动Activity所在进程是否有启动,没有则先启动进程
    void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
        // 根据processName和Uid查找启动Activity的所在进程
        final WindowProcessController wpc =
                mService.getProcessController(r.processName, r.info.applicationInfo.uid);

        boolean knownToBeDead = false;

        if (wpc != null && wpc.hasThread()) {
            // 进程已经存在,则直接启动Activity
            try {
                // 启动Activity ,并返回
                realStartActivityLocked(r, wpc, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
               ...
            }
            knownToBeDead = true;
        }

        // 所在进程没创建则调用ATMS.startProcessAsync创建进程并启动Activity
        mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
    }

    // 启动Activity的进程存在,则执行此方法 
    boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
                                    boolean andResume, boolean checkConfig) throws RemoteException {

        ...

        // 创建活动启动事务
        // proc.getThread()是一个IApplicationThread对象,可以通过ClientTransaction.getClient()获取
        final ClientTransaction clientTransaction = ClientTransaction.obtain(
                proc.getThread(), r.appToken);

        // 为事务设置Callback,为LaunchActivityItem,在客户端时会被调用
        clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
                System.identityHashCode(r), r.info,
                // TODO: Have this take the merged configuration instead of separate global
                // and override configs.
                mergedConfiguration.getGlobalConfiguration(),
                mergedConfiguration.getOverrideConfiguration(), r.compat,
                r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
                r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
                dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
                r.assistToken, r.createFixedRotationAdjustmentsIfNeeded()));

        // 设置所需的最终状态
        final ActivityLifecycleItem lifecycleItem;
        if (andResume) {
            lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
        } else {
            lifecycleItem = PauseActivityItem.obtain();
        }
        clientTransaction.setLifecycleStateRequest(lifecycleItem);

        // 执行事件,调用ClientLifecycleManager.scheduleTransaction
        mService.getLifecycleManager().scheduleTransaction(clientTransaction);

        ...
        return true;
    }
}

ActivityStackSupervisor中,先检查要启动activity的进程是否存在,如果存在则调用realStartActivityLocked方法,通过ClientTransaction事务回调ApplicationThread. scheduleTransaction方法;如果进程不存在,则创建进程。

ATMS小结

  1. ActivityStarter中检查调用进程,intent,权限等检查,通过PKMS获取ResolveInfo,ActivityInfo信息,符合条件的则往下走。
  2. ActivityStarter中根据启动模式计算flag,设置启动activity的Task栈。
  3. ActivityStackSupervisor检查要启动的activity的进程是否存在,存在则向客户端进程ApplicationThread回调启动Activity;否则创建进程。

三、ApplicationThread到启动Activity

下图为ActivityThread启动Activity过程的时序图:


// 主要是处理AMS端的请求
private class ApplicationThread extends IApplicationThread.Stub {
    @Override
    public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
        ActivityThread.this.scheduleTransaction(transaction);
    }
}

// ActivityThread的父类
public abstract class ClientTransactionHandler {

    void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        // 发送EXECUTE_TRANSACTION消息
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
    }
}

// 它管理应用程序进程中主线程的执行,根据活动管理器的请求,在其上调度和执行活动、广播和其他操作。
public final class ActivityThread extends ClientTransactionHandler {

    class H extends Handler {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EXECUTE_TRANSACTION:
                    final ClientTransaction transaction = (ClientTransaction) msg.obj;
                    // 调用TransactionExecutor.execute去处理ATMS阶段传过来的ClientTransaction
                    mTransactionExecutor.execute(transaction);
                    if (isSystem()) {
                        // Client transactions inside system process are recycled on the client side
                        // instead of ClientLifecycleManager to avoid being cleared before this
                        // message is handled.
                        transaction.recycle();
                    }
                    break;
            }
        }
    }
}

public class TransactionExecutor {
    public void execute(ClientTransaction transaction) {
        //...
        // 调用传过来的ClientTransaction事务的Callback
        executeCallbacks(transaction);

        executeLifecycleState(transaction);
    }

    public void executeCallbacks(ClientTransaction transaction) {
        final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
        ...
        final int size = callbacks.size();
        for (int i = 0; i < size; ++i) {
            final ClientTransactionItem item = callbacks.get(i);
            ...
            // 调用LaunchActivityItem.execute
            item.execute(mTransactionHandler, token, mPendingActions);
            item.postExecute(mTransactionHandler, token, mPendingActions);
            ...
        }
    }
}

public class LaunchActivityItem extends ClientTransactionItem {
    public void execute(ClientTransactionHandler client, IBinder token,
                        PendingTransactionActions pendingActions) {
        ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
                mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
                mPendingResults, mPendingNewIntents, mIsForward,
                mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
        // 调用ActivityThread.handleLaunchActivity
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
    }
}

ApplicationThread类绕了一大圈,最后调用在ATMS阶段设置的ClientTransactionCallBackexecute方法,也就是LaunchActivityItem.execute方法,此方法创建一个ActivityClientRecord对象,然后调用ActivityThread. handleLaunchActivity开启真正的Actvity启动。

真正启动activity:
public final class ActivityThread extends ClientTransactionHandler {
    // ActivityThread启动Activity的过程
    @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,
                                         PendingTransactionActions pendingActions, Intent customIntent) {
        // ...
        WindowManagerGlobal.initialize();
        // 启动Activity
        final Activity a = performLaunchActivity(r, customIntent);
    
        if (a != null) {
           ...
        } else {
            // 启动失败,调用ATMS停止Activity启动
            try {
                ActivityTaskManager.getService()
                        .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                                Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    
    return a;
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    // 获取ActivityInfo类
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        // 获取APK文件的描述类LoadedApk
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }
    // 启动的Activity的ComponentName类
    ComponentName component = r.intent.getComponent();

    // 创建要启动Activity的上下文环境
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        // 用类加载器来创建该Activity的实例
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        // ...
    } catch (Exception e) {
        // ...
    }

    try {
        // 创建Application
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        if (activity != null) {
            // 初始化Activity
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.configCallback,
                    r.assistToken);

            ...
            // 调用Instrumentation的callActivityOnCreate方法来启动Activity
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
          ...
        }
      ...

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        ...
    }

    return activity;
}


public class Instrumentation {

    public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        // 调用Activity的performCreate
        activity.performCreate(icicle);
        postPerformCreate(activity);
    }
}

public class Activity extends ContextThemeWrapper
      implements LayoutInflater.Factory2,
      Window.Callback, KeyEvent.Callback,
      OnCreateContextMenuListener, ComponentCallbacks2,
      Window.OnWindowDismissedCallback,
      AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {

    final void performCreate(Bundle icicle) {
        performCreate(icicle, null);
    }

    @UnsupportedAppUsage
    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        ...
        // 调用onCreate方法
        if (persistentState != null) {
            onCreate(icicle, persistentState);
        } else {
            onCreate(icicle);
        }
        ...
    }

}
小结:
  1. ActivityThread.mH中处理EXECUTE_TRANSACTION消息,处理从system_server进程传过来的ClientTransaction,然后回调ClientTransactionItemexecute()方法,而这个ClientTransactionItem就是在ActivityStakSupervisor类的realStartActivityLocked()方法中设置的其子类LaunchActivityItem
  2. 调用LaunchActivityItemexecute()方法,创建了一个ActivityClientRecord,对应system_server进程中的ActivityRecord,其作用是封装保存一个activity的相关信息,并传递到ActivityThread中。
  3. 继续回到ActivityThread中,通过一系列调用,最终来到performLaunchActivity方法:
  • 为ActivityInfo设置packageInfo,是一个LoadedApk类,用来保存当前应用的一些信息,如包名,资源目录等;
  • 创建要启动activity的上下文环境;
  • 通过Instrumentation实例化activity;
  • 创建Application;
  • 调用activity.attach()方法,初始化activity;
  • 调用Instrumentation.callActivityOnCreate()方法启动activity,并在activity的performCreate()方法中回调生命周期onCreate();

最后附一张完整流程图:


Activity启动流程图

原文链接:https://www.jianshu.com/p/aac6064cb41a

前言

在开始实施之前,我们必须制定我们的战略。这将减少命中和试验的次数。

注释处理在处理 Java 注释源代码时提供的东西:

  1. 设置<?****extends TypeElement>:它提供注释列表作为包含在正在处理的 Java 文件中的元素。
  2. RoundEnvironment:它通过实用程序提供对处理环境的访问以查询元素。我们将在这个环境中使用的两个主要函数是:processingOver(意味着知道它是否是最后一轮处理)和getRootElements(它提供将被处理的元素列表。其中一些元素将包含我们正在处理的注释感兴趣的。)

所以,我们有一组注释和一个元素列表。我们的库将生成一个包装类,该类将帮助映射活动的视图和点击监听器。

它将具有以下用法:

activity_main.xml定义了一个TextView带有 id的tv_content按钮和两个带有 id 和bt_1的按钮bt_2。我们的注释将映射视图和按钮以删除样板,就像 ButterKnife 一样。

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.tv_content)
    TextView tvContent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Binding.bind(this);
    }

    @OnClick(R.id.bt_1)
    void bt1Click(View v) {
        tvContent.setText("Button 1 Clicked");
    }

    @OnClick(R.id.bt_2)
    void bt2Click(View v) {
        tvContent.setText("Button 2 Clicked");
    }
}

我们将使用MainActivity定义通过注释处理自动生成名为MainActivity$Binding的包装类。

注意:我们将在其中使用注解的任何 Activity 都将创建一个名称以Binding**结尾的包装类。示例:如果我们有另一个活动,比如**ProfileActivity**,它有`@BindView`或`@OnClick`使用,那么它将导致**ProfileActivityBinding Java 源代码文件的创建。

处理后将创建以下类。

@Keep
public class MainActivity$Binding {
  public MainActivity$Binding(MainActivity activity) {
    bindViews(activity);
    bindOnClicks(activity);
  }

  private void bindViews(MainActivity activity) {
    activity.tvContent = (TextView)activity.findViewById(2131165322);
  }

  private void bindOnClicks(final MainActivity activity) {
    activity.findViewById(2131165218).setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        activity.bt1Click(view);
      }
    });
    activity.findViewById(2131165219).setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        activity.bt2Click(view);
      }
    });
  }
}

现在我们知道我们必须生成什么,让我们分析如何使用我们在处理时掌握的信息来创建它。

  1. 我们将首先过滤掉那些使用@BindView@OnClick来自getRootElements方法提供的元素列表的类 (Type) 元素。
  2. 然后我们将遍历这些过滤的元素,然后扫描它们的成员和方法,以使用JavaPoet 开发包装类的类模式。最后,我们将该类写入 Java 文件。

对于第 1 步,我们希望提高搜索效率。因此,我们将创建一个具有过滤方法的类ProcessingUtils

public class ProcessingUtils {

    private ProcessingUtils() {
        // not to be instantiated in public
    }

    public static Set<TypeElement> getTypeElementsToProcess(Set<? extends Element> elements,
                                                            Set<? extends Element> supportedAnnotations) {
        Set<TypeElement> typeElements = new HashSet<>();
        for (Element element : elements) {
            if (element instanceof TypeElement) {
                boolean found = false;
                for (Element subElement : element.getEnclosedElements()) {
                    for (AnnotationMirror mirror : subElement.getAnnotationMirrors()) {
                        for (Element annotation : supportedAnnotations) {
                            if (mirror.getAnnotationType().asElement().equals(annotation)) {
                                typeElements.add((TypeElement) element);
                                found = true;
                                break;
                            }
                        }
                        if (found) break;
                    }
                    if (found) break;
                }
            }
        }
        return typeElements;
    }
}

这里有两点我们需要了解:

  1. element.getEnclosedElements():封闭元素是包含在给定元素中的元素。在我们的例子中,元素将是MainActivity (TypeElement),而封闭的元素将是tvContentonCreatebt1Clickbt2Click其他继承的成员。
  2. subElement.getAnnotationMirrors():它将提供子元素上使用的所有注释。示例:@Override对于onCreate@BindView对于tvContent@OnClick对于bt1Click

因此,将MainActivitygetTypeElementsToProcess过滤为我们需要处理的TypeElement 。

现在,我们将扫描所有过滤后的元素以创建相应的包装类。

要点:

  1. 查找元素的包:(elementUtils.getPackageOf(typeElement).getQualifiedName().toString()在我们的例子中:com.mindorks.annotation.processing.example)
  2. 获取元素的简单名称:(typeElement.getSimpleName().toString()在我们的例子中为 MainActivity)
  3. 我们需要ClassName来使用注解 API:(ClassName.get(packageName, typeName)它将为 MainActivity 创建一个 ClassName)
  4. 我们必须为包装类MainActivity$Binding创建一个ClassName ,以便我们可以定义它的成员和方法。

注意:为了便于名称维护和良好的编码习惯,我们将创建一个名为NameStore的类。它将包含我们在定义 Binding 类时需要的所有类、变量和方法名称。

public final class NameStore {

    private NameStore() {
        // not to be instantiated in public
    }

    public static String getGeneratedClassName(String clsName) {
        return clsName + BindingSuffix.GENERATED_CLASS_SUFFIX;
    }

    public static class Package {
        public static final String ANDROID_VIEW = "android.view";
    }

    public static class Class {
        // Android
        public static final String ANDROID_VIEW = "View";
        public static final String ANDROID_VIEW_ON_CLICK_LISTENER = "OnClickListener";
    }

    public static class Method {
        // Android
        public static final String ANDROID_VIEW_ON_CLICK = "onClick";

        // Binder
        public static final String BIND_VIEWS = "bindViews";
        public static final String BIND_ON_CLICKS = "bindOnClicks";
        public static final String BIND = "bind";
    }

    public static class Variable {
        public static final String ANDROID_ACTIVITY = "activity";
        public static final String ANDROID_VIEW = "view";
    }
}

此外,您会发现在binder-annotations库的 ( internal -> BindingSuffix)类中添加了$Binding后缀。这样做有两个目的。

  1. 我们希望名称是可配置的,即我们可以将其从$Binding更改为_Binder或其他任何名称。
  2. 它将用于在binderbinder-compiler库中查找生成的类。

JavaPoet 速成课程:

JavaPoet使定义类结构并在处理时编写它变得非常简单。它创建非常接近手写代码的类。它提供了自动推断导入以及美化代码的工具。

要使用 JavaPoet,我们需要将以下依赖项添加到binder-compiler模块中。

dependencies {
    implementation project(':binder-annotations')
    implementation 'com.squareup:javapoet:1.11.1'
}

注意:使用JavaFileObject是非常不切实际和麻烦的。所以,我们甚至不会谈论它。

本教程所需的JavaPoet的基本用法(任何提前了解都可以从其<u style="text-decoration: none; border-bottom: 1px solid rgb(68, 68, 68);">GitHub Repo</u>中获得。)

  1. TypeSpec.Builder:定义类模式。
  2. addModifiers(修饰符):添加私有、公共或受保护的关键字。
  3. addAnnotation:向元素添加注释。示例:在我们的例子中,@ Override方法或@Keep方法。
  4. TypeSpec.Builder -> addMethod:向类添加方法。示例:构造函数或其他方法。
  5. MethodSpec -> addParameter:为方法添加参数类型及其名称。示例:在我们的例子中,我们希望将带有变量名activity的MainActivity类型传递给方法。
  6. MethodSpec -> addStatement:它将在方法中添加代码块。在这个方法中,我们首先定义语句的占位符,然后传递参数来映射这些占位符。示例:(addStatement("$N($N)", "bindViews", "activity") 这将生成代码bindViews(activity))。PlaceHolders : N -> names** , **T -> type (ClassName), $L -> literals (long etc.)。

其余的东西可以参考这个JavaPoet的基本介绍很容易理解。我把休息留给你自己弄清楚。我就是这样学习的。

最后一步:编写java源代码。

使用 JavaPoet 编写定义的类模式非常简单。

// write the defines class to a java file
try {
    JavaFile.builder(packageName,
            classBuilder.build())
            .build()
            .writeTo(filer);
} catch (IOException e) {
    messager.printMessage(Diagnostic.Kind.ERROR, e.toString(), typeElement);
}

它将在文件夹中生成源代码。/app/build/generated/source/apt/debug

在我们的例子中:/app/build/generated/source/apt/debug/com/mindorks/annotation/processing/example/MainActivity$Binding.java

作者:Janishar Ali
链接:Android Annotation Processing Tutorial: Part 3: Generate Java Source Code

原文链接:https://www.jianshu.com/p/dd10bc5fb267

从「树」结什么「果子」,你就知道这个「树」是怎样的树。

「树的本质」跟「果子的本质」一定是一样的;「树的品种」跟「树的果子的品种」一定一样的。

如果你种的苹果,出的是芒果的果子,这是不可能的事情,因为你种的是葡萄,不可能产生蒺藜,如果你种的是无花果,不可能产生荆棘,这是上帝讲的。

所以「树」跟「果」之间有两方面的相同点,第一就是「品种」的相同点,第二就是「质量」的相同点。

一个有这种「品种」的树,一定产生有这样「品种」的果子。照样,有这种「质量」的树,就会产生有这种「质量」的果子...

原文链接:https://www.jianshu.com/p/2e2f823de31a

前面两篇文章我们讲解了整个AOP切面的实现,刚开始我以为AOP也就这么多东西了,而当我总结起来时才发现,这仅仅是AOP的开始,相信你看完本篇文章会有:曲径通幽,豁然开朗 的感觉

从AOP到方法论

我们还是来看看AOP为我们搭建了一个怎样的框架(或者说一个黑盒吧):整个链路的流程如下:

准备阶段:查找所有增强器--> 筛选可以应用到当前对象的增强器 --> 构建代理对象

执行阶段:当代理对象的方法被调用时 --> 构建责任链 --> 执行时走责任链逻辑;

其中查找所有的增强器:Spring会获取所有的Advisor,如果开启了@Aspect的功能就会额外加载标有@Aspect的类,然后将标有@Before、@After等注解的方法封装成Advisor【InstantiationModelAwarePointcutAdvisorImpl】;
筛选可以应用到当前对象的增强器:主要分类两类的筛选:一类是IntroductionAdvisor即类级别的切入,这一类是通过Advisor中的ClassFilter来进行判断是否切入当前对象;另一个是PointcutAdvisor即方法级别的切入,会通过PointCut中的ClassFilter和MethodMatcher分别来进行类及方法级别的筛选,判断是都切入当前方法。构建代理对象,以及执行时责任链的封装这些都不需要我们来管的。总的来说,我们如果需要使用Sping的这套AOP框架来实现我们的业务逻辑,我们只需要写好自己的增强器(Advisor)就可以了,而这个过程中就包含了两个主要的部分:1、编写Advice,也就是我们的拦截逻辑;2、拦截的筛选规则,也就是上面提到的ClassFilter或者PointCut;也就是告诉Spring你要拦截什么,怎么拦截。
好了,说到这里我相信很多人应该都明白如何通过Spring提供的AOP框架来实现自己的业务逻辑拦截,如果没懂也没关系,接下来我们看看Spring家自己是如何在这个AOP框架的基础上扩展出更多功能的:

AOP方法论在Spring中的身影

1、Spring的事务实现

要看Spring的事务是如何实现的,我们看看开启Spring事务时都引入了什么?那我们就要从@EnableTransactionManagement注解到入了什么组件到容器中下手,let we see see :
@EnableTransactionManagement导入了TransactionManagementConfigurationSelector类,TransactionManagementConfigurationSelector帮我们导入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个类,前者是为了能开启AOP的功能,我们先不说,ProxyTransactionManagementConfiguration这个类才是Spring事务发挥作用的关键先生,一起来一探究竟吧:

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    // 创建了用于事务的Advisor
    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
            TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        // 设置transactionAttributeSource
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        // 设置Advice
        advisor.setAdvice(transactionInterceptor);
        if (this.enableTx != null) {
            advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        }
        return advisor;
    }

    //封装事务管理配置的参数,@Transactional(..)中的参数
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource);
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

}

哦豁,映入眼帘的是熟悉的Advisor和Advice,也是验证我们上面所说的方法论。就从我们熟练使用Spring申明是事务注解@Transactional的角度来说,PointCut中肯定就会匹配@Transactional这个注解,然后在Advice中帮我们建立连接,开启事务,执行sql,提交或回滚事务。详细的事务讲解,我会留在下一个模块中来讲解,毕竟Spring事务中还是有很多有趣的点的,而且他也是面试的常客之一啊,不单独给一个模块描述不应该。

2、Spring的缓存实现

在查看了Spring事务的逻辑,再来看Spring的缓存逻辑其实是大差不差的,我们直接来看开启Spring缓存的@EnableCaching注解为我们向Spring中导入了什么组件,其实在不引入JSR107和JcacheImpl的情况下,也是为我们引入了两个组件:AutoProxyRegistrar和ProxyCachingConfiguration,同样,前者我们先不关心,我们来看看ProxyCachingConfiguration里给我们带来了什么:

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {

    @Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor(
            CacheOperationSource cacheOperationSource, CacheInterceptor cacheInterceptor) {

        BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor();
        advisor.setCacheOperationSource(cacheOperationSource);
        advisor.setAdvice(cacheInterceptor);
        if (this.enableCaching != null) {
            advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));
        }
        return advisor;
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public CacheOperationSource cacheOperationSource() {
        return new AnnotationCacheOperationSource();
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public CacheInterceptor cacheInterceptor(CacheOperationSource cacheOperationSource) {
        CacheInterceptor interceptor = new CacheInterceptor();
        interceptor.configure(this.errorHandler, this.keyGenerator, this.cacheResolver, this.cacheManager);
        interceptor.setCacheOperationSource(cacheOperationSource);
        return interceptor;
    }

}

我相信,你看到这一串代码,你都不敢相信吧,这和事务的逻辑几乎一模一样啊,是不是,CacheAdvisor以及CacheInterceptor,都是同样的套路,都是上面所说的方法论,用起来简直不要太方便。

3、Spring异步的实现

看了上面Spring事务和Spring缓存的实现,对于Spring异步De实现你是不是也能猜到是怎么实现的了,我们直接看@EnableAsync引入的ProxyAsyncConfiguration吧:

    public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {

    @Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
        Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
        AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
        bpp.configure(this.executor, this.exceptionHandler);
        Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
        if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
            bpp.setAsyncAnnotationType(customAsyncAnnotation);
        }
        bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
        bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
        return bpp;
    }

}

乍看第一眼,我们并没有看到我们预料中的Advisor和Interceptor(Advice),而是构建了一个Bean的后置处理器AsyncAnnotationBeanPostProcessor,并为这个后置处理器配置了线程池executor和异常处理器exceptionHandler,那么异步的处理就是在AsyncAnnotationBeanPostProcessor中实现的,我们在进一步看看AsyncAnnotationBeanPostProcessor这个类,它里面的实现究竟是怎么样的呢?

    public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {


    public static final String DEFAULT_TASK_EXECUTOR_BEAN_NAME =
            AnnotationAsyncExecutionInterceptor.DEFAULT_TASK_EXECUTOR_BEAN_NAME;


    protected final Log logger = LogFactory.getLog(getClass());

    // 此处省略若干行代码

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        super.setBeanFactory(beanFactory);

        // 此处注入了 AsyncAnnotationAdvisor
        AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);
        if (this.asyncAnnotationType != null) {
            advisor.setAsyncAnnotationType(this.asyncAnnotationType);
        }
        advisor.setBeanFactory(beanFactory);
        this.advisor = advisor;
    }

}

其中的一起配置方法我们不看,我们就看下最后的setBeanFactory方法,哈哈,惊不惊喜,意不意外,一个大大的Advisor映入了眼帘,这不就是我们期望的吗,读者可能会问那Adice在哪呢?难道你忘记了Advisor是Advice和Pointcut的整合,那么Advisor中当然包含了Advice和Poincut的构建了,不妨一看:

        public AsyncAnnotationAdvisor(
            @Nullable Supplier<Executor> executor, @Nullable Supplier<AsyncUncaughtExceptionHandler> exceptionHandler) {

        Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<>(2);
        asyncAnnotationTypes.add(Async.class);
        try {
            asyncAnnotationTypes.add((Class<? extends Annotation>)
                    ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
        }
        catch (ClassNotFoundException ex) {
            // If EJB 3.1 API not present, simply ignore.
        }
        this.advice = buildAdvice(executor, exceptionHandler);
        this.pointcut = buildPointcut(asyncAnnotationTypes);
    }

buildAdvice,buildPointcut这两个方法就是分别来构建Advice和Pointcut的。
但是Spring异步的实现和前面两个的实现确实是有点不同的,首先我们发现在注入的时候@EnableAsync仅仅引入了一个ProxyAsyncConfiguration,并没有像前面两个一样引入AutoProxyRegistrar,而AutoProxyRegistrar的作用就是基于自己是BeanPostProcessor通过bean的生命周期方法postProcessBeforeInstantiation来帮助完成扫描缓存所有的Advisor,然后再通过bean的生命周期方法postProcessAfterInstantiation帮忙给可以应用Advisor的bean创建代理对象,而能够在执行的时候走到责任链的拦截模式关键就是创建出代理对象;那么Spring异步是如何来帮助我们创建代理对象的呢?其实你被忘了,Spring异步的实现本来就是靠的一个BeanPostProcesor即AsyncAnnotationBeanPostProcessor,所以Spring家将创建代理对象的逻辑也就放在了AsyncAnnotationBeanPostProcessor的postProcessAfterInitialization方法中。看到这个地方,你有没有一个疑问,如果我同时在一个方法上标注了@Transactional和@Async注解,那么它不是会走两遍创建代理对象的逻辑吗?确实是这样的,Spring也对这一情况做了兼容,来一起看下AsyncAnnotationBeanPostProcessor的postProcessAfterInitialization这个方法:

    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (this.advisor == null || bean instanceof AopInfrastructureBean) {
            // Ignore AOP infrastructure such as scoped proxies.
            return bean;
        }

        // 兼容走aop的逻辑已经生成了的代理对象,那么只需要将异步的这个增强器添加到代理对象的增强器集合中就可以了
        if (bean instanceof Advised) {
            Advised advised = (Advised) bean;
            if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
                // Add our local Advisor to the existing proxy's Advisor chain...
                if (this.beforeExistingAdvisors) {
                    advised.addAdvisor(0, this.advisor);
                }
                else {
                    advised.addAdvisor(this.advisor);
                }
                return bean;
            }
        }
        // 帮助创建代理对象
        if (isEligible(bean, beanName)) {
            ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
            if (!proxyFactory.isProxyTargetClass()) {
                evaluateProxyInterfaces(bean.getClass(), proxyFactory);
            }
            proxyFactory.addAdvisor(this.advisor);
            customizeProxyFactory(proxyFactory);
            return proxyFactory.getProxy(getProxyClassLoader());
        }

        // No proxy needed.
        return bean;
    }

如果当前这个bean已经经历过了AOP的增强成代理对象,那么它就属于Advised类型的,我们只需要把当前这个异步的Advisor加入到这个代理对象的增强器链中就可以了;而如果这个bean对象没有经历过AOP的代理,那么就会在此处为它创建代理对象,然后的执行流程都是一样的。至于为什么Spring在实现异步封装的时候没有像实现事务和缓存那样直接基于AOP框架来实现,我也不是很清楚,可能是为了提供一种新的方式来实现告诉读者是可以一题多解的吧,也有可能就是不同的人有不同的想法呢,毕竟作者也不是同一个人,而且这种情况在Spring中也不是第一次出现了,前面我们讲的增强器转拦截器一样使用两种不同的实现方法。

写在最后

好了,说到这里这篇文章也就差不多了,虽然我只讲了Spring中事务,缓存,异步这三种实现的应用,但是在Spring中基于AOP框架的实现不仅仅于此,还有@Validated以及mybatis-plus中多数据源@DS的实现,等等等等。我们需要的是掌握这个方法论,懂了方法论,不管是在以后的开发中,还是以后看别的源码时,就能很快的了解实现的原理,是事倍功倍的。关于AOP就讲到这里了;接下来,我会开始讲解Spring的事务实现,这也是面试的一个高频点,希望对有缘人有所帮助。

原文链接:https://www.jianshu.com/p/912a23e5f01b