服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

手把手带你搞懂AMS启动原理

日期: 来源:郭霖收集编辑:Pingred


/   今日科技快讯   /

近日,加拿大政府以维护政府信息安全为由,宣布禁止在政府部门使用的移动设备上使用TikTok(抖音海外版)应用程序。按加官方要求,从2023年2月28日起,TikTok应用程序将被从加政府发放的移动设备上删除;这些设备的使用者也不得下载该应用程序。

/   作者简介   /

本篇文章来自Pingred_hjh的投稿,文章主要分享了AMS启动原理的相关内容,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。

Pingred_hjh的博客地址:
https://blog.csdn.net/qq_39867049?type=blog

/   开始   /

最近那么多教学视频(特别是搞车载的)都在讲AMS,可能这也跟要快速启动一个app(甚至是提高安卓系统启动速度有关),毕竟作为安卓系统的核心系统服务之一。

我们都知道当手机开机时,或者是安装某个apk时,PMS会去扫描加载/data/app目录和system/app里每个apk里的所有类信息并且进行解析,然后缓存到PMS它自己里面定义好的集合里,供AMS使用,AMS即ActivityManagerService就能根据PMS里面的这些类信息来进行创建入口Activity等四大组件类并启动。下面将详细讲解AMS是怎样工作的。

/   回顾PackageManagerService   /

讲AMS之前,还是得回顾一下PMS的工作流程,PMS会把每个apk进行扫描,然后分别把每个apk里的信息都缓存在mPackages集合里:


它是PackageParser.Package类型,所以我们看看这个类里的内容:

public final static class Package implements Parcelable {

        @UnsupportedAppUsage
        public String packageName;

        // The package name declared in the manifest as the package can be
        // renamed, for example static shared libs use synthetic package names.
        public String manifestPackageName;
        ...

        // For now we only support one application per package.
        @UnsupportedAppUsage
        public ApplicationInfo applicationInfo = new ApplicationInfo();

        @UnsupportedAppUsage
        public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
        @UnsupportedAppUsage
        public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
        @UnsupportedAppUsage
        public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
        @UnsupportedAppUsage
        public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
        @UnsupportedAppUsage
        public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
        @UnsupportedAppUsage
        public final ArrayList<Service> services = new ArrayList<Service>(0);
        @UnsupportedAppUsage
        public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);

        @UnsupportedAppUsage
        public final ArrayList<String> requestedPermissions = new ArrayList<String>();
        ...
}

明显可以看到这些集合都是分别缓存四大组件以及一些权限以及跳转意图等信息,每个apk对应一个Package:


Package是在PMS里,而PMS又是作为一个对象被SystemServer所拥有,SystemServer进程是被zygote进程所开启的,而zygote进程又是给init进程孵化的:


init进程是安卓手机开机后第一个启动的进程:


我们可以从系统源码中看看它的配置脚本文件init.rc写了什么内容:

# Copyright (C) 2012 The Android Open Source Project
#
# IMPORTANT: Do not create world writable files or directories.
# This is a common source of Android security bugs.
#

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc

on early-init
    # Set init and its forked children's oom_adj.
    write /proc/1/oom_score_adj -1000

    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0

    # Set the security context of /adb_keys if present.
    restorecon /adb_keys

    # Shouldn't be necessary, but sdcard won't start without it. http://b/22568628.
    mkdir /mnt 0775 root system

    # Set the security context of /postinstall if present.
    restorecon /postinstall

    start ueventd

on init
    sysclktz 0

    # Mix device-specific information into the entropy pool
    copy /proc/cmdline /dev/urandom
    copy /default.prop /dev/urandom

    # Backward compatibility.
    symlink /system/etc /etc
    symlink /sys/kernel/debug /d

    # Link /vendor to /system/vendor for devices without a vendor partition.
    symlink /system/vendor /vendor

    # Mount cgroup mount point for cpu accounting
    mount cgroup none /acct cpuacct
    mkdir /acct/uid

    # Create energy-aware scheduler tuning nodes
    mkdir /dev/stune
    mount cgroup none /dev/stune schedtune
    mkdir /dev/stune/foreground
    mkdir /dev/stune/background
    mkdir /dev/stune/top-app
    ...

它里面是配置服务的逻辑,很多手机厂商在这里设置它们专属的一些常驻服务的地方,就是在这里改动的,其中可以看到这里:

