Hook AMS for service plugin

Hook AMS for service plugin

26 January 2018

Hook AMS 实现 Service 插件化。同样是 hook AMS 的方式,但是却比 Activity 插件化 更为简单,可以从 ServiceFramework 中的启动流程中可以看出来。

唯一纠结的一点,就是 Service 插件化中的 进程 问题

所以,需要 一个 Proxy Service 写好在 AndroidManifest 里,然后配置好 进程 name。然后,在这个 Proxy Service 所在的进程上启动 插件化的 Service。从而,实现了 插件化 Service 的独立进程。

看得出,Framework 对开发者在进程方面的限制很大。不过想想也是,如果一个 App 动态开启新的进程 是多么恐怖...




进 systemserver


ContextImpl 部分源码

package android.app;

class ContextImpl extends Context {

    ...

    @Override
    public boolean bindService(Intent service, ServiceConnection conn,
            int flags) {
        warnIfCallingFromSystemProcess();
        return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
                Process.myUserHandle());
    }

    ...

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
        IServiceConnection sd;

        ...

        try {
            IBinder token = getActivityToken();

            ...

            service.prepareToLeaveProcess(this);
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());

            ...

        } catch (RemoteException e) {
            ...
        }
    }

    ...

}


ActivityManagerNative 部分源码

package android.app;

public abstract class ActivityManagerNative extends Binder implements IActivityManager{

    ...

    public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType, IServiceConnection connection,
            int flags,  String callingPackage, int userId) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();

        ...

        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
        reply.readException();

        ...

    }

    ...

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {

            ...

            case BIND_SERVICE_TRANSACTION: {

                ...

                IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
                int res = bindService(app, token, service, resolvedType, conn, fl,
                        callingPackage, userId);

                ...

            }

            ...

        }
    }

    ...

}


ActivityManagerService 部分源码

package com.android.server.am;

public final class ActivityManagerService extends ActivityManagerNative  
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    ...

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {

            ...

            case BIND_SERVICE_TRANSACTION: {

                ...

                IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
                int res = bindService(app, token, service, resolvedType, conn, fl,
                        callingPackage, userId);

                ...

            }

            ...

        }
    }

    ...

    public int bindService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String callingPackage,
            int userId) throws TransactionTooLargeException {

        ...

        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, callingPackage, userId);
        }
    }

    ...        

}


ContextImpl # bindServiceCommon(...)ActivityManagerNative # bindService(...)。这样,就来到了 AMS 的远程 Binder Proxy 类,就准备和 AMS 所在的 systemserver 进程 通信。

ActivityManagerNative # bindService(...) 中,通过 mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0),就对 AMS 所在的 systemserver 进程 进行通信。

然后,来到了 systemserver 进程 中的 ActivityManagerService # onTransact(...)。接收到了 BIND SERVICE TRANSACTIONcode。开始了在 AMS 中的执行流程,ActivityManagerService # bindService(...) -> ActiveServices # bindServiceLocked(...)


值得一提的是: ActivityManagerService 中源码中,直观上没有 onTransact(...) 方法。但是 ActivityManagerService 继承了 ActivityManagerNative,所以,存在 ActivityManagerService # onTransact(...) 方法。而且是在 ActivityManagerNative # onTransact(...)

可能是我个人的原因,我觉得代码有点魔性了。意味着:AMS 所在 systemserver 进程中,AMS 用到了 AMS 远程 Binder Proxy 类实现的代码,因为继承关系。
当然,这样写的可能 为了:Binder 的跨进程通信代码中的 发送 和 接收 代码都在一个类里( ActivityManagerNative )。




在 systemserver


ActiveServices 部分源码

package com.android.server.am;

public final class ActiveServices {

    ...

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {

        ...

        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);

        ...

        ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
                    Binder.getCallingUid(), userId, true, callerFg, isBindExternal);

        ...

        ServiceRecord s = res.record;

        ...

        AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);

        ...

        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
            s.lastActivity = SystemClock.uptimeMillis();
            if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                    permissionsReviewRequired) != null) {
                return 0;
            }
        }

        ...

    }

    ...

    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {

        ...

        ProcessRecord app;
        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    ...
                } catch (RemoteException e) {
                    ...
                }
            }
        } else {
            ...
        }

        ...

        if (app == null && !permissionsReviewRequired) {
            if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                    "service", r.name, false, isolated, false)) == null) {
                bringDownServiceLocked(r);
                return msg;
            }
            ...
        }

        ...

    }

    ...

    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {

        ...

        boolean created = false;
        try {

            ...

            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            ...
        } finally {
            ...
        }

        ...

        requestServiceBindingsLocked(r, execInFg);

        ...

    }    

    ...

    private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
            throws TransactionTooLargeException {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
            if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
                break;
            }
        }
    }

    ...

    private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {

        ...

        r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
        r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                r.app.repProcState);

        ...

    }

    ...    

}


ActivityManagerService 部分源码

package com.android.server.am;

public final class ActivityManagerService extends ActivityManagerNative  
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    ...

    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {

        ...

        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);
        checkTime(startTime, "startProcess: returned from zygote!");
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (app.isolated) {
            mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid);
        }
        mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);

        ...

    }    

    ...        

}


ActivityThread 部分源码

package android.app;

public final class ActivityThread {

    ...

    private class ApplicationThread extends ApplicationThreadNative {

        ...

        public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;
            sendMessage(H.CREATE_SERVICE, s);
        }        

        ...

