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

这篇具有很好参考价值的文章主要介绍了手把手带你搞懂AMS启动原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

彻底搞懂AMS即ActivityManagerService,看这一篇就够了


前言

最近那么多教学视频(特别是搞车载的)都在讲AMS,可能这也跟要快速启动一个app(甚至是提高安卓系统启动速度有关),毕竟作为安卓系统的核心系统服务之一,AMS以及PMS都是很重要的,而我之前在 应用的开端–PackageManagerService(PMS) 已经很详细地讲解过PMS,大家有兴趣的可以去看看。

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


提示:以下是本篇文章正文内容

一、回顾PackageManagerService

讲AMS之前,还是得回顾一下PMS的工作流程,PMS会把每个apk进行扫描,然后分别把每个apk里的信息都缓存在mPackages集合里:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

它是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:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

Package是在PMS里,而PMS又是作为一个对象被SystemServer所拥有,SystemServer进程是被zygote进程所开启的,而
zygote进程又是给init进程孵化的:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

init进程是安卓手机开机后第一个启动的进程:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试
我们可以从系统源码中看看它的配置脚本文件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方法。

那么再来总结一下整个系统启动流程:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

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:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

所以我们完全可以通过反射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应用进程:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

只要是跟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并启动:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

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

三、源码

接下来我们将从源码的角度去分析整个启动过程,首先来看整个过程的时序图:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

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修饰的:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

我们点进去看它的详情:

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:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

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

而hook一般是hook系统进程,这才有意义:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

一般来说,自己开发的应用不需要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;
    }

手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

反射方式去获取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的执行方法了。如果想获取完整的hook代码可以关我公号Pingred

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

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

五、总结

整个app启动过程,所有参与的类以及它们的关系流程:
手把手带你搞懂AMS启动原理,移动互联网,android,ActivityManagerService,java,android,面试

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

到了这里,关于手把手带你搞懂AMS启动原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 手把手带你实现DQN(TensorFlow2)

            大家好,今天给大家带来DQN的思路及实现方法。         关于DQN,就不用我多做介绍了,我会以最简短明白的阐述讲解DQN,尽量让你在10分钟内理清思路。         非常重要的一点!!!         非常重要的一点!!!我在GitHub上下载了DQN代码,跑完后,我重写一

    2023年04月08日
    浏览(17)
  • 从0手把手带你搭建pytorch深度学习

    目录 一、查看电脑有NVIDIA显卡没 二、更新电脑驱动 三、安装CUDA ToolKit和CUDNN 1、查看显卡驱动版本 2、查看合适的CUDA版本 3、下载CUDA ToolKit 4、安装CUDA 5、查看是否安装成功 6、安装CUDNN 7、CUDNN配置 四、安装anaconda 五、安装pycharm 六、搭建pytorch深度学习环境 1、进入Anaconda Pr

    2024年02月07日
    浏览(16)
  • 手把手带你做一套毕业设计-征程开启

     本文是《Vue + SpringBoot前后端分离项目实战》专栏的开篇,文本将会包含我们创作这个专栏的初衷,专栏的主体内容,以及我们专栏的后续规划。关于这套毕业设计的作者呢前端部分由狗哥负责,服务端部分则由天哥操刀。我们力求毕业生或者新手通过学完本专栏,可以开心

    2023年04月10日
    浏览(48)
  • 手把手带你啃透比特币白皮书-摘要

    很多人虽然了解了区块链,也可能参与了一些项目,但是可能没有见过比特币白皮书,也没有读过。我接下来就要和大家聊一聊,什么是白皮书,尤其是来给大家精读一下比特币的白皮书。 通过比特币白皮书,你能够 了解到真正的白皮书应该是什么样形式的 。因为很多人可

    2024年02月02日
    浏览(22)
  • 实战项目:手把手带你实现一个高并发内存池

    1.这个项目做的是什么? 当前项目是实现一个高并发的内存池,他的原型是google的一个开源项目tcmalloc,tcmalloc全称Thread-Caching Malloc,即线程缓存的malloc,实现了高效的多线程内存管理,用于替代系统的内存分配相关的函数(malloc、free)。 2.项目目标 模拟实现出一个自己的高

    2023年04月26日
    浏览(22)
  • 真手把手带你跑r3live

    实验室来了台机器人,上面的设备是依据r3live的设备选的,因为R3LIVE的效果太好了,特别感谢大佬的开源精神。这几天把车子跑起来,就打算写个博客记录一下。 本人能力有限,可能某些地方会有些问题,若发现问题,还请指正。 效果如下: 在多传感器融合slam中,由于会集

    2024年02月09日
    浏览(16)
  • 手把手教你 ,带你彻底掌握八大排序算法【数据结构】

    直接插入排序是一种简单的插入排序法,其基本思想:是把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 可以理解为一遍摸扑克牌,一边进行排序 在待排序的元素中,假设前面n-1(其中n=2)个数

    2024年02月02日
    浏览(23)
  • 四步带你爬虫入门,手把手教学爬取电影数据

    本文内容是通过Pycharm来进行实操 创建项目的虚拟环境,目的是为了不让其他的环境资源干扰到当前的项目 本文将以豆瓣作为手把手学习参考,网址:https://movie.douban.com/top250, 1. 进入Terminal终端,安装我们需要的scrapy模块 pip install scrapy 2. 通过pycharm进入Terminal终端,输入我们

    2024年02月22日
    浏览(20)
  • 手把手带你使用VSCode 搭建 STM32开发环境!

    首先附上一张VS Code图一直都喜欢这种,黑色主题感觉高大上。 下载最新版VS Code: 安装好插件,具有良好的代码补全与调试功能。 “ VS Code下载地址:https://code.visualstudio.com/ ” 下载 LLVM:用于代码补全,其实可以理解为 Clang。因为VS Code 中“C/C++”插件的自动补全功能不太好

    2024年02月07日
    浏览(25)
  • 【reverse】手把手带你基于dll实现多次SMC

    SMC,即self modifying code,自修改代码,逆向入门SMC可以看一下我的题解。我打算实现一个类似于【网鼎杯2020青龙组】jocker的SMC方案。这个方案不需要用到汇编,因此门槛极低( 连小小前端都能学会 )。为什么要基于dll呢?因为代码段加密功能是通过外部python脚本完成的,将自

    2024年02月02日
    浏览(22)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包