import /init.${ro.zygote}.rc

配置了zygote进程,引入了zygote.rc文件,我们来看看32位下的zygote.rc文件:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

代码很少,但可以看到,这里面它启动了zygote进程服务的main方法。那么再来总结一下整个系统启动流程:


SystemServer的启动服务、核心服务以及其他服务如下源码所示启动,启动服务就包括PMS和AMS等这些服务:

    // Start services.
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
        ...

startBootstrapServices()方法里就是启动AMS和PMS等:

  ...
        // Activity manager runs the show.
        traceBeginAndSlog("StartActivityManager");
        // TODO: Might need to move after migration to WM.
        ActivityTaskManagerService atm = mSystemServiceManager.startService(
                ActivityTaskManagerService.Lifecycle.class).getService();
        mActivityManagerService = ActivityManagerService.Lifecycle.startService(
                mSystemServiceManager, atm);
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);
        mWindowManagerGlobalLock = atm.getGlobalLock();
        traceEnd();
        ...

        traceBeginAndSlog("StartPackageManagerService");
        try {
            Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
            mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        } finally {
            Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
        }
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
        traceEnd();
        ...

但这里要注意的是PMS和AMS它们是作为一个对象被SystemServer所持有的:

public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        // Self-check for initial settings.
        PackageManagerServiceCompilerMapping.checkProperties();

        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        m.enableSystemUserPackages();
        ServiceManager.addService("package", m);
        final PackageManagerNative pmn = m.new PackageManagerNative();
        ServiceManager.addService("package_native", pmn);
        return m;
    }

main()方法只是一个普通的构造PackageManagerService它自己对象的方法,它是直接new的,并没有开启单独的进程,AMS也是如此:

public <T extends SystemService> T startService(Class<T> serviceClass) {
        try {
            final String name = serviceClass.getName();
            Slog.i(TAG, "Starting " + name);
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);

            // Create the service.
            if (!SystemService.class.isAssignableFrom(serviceClass)) {
                throw new RuntimeException("Failed to create " + name
                        + ": service must extend " + SystemService.class.getName());
            }
            final T service;
            try {
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
            }
            ...
            startService(service);
            return service;
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        }
    }

它也只是通过反射去实例化自己,而且都是在SystemServer里进行的。以下这些服务对象都被SystemServer所持有:

   // TODO: remove all of these references by improving dependency resolution and boot phases
    private PowerManagerService mPowerManagerService;
    private ActivityManagerService mActivityManagerService;
    private WindowManagerGlobalLock mWindowManagerGlobalLock;
    private WebViewUpdateService mWebViewUpdateService;
    private DisplayManagerService mDisplayManagerService;
    private PackageManagerService mPackageManagerService;
    private PackageManager mPackageManager;
    ...

既然我们都知道PMS会去扫描Apk文件,那么它的扫描方法就是使用Packageparser扫描的,最终得到Package:


所以我们完全可以通过反射PackageParser,然后调用它的parsePackage方法,传apk路径进去,然后得到Package对象,拿到这个Package对象后,你就可以通过DexClassLoader配合着Package对象去反射构造你想要的apk里的类对象,这样一种思路是可以被用到很多应用场景的,比如热修复、插件化以及换肤功能等。

DexClassLoader dexClassLoader = new DexClassLoader("apk路径","apk被缓存后的dex文件路径"
                            ,null,classLoader类加载器 );
    Class clazz = dexClassLoader.loadClass("要反射的类全类名路径");   
    ... 

这样就已经相当于把一个apk文件里的某个类文件对象给找出来了,当然还有很多细节以及具体用法就靠大家去自己琢磨了。

所以,总的来说,PMS它只是把apk里也就是清单文件里定义的四大组件以及一些权限、意图信息等缓存在它里面的Package类里,然后供AMS去迅速定位到某一个类,然后创建它和启动它,这样就能确保我们启动App时不会耗时太长。

/   ActivityManagerService   /

当我们安卓手机开机成功后,就处在桌面上,我们点击某个app的图标时,Launcher进程就会请求SystemServer进程里的AMS去创建这个app的入口(启动)Activity,这时AMS就会请求zygote进程去孵化出该app应用进程:


只要是跟zygote进程通信的都采用socket方式之外,其他进程互相通信都是采用binder方式。使用过binder来进行进程间通信都知道,binder相当于强引用,客户端能直接获取到服务端引用,从而可直接接触到服务端进程对象及其方法,从安全方面考虑这样是不安全的;另外,zygote进程一旦挂掉,会影响到整个系统重启,因此不能让其他进程能轻易影响到zygote进程,本身Socket就相当于弱引用,只通过参数进行通信,安全性就较强,因此就采用socket方式来跟zygote进程通信。

我们来看看zygote进程的main方法:

 @UnsupportedAppUsage
    public static void main(String argv[]) {
        ZygoteServer zygoteServer = null;

        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        // Zygote goes into its own process group.
        try {
            Os.setpgid(0, 0);
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        ...

ZygoteServer里可以看到有一个叫LocalServerSocket变量:

/**
Server socket class for zygote processes. 
Provides functions to wait for commands on a UNIX domain socket, 
and fork off child processes that inherit the initial state of the VM.% 
Please see ZygoteArguments for documentation on the client protocol.
*/
class ZygoteServer {
    // TODO (chriswailes): Change this so it is set with Zygote or ZygoteSecondary as appropriate
    public static final String TAG = "ZygoteServer";

    ...

    /** The default value used for the USAP_POOL_SIZE_MIN device property */
    private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1";

   ...
     */
    private LocalServerSocket mZygoteSocket;

    /**
     * The name of the unspecialized app process pool socket to use if the USAP pool is enabled.
     */
    private LocalServerSocket mUsapPoolSocket;

    ...

LocalServerSocket就是Socket对象:

package android.net;

...

/**
 * Non-standard class for creating an inbound UNIX-domain socket
 * in the Linux abstract namespace.
 */
public class LocalServerSocket implements Closeable {
    private final LocalSocketImpl impl;
    private final LocalSocketAddress localAddress;

    /** 50 seems a bit much, but it's what was here */
    private static final int LISTEN_BACKLOG = 50;

    /**
     * Creates a new server socket listening at specified name.
     * On the Android platform, the name is created in the Linux
     * abstract namespace (instead of on the filesystem).
     * 
     * @param name address for socket
     * @throws IOException
     */
    public LocalServerSocket(String name) throws IOException
    {
        ...
    }
    ...

Launcher进程请求AMS创建该app进程的入口Activity时,AMS会请求Zygote进程孵化出该app应用进程先,然后AMS就会通过binder方式去跟该app应用进程进行通信,也就是在app应用进程里通过ActivityThead去创建入口Activity并启动:


这里要注意的是app进程是不能逆向跟zygote通信,zygote是单向孵化出app进程,所以它们不是双向的。只有一些系统服务进程才能直接跟zygoet通信。

/   源码   /

接下来我们将从源码的角度去分析整个启动过程,首先来看整个过程的时序图:


Launcher首先会去调用启动Activity方法,由于第一次点击启动活动肯定是为空(就算是不为空),最终还是会去调用Instrumentation的execStartActivity()方法:

public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

点进去看该方法execStartActivity(),里面也是调用了一个ActivityTaskManager.getService()的startActivity()方法:

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

       IApplicationThread whoThread = (IApplicationThread) contextThread;
        Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }

        ...
       try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), 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;
    }

而这里的getService返回的是IActivityManager对象,它其实是Binder接口对象,通过它可以拿到AMS对象:

public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
};

所以现在就可以调用AMS的startActivity方法:

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

系统中的所有应用进程都是由Zygote进程fork出来的,SystemServer进程是系统进程,它里面有很多系统服务,例如ActivityManagerService、PackageManagerService、WindowManagerService等等都是存在SystemServer进程被创建后启动;ActivityManagerServices(AMS)是一个服务端对象,负责所有的Activity的生命周期,AMS通过Binder机制与App应用进程通信,那就代表App应用进程是能够拿到AMS对象,而AMS也就能调度App进程去创建Activity等这些组件并且启动它们。

而ActivityThread是App应用进程里的类,是UI线程/主线程,它的main()方法是APP的真正入口;ApplicationThread是一个实现了IBinder接口的ActivityThread内部类,它跟ActivityThread之间是通过Handler机制通信的,这样ApplicationThread就能让ActivityThread和AMS的所在进程间通信(也就是应用进程与SystemServer进程通信);Instrumentation可以理解为ActivityThread的一个工具类,在ActivityThread中初始化,一个进程只存在一个Instrumentation对象,负责调用Activity的生命周期方法:

public void callActivityOnCreate(Activity activity, Bundle icicle,
            PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);
        postPerformCreate(activity);
    }

activity随后就执行它的生命周期方法:

final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        ...
        if (persistentState != null) {
            onCreate(icicle, persistentState);
        } else {
            onCreate(icicle);
        }
       ...
    }

说到这里,我们也可以去看看29以下的版本的源码是怎样的,比如23里的Instrumentation调用的execsStartActivity方法:

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        ...
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), 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;
    }

它的调用是由ActivityManagerNative.getDefault()来执行,那么来跟踪一下getDefault()方法:

//Retrieve the system's default/global activity manager.
static public IActivityManager getDefault() {
        return gDefault.get();
    }

这个gDefault是一个内部类,而且是static修饰的:


我们点进去看它的详情:

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

它是一个抽象类Singleton,继续看这个类的详情:

public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

看它的get方法,就可以推测到,它实际上就是一个单例,只不过是由实现它之后子类自己实现的create方法来决定具体逻辑,那么就来看实现了它的IActivityManager的create方法:

protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }

可以看到,里面是调用了ServiceManager.getService()方法。那么现在来看,当我们的App应用进程调用gDafault.get()方法时,返回的是一个单例对象Singleton,而这个单例对象对应的也就是IActivityManager对象(因为IActivityManager实现了Singleton),它在这里构造时如果是空的,则会调用抽象方法create方法生成,而具体的create实现方法里调用了ServiceManager的getService方法,这样就通过IBinder拥有了AMS的引用了。

值得一提的是,作为app应用开发者,我们可以使用反射去获取Singleton的mInstance变量,因为mInstance它就是AMS,而且它是单例的,即只有一份:

public abstract class Singleton<T> {
    private T mInstance;
   ...
}

/   Hook   /

既然我们上面说到了可以去反射Singleton的mInstance变量,从而得到AMS,这个过程实际上就是常说的Hook技术。Hook技术其实是在A与B交流的过程中,在中途把消息给拦截,然后再做一些自定义操作,最后再把消息给传去给B:


不过记住的是,hook之后,不能影响到后续流程,也就是说你的hook处理怎么处理都行,但不能影响到整个流程,否则就会导致整个流程错乱而跑不动了,因为这是一个一环扣一环的流程,你现在是从中间hook进来,做了一些额外的处理,势必会影响到流程,因此你的处理流程里必须要让hook之后回到原来的流程顺序,从而保证程序能继续运行。

而hook一般是hook系统进程,这才有意义:


一般来说,自己开发的应用不需要hook,因为源码就是我们自己写的,直接使用就可以,而一些系统应用因为安全性是不直接开放给开发者的,但有时又确实是需要使用它里面的一些功能,那这时候就可以去hook它们,因此hook可以分类为:

1)根据Hook的API语言划分(Hook Java、Hook Native)
2)根据Hook的进程划分(应用进程、全局)
3)根据Hook的实现方式划分

去hook java相对来说会比较容易,使用反射和代理实现,从而修改SDK代码的执行流程。

我们来看看怎么去hook一下AMS启动应用的入口Activity流程,我们现在假设找到了系统的源码,其中ActivityManager类如下(一段伪代码):

//系统层
public class ActivityManager {
    public IActivityManager activityManager = new IActivityManager();

    class IActivityManager{

        private String managerName;
        ...
    }
    ...
}

它已经在我们应用中开始前就在系统里运行,该IActivityManager对象已经在内存中存在,而现在我们应用层里无论怎么new它,或者使用反射去构造它,都不是原来那个运行着的系统对象,我们构造的只是一个在应用层里全新的一个对象,因此这样是不能够hook AMS启动应用的入口Activity的流程,也就是没有hook点。那这种情况下要怎么去hook呢?答案是用static去修饰IActivityManager:

//系统层
public class ActivityManager {
    public static IActivityManager activityManager = new IActivityManager();

    class IActivityManager{

        private String managerName;
        ...
    }
}

这时应用层里,可以通过反射去获取这个静态对象,因为它是static修饰,只有一份,因此不管你是不是一早就在内存里运行还是后来构造,整个内存都是只此一份,它也就是系统进程里独有的那个对象了。