        public final void scheduleBindService(IBinder token, Intent intent,
                boolean rebind, int processState) {
            updateProcessState(processState, false);
            BindServiceData s = new BindServiceData();
            s.token = token;
            s.intent = intent;
            s.rebind = rebind;
            if (DEBUG_SERVICE)
                Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                        + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
            sendMessage(H.BIND_SERVICE, s);
        }        

        ...

    }

    ...

    private class H extends Handler {

        ...

        public static final int CREATE_SERVICE          = 114;

        ...

        public static final int BIND_SERVICE            = 121;

        ...

        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {

                ...

                case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;                

                ...

               case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;                

                ...

            }
        }     
    }

    ...

    private void handleCreateService(CreateServiceData data) {

        ...

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            ...
        }
    }  

    ...

    private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);

        ...

        try {
            if (!data.rebind) {
                IBinder binder = s.onBind(data.intent);
                ActivityManagerNative.getDefault().publishService(
                        data.token, data.intent, binder);
            } else {
                s.onRebind(data.intent);
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            }
            ensureJitEnabled();
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }

        ...

    }

    ...      

}


在 systemserver 又分为 两条线。是关于 是否需要创建新的进程的问题


不创建新的进程: ActiveServices # bindServiceLocked(...) -> ActiveServices # bringUpServiceLocked(...) -> ActiveServices # realStartServiceLocked(...)

这样的话,在 ActiveServices # realStartServiceLocked(...) 中能找到 app.thread.scheduleCreateService(...)app.threadApplicationThread 类型,就是 App 进程的远程 Binder Proxy 代理类。这样,就 能和 App 进程通信


创建新的进程: ActiveServices # bindServiceLocked(...) -> ActiveServices # bringUpServiceLocked(...) -> ActivityManagerService # startProcessLocked(...) -> ActiveServices # bringUpServiceLocked(...) -> ActiveServices # realStartServiceLocked(...)

其实,创建新的进程,也就在 if 判断中 多走一下 ActivityManagerService # startProcessLocked(...)。然后,在 if 内 再走一次 ActiveServices # bringUpServiceLocked(...)。这样,再次回到 ActiveServices # bringUpServiceLocked(...) 的时候,就在 ActiveServices # realStartServiceLocked(...) 跳走了,不会有下面的判断进程的逻辑。


总的来说,都是通过 ActivityThread # ApplicationThread # scheduleCreateService(...) 这个 App 进程的远程 Binder Proxy 代理类,回到 App 进程里


realStartServiceLocked 这一行


ApplicationThread # scheduleCreateService(...) -> H # handleMessage(...) -> ActivityThread # handleCreateService(...)
这个过程到最后,完成了一趟 systemserver 到 App 进程 的通信。完成了 Service 的创建,并且 回调 Service # onCreate

虽然完成了 AMS 所在的 systemserver 进程App 进程 的通信。但是,这也只是 ActiveServices # realStartServiceLocked(...) 这一行在 systemserver 进程 执行的效果。意味着,执行完 ActiveServices # realStartServiceLocked(...),还在 systemserver 进程 内


执行完 ActiveServices # realStartServiceLocked(...),还在 systemserver 进程 内的 ActiveServices # bringUpServiceLocked(...)

接下来,就会接着执行 ActiveServices # bringUpServiceLocked(...) 的后半段中的 ActiveServices # requestServiceBindingsLocked


requestServiceBindingsLocked 这一行


ActiveServices # requestServiceBindingsLocked -> ActiveServices # requestServiceBindingLocked(...) -> ApplicationThread # scheduleBindService(...) -> H # handleMessage(...) -> ActivityThread # handleBindService(...)

这个过程到最后,又完成了一趟 systemserver 到 App 进程 的通信。终于完成了 Service 的绑定,并且 回调 Service # onBind 或者 Service # onRebind(...)


总的来说,真的 很奇妙,也很漫长

怎么说呢...ActiveServices # realStartServiceLocked(...) 内分别完成了 两趟 systemserver 到 App 进程 的通信。分别完成了 Service 的创建Service 的绑定。这个方法感觉 在 systemserver 很漫长,也非常重要




最后再跟踪一下


ActivityThread # handleBindService(...) 内的 ActivityManagerNative.getDefault().publishService(...) 开始。

这里是,从 App 进程 调用了 AMS 的远程 Binder Proxy 类,与 AMS 所在的 systemserver 进程 通信。


ActivityManagerService 部分源码

package com.android.server.am;

public final class ActivityManagerService extends ActivityManagerNative  
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

    ...


    public void publishService(IBinder token, Intent intent, IBinder service) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors() == true) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                throw new IllegalArgumentException("Invalid service token");
            }
            mServices.publishServiceLocked((ServiceRecord)token, intent, service);
        }
    }   

    ...        

}


ActiveServices 部分源码

package com.android.server.am;

public final class ActiveServices {

    ...

    void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {

        ...

        for (int conni=r.connections.size()-1; conni>=0; conni--) {
            ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
            for (int i=0; i<clist.size(); i++) {
                ConnectionRecord c = clist.get(i);

                ...

                try {
                    c.conn.connected(r.name, service);
                } catch (Exception e) {
                    ...
                }
            }
        }

        ...

    }    

    ...    

}


ActivityThread # handleBindService(...) -> ActivityManagerService # publishService(...) -> ActiveServices # publishServiceLocked

会发现,在 ActiveServices # publishServiceLocked(...) 执行了 c.conn.connected(r.name, service)。可以知道 conn 是一个 IServiceConnection 类型,继承了 IBinder。但是不知道它的 远程 Binder Proxy 实现类 在哪?