所以hook点往往就是去hook那些static修饰的对象,因为只有一份,所以可以使用反射去获取它,同理我们也可以这样使用hook去获取AMS对象。

我们在上文分析源码时知道,gDefalut里的mInstance是AMS对象,是单例的,只有一份,因此可以反射来获取它:

 Field gDefault = null;
 Class<?> ActivityManagerNativecls = Class.forName("android.app.ActivityManagerNative");
 gDefault = ActivityManagerNativecls.getDeclaredField("gDefault");
 gDefault.setAccessible(true);
 Object defaultValue = gDefault.get(null);
 Class<?> SingletonClass = Class.forName("android.util.Singleton");
 Field mInstance = SingletonClass.getDeclaredField("mInstance");
 mInstance.setAccessible(true);

先获取gDefalut变量,然后再获取Singleton变量,最后获取它的mInstance变量对象即ActivityManager对象:

Object iActivityManagerObject = mInstance.get(defaultValue);

这样也就获得了AMS对象了。不过这是在安卓23版本的情况下的hook逻辑,当回到安卓28版本的时候,这时源码有变动了,变成:

public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

此时gDefalut变成了IActivityManagerSingleton,因此反射时就要做版本适配了,根据版本号的不同来反射对应的变量,进而取出它那唯一的AMS变量:

Field gDefault = null;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            Class<?> ActivityManagerNativecls = Class.forName("android.app.ActivityManagerNative");
            gDefault = ActivityManagerNativecls.getDeclaredField("gDefault");
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
            Class<?> activityManager = Class.forName("android.app.ActivityManager");
            gDefault = activityManager.getDeclaredField("IActivityManagerSingleton");
        } else {
            //其他版本就交给大家自行去研究源码了
        }
        ...

继续上面讲到的拿到AMS对象后,我们就可以使用动态代理(之后会更新一篇专门讲动态代理的文章,感兴趣的大家可继续期待)的方式来处理AMS对象了:

    ...
    Object iActivityManagerObject = mInstance.get(defaultValue);
    Class<?> IActivityManagerIntercept = Class.forName("android.app.IActivityManager");
        Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{IActivityManagerIntercept}, new AmsInvocationHandler(iActivityManagerObject));
        mInstance.set(defaultValue, proxy);

        class AmsInvocationHandler implements InvocationHandler {

        private Object iActivityManagerObject;
        public AmsInvocationHandler(Object iActivityManagerObject) {
                    this.iActivityManagerObject = iActivityManagerObject;
                }

        @Override
                public Object invoke(Object o, Method method, Object[] args) throws Throwable {
                //Hook逻辑
                return method.invoke(iActivityManagerObject,args);
        }
    }   

使用动态代理是为了不影响到AMS对象,把处理过程都放在处理器来处理,起到隔离作用,还能监听AMS对象所执行的方法。当启动程序后,调用了hook方法后,系统使用AMS调用的方法都一一交由invoke方法去监听,然后我们返回method的invoke()方法让它继续执行,不断监听。

PMS同样也是可以hook的,因为它也是static修饰的,只有一份:

public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        sPackageManager = IPackageManager.Stub.asInterface(b);
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }    


反射方式去获取PMS对象跟AMS一样:

  // 获取全局的ActivityThread对象
            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
            Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");
            Object currentActivityThread = currentActivityThreadMethod.invoke(null);//得到ActivityThread对象

             // 获取ActivityThread里面原始的 sPackageManager
            Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
            sPackageManagerField.setAccessible(true);
            Object sPackageManager = sPackageManagerField.get(currentActivityThread);
            ...
            //使用动态代理处理sPackageManager

然后同样使用动态代理去接收与处理PMS对象:

class HookPmsHandler implements InvocationHandler {

        private Object iPmsObject;

        public HookHandler(Object iPmsObject) {
            this.iPmsObject= iPmsObject;
        }

        @Override
        public Object invoke(Object o, Method method, Object[] args) throws Throwable {
            Log.i("david","----------------pms------------   "+method.getName());
            return method.invoke(iPmsObject,args);
        }
    }

这样就能监听到PMS的执行方法了。现在我们通过动态代理来监听它整个启动流程会执行的各种方法,那其中肯定也包括startActivity方法,那我们自然就能利用它来修改Activity之间跳转的逻辑,比如现在当我从MainActivity跳转到TwoActivity时根据是否登录状态来决定要跳转到登录页面还是直接跳转到TwoActivity,那么上面AMS的动态代理方法就会触发,而我们就监听startActivity的方法,因为AMS肯定是会调用这个方法的,然后再判断此时登录状态来进行对应的跳转逻辑。