c.conn.connected(r.name, service); 还在 systemserver。所以,可以推测出 conn远程 Binder Proxy 实现类App 进程内


ContextImpl 部分源码

package android.app;

class ContextImpl extends Context {

    ...

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
            handler, UserHandle user) {
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }

        ...

    }

    ...

}


LoadedApk 部分源码

package android.app;

public final class LoadedApk {

    ...

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (map == null) {
                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }

    ...

    static final class ServiceDispatcher {

        private final ServiceDispatcher.InnerConnection mIServiceConnection;
        private final ServiceConnection mConnection;        

        ...

        private static class InnerConnection extends IServiceConnection.Stub {
            final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
            }
            public void connected(ComponentName name, IBinder service) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
        }        

        ...

        public void connected(ComponentName name, IBinder service) {
            if (mActivityThread != null) {
                mActivityThread.post(new RunConnection(name, service, 0));
            } else {
                doConnected(name, service);
            }
        }        

        ...

        public void doConnected(ComponentName name, IBinder service) {

            ...

            service.linkToDeath(info.deathMonitor, 0);

            ...        

            // If there was an old service, it is not disconnected.
            if (old != null) {
                mConnection.onServiceDisconnected(name);
            }
            // If there is a new service, it is now connected.
            if (service != null) {
                mConnection.onServiceConnected(name, service);
            }

            ...

        }        

    }

}


再一次看下 ContextImpl # bindServiceCommon(...) 发现了 IServiceConnection sd。同时,也有 sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags)。这样,就找了了最开始的 IServiceConnection

LoadedApk # getServiceDispatcher(...) 发现了内部类 LoadedApk # ServiceDispatcher。从 LoadedApk # ServiceDispatcher 的结构看到了,一个 远程 Binder Proxy 类的实现( 因为继承了 IServiceConnection.Stub )。就是 ServiceDispatcher # InnerConnection

所以,c.conn.connected(r.name, service) 中的 connServiceDispatcher # InnerConnection


那么 ActiveServices # publishServiceLocked(...) 之后的流程就是:ActiveServices # publishServiceLocked(...) -> ServiceDispatcher # InnerConnection # connected(...) -> ServiceDispatcher # doConnected(...)

然后我们看到了 IBinderServiceConnection 的各种回调。


由此,Service 的启动结束

当然,这 最后再跟踪一下Service 插件化 没关系。




Hook AMS for service plugin 思路


和 Hook Activity 类似,也需要有个 代理 Service 在 AndroidManifest 里,这样能保证 插件 Service 在独立进程上。

概括: 启动 插件 Service 时,hook AMS 改为启动 代理 Service。然后,进到 代理 Service 内。再反射 ActivityThread # handleCreateService(...) 创建了 插件 service。也在 代理 Service 内,完成手动调用 插件 Service 的生命周期,完成 回调插件 Service 的创建和销毁都在 代理 Service 上,插件 Service 的每个行为都分发到 代理 Service 的 onStart 方法上,再进行二次分发,完成 插件 Service 的生命周期回调。


1. AndroidManifest 写入一个 代理 Service

2. 准备好 IActivityManager 的 动态代理类。

3. IActivityManager 的 动态代理类,对 IActivityManager # startService(...)IActivityManager # stopService(...) 进行 hook。 去完成将 插件 Service Intent 替换为 代理 Service Intent。拿着 代理 Service Intent 去交给 AMS

4. 插件 Service Intent 中记录 插件 Service 的行为( 比如:startService 或者 stopService )。同时,插件 Service Intent 作为 代理 Service Intent 额外参数,进行保存。

5. Hook AMS

6. 代理 Service 中的 Service # onStart(...) 方法可以拿到 代理 Service Intent。从 代理 Service Intent 中取出 4. 保存的 插件 Service Intent

6. 根据取出的 插件 Service Intent。获取 插件 Service 的行为( 比如:startService 或者 stopService )。

7. 然后,进行 行为的分发代理Service 没创建的话,就反射 ActivityThread # handleCreateService(...) 创建 Service。并且拿到创建好的 Service 实例,进行 Service 缓存 保存。

8. 如果 插件 Service Intent 信息对应了一个 7. 中保存的 Service 缓存。那么取出该 Service 缓存,手动调用其 onStart 或者 onDestory 方法。

9. 如果手动调用了 onDestory 方法。那么就得 删除对应的 Service 缓存。因为, 7. 进行了加操作,必然就有减操作。不然缓存中就有重复的 Service 缓存实例




Hook AMS for service plugin


IActivityManagerHandler

/**
 * 动态代理 AMS
 *
 * @author CaMnter
 */

public class IActivityManagerHandler implements InvocationHandler {

    private static final String TAG = IActivityManagerHandler.class.getSimpleName();

    Object base;


    public IActivityManagerHandler(Object base) {
        this.base = base;
    }


    @SuppressWarnings("DanglingJavadoc")
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        final String methodName = method.getName();
        if ("startService".equals(methodName)) {
            /**
             * 只拦截这个方法
             *
             * API 23:
             * public ComponentName startService(IApplicationThread caller,
             *                                   Intent service,
             *                                   String resolvedType,
             *                                   int userId) throws RemoteException
             */
            final Pair<Integer, Intent> integerIntentPair = foundFirstIntentOfArgs(args);
            final Intent rawIntent = integerIntentPair.second;

            /**
             * 判断是否有 其他动作
             * 没有默认为 start
             */
            if (TextUtils.isEmpty(rawIntent.getStringExtra(AMSHooker.EXTRA_TARGET_INTENT_ACTION))) {
                rawIntent.putExtra(AMSHooker.EXTRA_TARGET_INTENT_ACTION,
                    AMSHooker.INTENT_ACTION_START);
            }

            // 代理 service 包名
            final String proxyServicePackageName = SmartApplication.getContext().getPackageName();

            // 启动的 Service 替换为 ProxyService
            final Intent intent = new Intent();
            final ComponentName componentName = new ComponentName(proxyServicePackageName,
                ProxyService.class.getName());
            intent.setComponent(componentName);
            // 保存原始 要启动的 TargetService
            intent.putExtra(AMSHooker.EXTRA_TARGET_INTENT, rawIntent);

            // 替换掉 Intent, 欺骗 AMS
            args[integerIntentPair.first] = intent;
            Log.v(TAG,
                "[IActivityManagerHandler]   [startService]   hook method startService success");
            return method.invoke(base, args);
        }

        /**
         * public int stopService(IApplicationThread caller,
         *                        Intent service,
         *                        String resolvedType,
         *                        int userId) throws RemoteException
         */
        if ("stopService".equals(methodName)) {
            final Intent rawIntent = foundFirstIntentOfArgs(args).second;
            final ComponentName rawComponentName = rawIntent.getComponent();
            final String rawPackageName = rawComponentName == null
                                          ? ""
                                          : rawComponentName.getPackageName();
            // 是否是 插件 的 intent
            if (!TextUtils.equals(SmartApplication.getContext().getPackageName(),
                rawPackageName)) {
                /*
                 * 继续走 start
                 * 通过 start 去分发
                 *
                 * 底下就不调用 method.invoke(base, args) 了
                 * 因为不让它走 stop
                 */
                rawIntent.putExtra(AMSHooker.EXTRA_TARGET_INTENT_ACTION,
                    AMSHooker.INTENT_ACTION_STOP);
                SmartApplication.getContext().startService(rawIntent);
                Log.v(TAG,
                    "[IActivityManagerHandler]   [stopService]   hook method stopService success");
            }
        }

        return method.invoke(base, args);
    }


    /**
     * 寻找 参数里面的第一个Intent 对象
     *
     * @param args args
     * @return Pair<Integer, Intent>
     */
    private Pair<Integer, Intent> foundFirstIntentOfArgs(Object... args) {
        int index = 0;

        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof Intent) {
                index = i;
                break;
            }
        }
        return Pair.create(index, (Intent) args[index]);
    }

}


AMSHooker

/**
 * @author CaMnter
 */

public final class AMSHooker {

    public static final String EXTRA_TARGET_INTENT = "extra_target_intent";
    public static final String EXTRA_TARGET_INTENT_ACTION = "extra_target_intent_action";

    public static final String INTENT_ACTION_STOP = "intent_action_stop";
    public static final String INTENT_ACTION_START = "intent_action_start";


    /**
     * Hook ActivityManagerNative 这个 Binder 中的 AMS
     *
     * @throws ClassNotFoundException ClassNotFoundException
     * @throws NoSuchMethodException NoSuchMethodException
     * @throws InvocationTargetException InvocationTargetException
     * @throws IllegalAccessException IllegalAccessException
     * @throws NoSuchFieldException NoSuchFieldException
     */
    @SuppressWarnings("DanglingJavadoc")
    @SuppressLint("PrivateApi")
    public static void hookActivityManagerNative() throws ClassNotFoundException,
                                                          NoSuchMethodException,
                                                          InvocationTargetException,
                                                          IllegalAccessException,
                                                          NoSuchFieldException {

        /**
         * *****************************************************************************************
         *
         * ActivityManagerNative 部分源码
         *
         *
         * public abstract class ActivityManagerNative extends Binder implements IActivityManager{
         *
         *      ...
         *
         *      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 的类结构
         *
         * package android.util;
         *
         *  **
         *  * Singleton helper class for lazily initialization.
         *  *
         *  * Modeled after frameworks/base/include/utils/Singleton.h
         *  *
         *  * @hide
         *  **
         *
         * 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;
         *          }
         *      }
         * }
         *
         * *****************************************************************************************
         */
        // static public IActivityManager getDefault()
        final Field gDefaultField = ActivityManagerNative.class.getDeclaredField("gDefault");
        gDefaultField.setAccessible(true);

        // IActivityManager
        final Object gDefault = gDefaultField.get(null);

        // 反射获取 IActivityManager # android.util.Singleton 的实例
        final Field mInstanceField = Singleton.class.getDeclaredField("mInstance");
        mInstanceField.setAccessible(true);

        // 获取 ActivityManagerNative 中的 gDefault 对象里面原始的 IActivityManager 实例
        final Object rawIActivityManager = mInstanceField.get(gDefault);

        // 动态代理 创建一个 IActivityManager 实现类
        final Object proxy = Proxy.newProxyInstance(
            Thread.currentThread().getContextClassLoader(),
            new Class<?>[] { IActivityManager.class },
            new IActivityManagerHandler(rawIActivityManager)
        );

        /**
         * 用 动态代理 创建的 IActivityManager 实现类
         * Hook 掉 IActivityManager # Singleton # mInstance
         */
        mInstanceField.set(gDefault, proxy);
    }

}


BaseDexClassLoaderHooker

/**
 * DexElements 插桩
 *
 * @author CaMnter
 */

public final class BaseDexClassLoaderHooker {