这样就可以仅仅在一个地方进行管理和判断所有Activity的登录状态,然后实现是否要跳转的集中式登录判断功能,这是非常好用的,这样也就不需要在每个Activity上都要进行判断,不过要注意的是我们上面已经讲到了hook的原则,就是处理了你要处理的逻辑之后,还要让它的后续流程能顺利执行下去,所以上面例子要修改跳转到哪个Activity上可以通过修改它的Intent意图参数来实现。还有很多这样的场景就交由读者自己去琢磨了。

/   总结   /

整个app启动过程,所有参与的类以及它们的关系流程:


当点击应用图标的那刻起,Launcher进程会去发送请求AMS要启动Activity(通过Binder方式通信),AMS这时会通过Socket方式请求Zygote去创建应用进程,应用进程被Zygote孵化后,应用进程就会通过binder方式去请求AMS通信,然后AMS就开始从PMS里去获取需要启动的Activity里的信息,然后把这些信息都通过binder方式发送给应用进程,应用进程里的ApplicationThread接受到后,就会通过Handler方式发送给ActivityThread去创建与启动Activity,之后的具体实现就是由ActivityThread的Instrumentation去实现,进而启动Activity。

推荐阅读:
我的新书,《第一行代码 第3版》已出版!
Android自定义通知方方面面全适配
Kotlin协程开发的基础入门知识

欢迎关注我的公众号
学习技术或投稿


长按上图,识别图中二维码即可关注


相关阅读

  • 实现一个简单的 Spring Bean 容器

  • 面对复杂的源码,试着找到开头和结尾是一件非常具有挑战的事。为了让更多的初学者上手,从本文开始,我们将通过实践的方式带领读者逐步实现 Spring 框架的核心链路和功能逻辑。简
  • 一些顶级 JavaScript 技巧汇总

  • 英文 | https://medium.com/stackanatomy/top-javascript-shorthand-techniques-64920294f0c8JavaScript包含各种对典型编程思想有用的一些技巧,在实际开发中,我们通常希望减
  • SpringMVC:注解@ControllerAdvice的工作原理

  • 来源:blog.csdn.net/andy_zhang2007/article/details/100041219Spring MVC中,通过组合使用注解@ControllerAdvice和其他一些注解,我们可以为开发人员实现的控制器类做一些全局
  • @成都人,这一全国普查来了!请配合!

  • 近日,成都市人民政府印发《关于做好第五次全国经济普查工作的通知》(成府发〔2023〕5号),全面部署我市第五次全国经济普查。
    第五次全国经济普查目的、意义是什么?普查对象、内容
  • 文科必会:用“民族志”方法,写深度论文

  • 本文来自百万硕博成长平台“科藤学术中心” 可点击关注人文社科专业的研究生肯定都听说过“民族志”(田野调查)这样一种研究方法。这种最早隶属于人类学的研究方法,因为拥有强

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 手把手带你搞懂AMS启动原理

  • / 今日科技快讯 /近日,加拿大政府以维护政府信息安全为由,宣布禁止在政府部门使用的移动设备上使用TikTok(抖音海外版)应用程序。按加官方要求,从2023年2月28日起,TikTok应用
  • 应该没什么美食号教过你这种调味技巧。

  • 一个小观察,很多厨房新手做饭都有一个共同困扰:跟着网上菜谱学做菜,几乎每次都要买很多调味料,做两次就要闲置;但如果是自己发挥,永远都是酱油蚝油老抽三部曲,炒什么都是一个味道,怎
  • 河南人爱说的“中”,背后竟有这样的渊源

  • 据统计普通人一天要说3500个常用字日常生活中不管干什么都得“吐字儿”如果要说河南方言一天当中最常说的一定是——中说起“中”这个汉字要从安阳殷墟出土的甲骨说起了“
  • 成年人最爱的微醺快乐水,2支。

  • 莫斯卡托(Moscato),应该是所有葡萄酒里,最让人砰然心动的品种了。嫩嘟嘟的水蜜桃、荔枝玫瑰香,奔放又活泼,即便平时不怎么爱喝酒的人,一闻到都会忍不住心情明快起来。正是因为它非