    @SuppressWarnings("DanglingJavadoc")
    public static void patchClassLoader(@NonNull final ClassLoader classLoader,
                                        @NonNull final File apkFile,
                                        @NonNull final File optDexFile)
        throws IllegalAccessException,
               NoSuchMethodException,
               IOException,
               InvocationTargetException,
               InstantiationException,
               NoSuchFieldException,
               ClassNotFoundException {

        // 获取 BaseDexClassLoader # DexPathList pathList
        final Field pathListField = DexClassLoader.class.getSuperclass()
            .getDeclaredField("pathList");
        pathListField.setAccessible(true);
        final Object pathList = pathListField.get(classLoader);

        // 获取 DexPathList # Element[] dexElements
        final Field dexElementArray = pathList.getClass().getDeclaredField("dexElements");
        dexElementArray.setAccessible(true);
        final Object[] dexElements = (Object[]) dexElementArray.get(pathList);

        // Element 类型
        final Class<?> elementClass = dexElements.getClass().getComponentType();

        // 用于替换 PathList # Element[] dexElements
        final Object[] newElements = (Object[]) Array.newInstance(elementClass,
            dexElements.length + 1);

        /**
         * <= 4.0.0
         *
         * no method
         *
         * >= 4.0.0
         *
         * Element(File file, ZipFile zipFile, DexFile dexFile)
         *
         * ---
         *
         * >= 5.0.0
         *
         * Element(File file, boolean isDirectory, File zip, DexFile dexFile)
         *
         * ---
         *
         * >= 8.0.0
         *
         * @Deprecated
         * Element(File dir, boolean isDirectory, File zip, DexFile dexFile)
         * Element(DexFile dexFile, File dexZipPath)
         *
         */
        final int sdkVersion = Build.VERSION.SDK_INT;

        if (sdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            throw new RuntimeException(
                "[BaseDexClassLoaderHooker]   the sdk version must >= 14 (4.0.0)");
        }

        final Object element;
        final Constructor<?> constructor;

        if (sdkVersion >= Build.VERSION_CODES.O) {
            // >= 8.0.0
            // DexFile dexFile, File dexZipPath
            constructor = elementClass.getConstructor(
                DexFile.class,
                File.class
            );
            element = constructor.newInstance(
                DexFile.loadDex(apkFile.getCanonicalPath(), optDexFile.getAbsolutePath(), 0),
                apkFile
            );
        } else if (sdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
            // >= 5.0.0
            // File file, boolean isDirectory, File zip, DexFile dexFile
            constructor = elementClass.getConstructor(
                File.class,
                boolean.class,
                File.class,
                DexFile.class
            );
            element = constructor.newInstance(
                apkFile,
                false,
                apkFile,
                DexFile.loadDex(apkFile.getCanonicalPath(), optDexFile.getAbsolutePath(), 0)
            );
        } else {
            // >= 4.0.0
            // File file, ZipFile zipFile, DexFile dexFile
            constructor = elementClass.getConstructor(
                File.class,
                ZipFile.class,
                DexFile.class
            );
            element = constructor.newInstance(
                apkFile,
                new ZipFile(apkFile),
                DexFile.loadDex(apkFile.getCanonicalPath(), optDexFile.getAbsolutePath(), 0)
            );
        }

        final Object[] toAddElementArray = new Object[] { element };
        // 把原始的 elements 复制进去
        System.arraycopy(dexElements, 0, newElements, 0, dexElements.length);
        // 把插件的 element  复制进去
        System.arraycopy(toAddElementArray, 0, newElements, dexElements.length,
            toAddElementArray.length);

        // 替换
        dexElementArray.set(pathList, newElements);
    }

}


ProxyService

/**
 * @author CaMnter
 */

public class ProxyService extends Service {

    private static final String TAG = ProxyService.class.getSimpleName();


    @Override
    public void onCreate() {
        Log.d(TAG, "[ProxyService]   [onCreate]");
        super.onCreate();
    }


    @Override
    public void onStart(Intent intent, int startId) {
        Log.d(TAG, "[ProxyService]   [onStart]");
        // 分发 Service Action
        final Intent rawIntent = intent.getParcelableExtra(AMSHooker.EXTRA_TARGET_INTENT);
        if (rawIntent == null) {
            Log.d(TAG, "[ProxyService]   [onStart]   no rawIntent");
            super.onStart(intent, startId);
            return;
        }
        final String action = rawIntent.getStringExtra(AMSHooker.EXTRA_TARGET_INTENT_ACTION);
        if (!TextUtils.isEmpty(action)) {
            Log.d(TAG, "[ProxyService]   [onStart]   [Action] = " + action);
            if (AMSHooker.INTENT_ACTION_STOP.equals(action)) {
                ProxyServiceManager.getInstance().onStop(rawIntent);
            } else if (AMSHooker.INTENT_ACTION_START.equals(action)) {
                ProxyServiceManager.getInstance().onStart(rawIntent, startId);
            }
        } else {
            Log.d(TAG, "[ProxyService]   [onStart]   no action");
        }
        super.onStart(intent, startId);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "[ProxyService]   [onBind]");
        return null;
    }


    @Override
    public void onDestroy() {
        Log.d(TAG, "[ProxyService]   [onDestroy]");
        super.onDestroy();
    }

}


ProxyServiceManager

/**
 * @author CaMnter
 */

@SuppressWarnings("DanglingJavadoc")
public final class ProxyServiceManager {

    private static final String TAG = ProxyServiceManager.class.getSimpleName();

    private static volatile ProxyServiceManager INSTANCE;

    // 缓存在创建好的 Service
    private Map<String, Service> serviceMap = new HashMap<>();

    // 解析 apk file,存储插件的 ServiceInfo
    private Map<ComponentName, ServiceInfo> serviceInfoMap = new HashMap<>();


    public synchronized static ProxyServiceManager getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new ProxyServiceManager();
        }
        return INSTANCE;
    }


    /**
     * 启动插件 Service
     * 如果 Service 没启动,会创建一个 new 插件 Service
     *
     * @param rawIntent proxyIntent
     * @param startId startId
     */
    void onStart(@NonNull final Intent rawIntent,
                 final int startId) {
        // 查询是否有 该 intent 对应的 插件 ServiceInfo 缓存
        final ServiceInfo serviceInfo = this.selectPluginService(rawIntent);

        if (serviceInfo == null) {
            Log.w(TAG, "[ProxyServiceManager]   [onStart]   can not found service : " +
                rawIntent.getComponent());
            return;
        }

        try {
            if (!serviceMap.containsKey(serviceInfo.name)) {
                // service 不存在
                this.proxyCreateService(serviceInfo);
            }

            final Service service = this.serviceMap.get(serviceInfo.name);
            service.onStart(rawIntent, startId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 停止插件 Service
     * 全部的插件 Service 都停止之后, ProxyService 也会停止
     *
     * @param rawIntent rawIntent
     * @return int
     */
    @SuppressWarnings("UnusedReturnValue")
    int onStop(@NonNull final Intent rawIntent) {
        // 获取 Intent 对应的 ServiceInfo 缓存
        final ServiceInfo serviceInfo = selectPluginService(rawIntent);
        if (serviceInfo == null) {
            Log.w(TAG, "[ProxyServiceManager]   [stopService]   can not found service: " +
                rawIntent.getComponent());
            return 0;
        }
        // 获取 ServiceInfo 对应的 Service 缓存
        final Service service = this.serviceMap.get(serviceInfo.name);
        if (service == null) {
            Log.w(TAG,
                "[ProxyServiceManager]   [stopService]   can not running, are you stopped it multi-times?");
            return 0;
        }
        service.onDestroy();
        // 删除 Service 缓存
        this.serviceMap.remove(serviceInfo.name);
        if (this.serviceMap.isEmpty()) {
            Log.d(TAG, "[ProxyServiceManager]   [stopService]   service all stopped, stop proxy");
            final Context appContext = SmartApplication.getContext();
            appContext.stopService(new Intent().setComponent(
                new ComponentName(appContext.getPackageName(), ProxyService.class.getName())));
        }
        return 1;
    }


    /**
     * 匹配 ServiceInfo 缓存
     *
     * @param pluginIntent 插件 Intent
     * @return 插件 intent 的 ServiceInfo
     */
    private ServiceInfo selectPluginService(Intent pluginIntent) {
        for (ComponentName componentName : this.serviceInfoMap.keySet()) {
            if (componentName.equals(pluginIntent.getComponent())) {
                return this.serviceInfoMap.get(componentName);
            }
        }
        return null;
    }


    /**
     * 反射 ActivityThread # handleCreateService 创建 Service
     *
     * @param serviceInfo 插件 service
     * @throws Exception exception
     */
    @SuppressLint("PrivateApi")
    private void proxyCreateService(@NonNull final ServiceInfo serviceInfo) throws Exception {
        IBinder token = new Binder();

        /**
         * 反射创建 ActivityThread # CreateServiceData 对象
         *
         * CreateServiceData 结构
         *
         * static final class CreateServiceData {
         *      IBinder token;
         *      ServiceInfo info;
         *      CompatibilityInfo compatInfo;
         *      Intent intent;
         *      public String toString() {
         *          return "CreateServiceData{token=" + token + " className=" + info.name + " packageName=" + info.packageName + " intent=" + intent + "}";
         *      }
         * }
         */
        final Class<?> createServiceDataClass = Class.forName(
            "android.app.ActivityThread$CreateServiceData");
        final Constructor<?> constructor = createServiceDataClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        final Object createServiceData = constructor.newInstance();

        /**
         * Hook CreateServiceData # IBinder token
         */
        final Field tokenField = createServiceDataClass.getDeclaredField("token");
        tokenField.setAccessible(true);
        tokenField.set(createServiceData, token);

        /**
         * Hook CreateServiceData # ServiceInfo info
         *
         * 因为 loadClass 的时候
         * LoadedApk 会是主程序的 ClassLoader
         * Hook BaseDexClassLoader 方式 加载插件
         */
        serviceInfo.applicationInfo.packageName = SmartApplication.getContext().getPackageName();
        final Field infoField = createServiceDataClass.getDeclaredField("info");
        infoField.setAccessible(true);
        infoField.set(createServiceData, serviceInfo);

        /**
         * Hook CreateServiceData # CompatibilityInfo compatInfo
         *
         * public class CompatibilityInfo implements Parcelable {
         *
         *     ***
         *
         *     public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo(){}
         *
         *     ***
         *
         * }
         *
         * 获取默认的 CompatibilityInfo 配置
         */
        final Class<?> compatibilityClass = Class.forName("android.content.res.CompatibilityInfo");
        final Field defaultCompatibilityField = compatibilityClass.getDeclaredField(
            "DEFAULT_COMPATIBILITY_INFO");
        final Object defaultCompatibility = defaultCompatibilityField.get(null);
        final Field compatInfoField = createServiceDataClass.getDeclaredField("compatInfo");
        compatInfoField.setAccessible(true);
        compatInfoField.set(createServiceData, defaultCompatibility);

        /**
         * 反射获取 ActivityThread
         */
        final Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
        final Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod(
            "currentActivityThread");
        final Object currentActivityThread = currentActivityThreadMethod.invoke(null);

        /**
         * 反射调用 ActivityThread # handleCreateService(CreateServiceData data)
         */
        final Method handleCreateServiceMethod = activityThreadClass.getDeclaredMethod(
            "handleCreateService", createServiceDataClass);
        handleCreateServiceMethod.setAccessible(true);
        handleCreateServiceMethod.invoke(currentActivityThread, createServiceData);

        /**
         * ActivityThread # handleCreateService(CreateServiceData data) 创造的 Service 会保存在
         * ActivityThread # mServices 字段里面
         *
         * 可以根据 CreateServiceData # IBinder token 获取该 Service
         */
        final Field mServicesField = activityThreadClass.getDeclaredField("mServices");
        mServicesField.setAccessible(true);
        final Map mServices = (Map) mServicesField.get(currentActivityThread);
        final Service service = (Service) mServices.get(token);

        /**
         * 获取到之后, 移除这个 Service
         *
         * 因为创建信息用的是插件 Service 去欺骗 AMS
         * 但是该 Service 未注册
         *
         * 只是 借花献佛
         */
        mServices.remove(token);

        /**
         * 将此 Service 存储起来
         */
        serviceMap.put(serviceInfo.name, service);
    }


    /**
     * 解析 Apk 文件中的 <service>
     * 并缓存
     *
     * 主要 调用 PackageParser 类的 generateServiceInfo 方法
     *
     * @param apkFile apkFile
     * @throws Exception exception
     */
    @SuppressLint("PrivateApi")
    public void preLoadServices(@NonNull final File apkFile, final Context context)
        throws Exception {

        /**
         * 反射 获取 PackageParser # parsePackage(File packageFile, int flags)
         */
        final Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser");

        /**
         * <= 4.0.0
         *
         * Don't deal with
         *
         * >= 4.0.0
         *
         * parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags)
         *
         * ---
         *
         * >= 5.0.0
         *
         * parsePackage(File packageFile, int flags)
         *
         */
        final int sdkVersion = Build.VERSION.SDK_INT;
        if (sdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            throw new RuntimeException(
                "[BaseDexClassLoaderHooker]   the sdk version must >= 14 (4.0.0)");
        }

        final Object packageParser;
        final Object packageObject;
        final Method parsePackageMethod;

        if (sdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
            // >= 5.0.0
            // parsePackage(File packageFile, int flags)
            /**
             * 反射创建 PackageParser 对象,无参数构造
             *
             * 反射 调用 PackageParser # parsePackage(File packageFile, int flags)
             * 获取 apk 文件对应的 Package 对象
             */
            packageParser = packageParserClass.newInstance();

            parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage",
                File.class, int.class);
            packageObject = parsePackageMethod.invoke(
                packageParser,
                apkFile,
                PackageManager.GET_SERVICES
            );
        } else {
            // >= 4.0.0
            // parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags)
            /**
             * 反射创建 PackageParser 对象,PackageParser(String archiveSourcePath)
             *
             * 反射 调用 PackageParser # parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags)
             * 获取 apk 文件对应的 Package 对象
             */
            final String apkFileAbsolutePath = apkFile.getAbsolutePath();
            packageParser = packageParserClass.getConstructor(String.class)
                .newInstance(apkFileAbsolutePath);

            parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage",
                File.class, String.class, DisplayMetrics.class, int.class);
            packageObject = parsePackageMethod.invoke(
                packageParser,
                apkFile,
                apkFile.getAbsolutePath(),
                context.getResources().getDisplayMetrics(),
                PackageManager.GET_SERVICES
            );
        }

        if (sdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            // >= 4.2.0
            // generateServiceInfo(Service s, int flags, PackageUserState state, int userId)
            /**
             * 读取 Package # ArrayList<Service> services
             * 通过 ArrayList<Service> services 获取 Service 对应的 ServiceInfo
             */
            final Field servicesField = packageObject.getClass().getDeclaredField("services");
            final List services = (List) servicesField.get(packageObject);

            /**
             * 反射调用 UserHandle # static @UserIdInt int getCallingUserId()
             * 获取到 userId
             *
             * 反射创建 PackageUserState 对象
             */
            final Class<?> packageParser$ServiceClass = Class.forName(
                "android.content.pm.PackageParser$Service");
            final Class<?> packageUserStateClass = Class.forName(
                "android.content.pm.PackageUserState");
            final Class<?> userHandler = Class.forName("android.os.UserHandle");
            final Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId");
            final int userId = (Integer) getCallingUserIdMethod.invoke(null);
            final Object defaultUserState = packageUserStateClass.newInstance();

            // 需要调用 android.content.pm.PackageParser#generateServiceInfo(Service s, int flags, PackageUserState state, int userId)
            Method generateReceiverInfo = packageParserClass.getDeclaredMethod(
                "generateServiceInfo",
                packageParser$ServiceClass, int.class, packageUserStateClass, int.class);

            /**
             * 反射调用 PackageParser # generateServiceInfo(Service s, int flags, PackageUserState state, int userId)
             * 解析出 Service 对应的 ServiceInfo
             *
             * 然后保存
             */
            for (Object service : services) {
                final ServiceInfo info = (ServiceInfo) generateReceiverInfo.invoke(packageParser,
                    service, 0,
                    defaultUserState, userId);
                this.serviceInfoMap.put(new ComponentName(info.packageName, info.name), info);
            }
        } else if (sdkVersion >= Build.VERSION_CODES.JELLY_BEAN) {
            // >= 4.1.0
            // generateServiceInfo(Service s, int flags, boolean stopped, int enabledState, int userId)
            /**
             * 读取 Package # ArrayList<Service> services
             * 通过 ArrayList<Service> services 获取 Service 对应的 ServiceInfo
             */
            final Field servicesField = packageObject.getClass().getDeclaredField("services");
            final List services = (List) servicesField.get(packageObject);

            // 需要调用 android.content.pm.PackageParser#generateServiceInfo(Service s, int flags, boolean stopped, int enabledState, int userId)
            final Class<?> packageParser$ServiceClass = Class.forName(
                "android.content.pm.PackageParser$Service");
            final Class<?> userHandler = Class.forName("android.os.UserId");
            final Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId");
            final int userId = (Integer) getCallingUserIdMethod.invoke(null);
            Method generateReceiverInfo = packageParserClass.getDeclaredMethod(
                "generateServiceInfo",
                packageParser$ServiceClass, int.class, boolean.class, int.class, int.class);

            /**
             * 反射调用 PackageParser # generateServiceInfo(Service s, int flags, boolean stopped, int enabledState, int userId)
             * 解析出 Service 对应的 ServiceInfo
             *
             * 在之前版本的 4.0.0 中 存在着
             * public class PackageParser {
             *     public final static class Package {
             *         // User set enabled state.
             *         public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
             *
             *         // Whether the package has been stopped.
             *         public boolean mSetStopped = false;
             *     }
             * }
             *
             * 然后保存
             */
            for (Object service : services) {
                final ServiceInfo info = (ServiceInfo) generateReceiverInfo.invoke(packageParser,
                    service, 0, false, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, userId);
                this.serviceInfoMap.put(new ComponentName(info.packageName, info.name), info);
            }
        } else if (sdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            // >= 4.0.0
            // generateServiceInfo(Service s, int flags)
            /**
             * 读取 Package # ArrayList<Service> services
             * 通过 ArrayList<Service> services 获取 Service 对应的 ServiceInfo
             */
            final Field servicesField = packageObject.getClass().getDeclaredField("services");
            final List services = (List) servicesField.get(packageObject);

            // 需要调用 android.content.pm.PackageParser#generateServiceInfo(Service s, int flags)
            final Class<?> packageParser$ServiceClass = Class.forName(
                "android.content.pm.PackageParser$Service");
            Method generateReceiverInfo = packageParserClass.getDeclaredMethod(
                "generateServiceInfo",
                packageParser$ServiceClass, int.class);

            /**
             * 反射调用 PackageParser # generateServiceInfo(Activity a, int flags)
             * 解析出 Service 对应的 ServiceInfo
             *
             * 然后保存
             */
            for (Object service : services) {
                final ServiceInfo info = (ServiceInfo) generateReceiverInfo.invoke(packageParser,
                    service, 0);
                this.serviceInfoMap.put(new ComponentName(info.packageName, info.name), info);
            }
        }

    }

}


SmartApplication

/**
 * @author CaMnter
 */

public class SmartApplication extends Application {

    private static Context BASE;

    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     *
     * @param base The new base context for this wrapper.
     */
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        BASE = base;
        try {
            // Hook AMS
            AMSHooker.hookActivityManagerNative();
            // assets 的 hook-ams-for-service-plugin-plugin.apk 拷贝到 /data/data/files/[package name]
            AssetsUtils.extractAssets(base, "hook-ams-for-service-plugin-plugin.apk");
            final File apkFile = getFileStreamPath("hook-ams-for-service-plugin-plugin.apk");
            final File odexFile = getFileStreamPath("hook-ams-for-service-plugin-plugin.odex");
            // Hook ClassLoader, 让插件中的类能够被成功加载
            BaseDexClassLoaderHooker.patchClassLoader(this.getClassLoader(), apkFile, odexFile);
            // 解析插件中的 Service 组件
            ProxyServiceManager.getInstance().preLoadServices(apkFile, base);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static Context getContext() {
        return BASE;
    }

}




启动插件 Service

/**
 * Called when a view has been clicked.
 *
 * @param v The view that was clicked.
 */
@Override
public void onClick(View v) {  
    switch (v.getId()) {
        case R.id.start_first_text:
            this.startFirstText.setEnabled(false);
            this.startService(new Intent().setComponent(
                new ComponentName("com.camnter.hook.ams.f.service.plugin.plugin",
                    "com.camnter.hook.ams.f.service.plugin.plugin.FirstService")));
            this.startFirstText.setEnabled(true);
            break;
        case R.id.start_second_text:
            startSecondText.setEnabled(false);
            this.startService(new Intent().setComponent(
                new ComponentName("com.camnter.hook.ams.f.service.plugin.plugin",
                    "com.camnter.hook.ams.f.service.plugin.plugin.SecondService")));
            startSecondText.setEnabled(true);
            break;
        case R.id.stop_first_text:
            stopFirstText.setEnabled(false);
            this.stopService(new Intent().setComponent(
                new ComponentName("com.camnter.hook.ams.f.service.plugin.plugin",
                    "com.camnter.hook.ams.f.service.plugin.plugin.FirstService")));
            stopFirstText.setEnabled(true);
            break;
        case R.id.stop_second_text:
            stopSecondText.setEnabled(false);
            this.stopService(new Intent().setComponent(
                new ComponentName("com.camnter.hook.ams.f.service.plugin.plugin",
                    "com.camnter.hook.ams.f.service.plugin.plugin.SecondService")));
            stopSecondText.setEnabled(true);
            break;
    }
}




参考资料


Android 插件化原理解析——Service的插件化