探索Activity启动流程-实现打开插件中的Activity

通过分析Activity的启动流程,探索Android的插件化,下面通过源码分析实现一个简单的插件化
打开一个 未安装apk中的Activity

开始分析

Activity的启动流程从 startActivity开始

// Activity.java
public void startActivity(Intent intent) {
        this.startActivity(intent, null);
}

public void startActivity(Intent intent, @Nullable Bundle options) {
    if (options != null) {
        startActivityForResult(intent, -1, options);
    } else {
        // Note we want to go through this call for compatibility with
        // applications that may have overridden the method.
        startActivityForResult(intent, -1);
    }
}
// 最终会调用到这个方法
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
    @Nullable Bundle options) {
    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());
    }
    //省略其他代码
    .............
}

然后通过 Instrumentation.execStartActivity() 方法启动一个Activity,我们跟进这个方法,在方法中发现了这么一段代码
这是通过 ActivityManagerService 启动Activity 简称ams,这是一个系统级的服务,我们继续跟进

int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);

ActivityManager.java, 通过ServiceManager.getService()获取ActivityManager的服务

/**
     * @hide
     */
    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;
                }
            };

ActivityManager 的服务是什么时候注册到ServiceManager中的 ? 通过源码查看发现 ActivityManagerService 是在SystemServer 中初始化的。 这个SystemServer 又是什么东西了?

SystemServer 是系统级别的服务,当系统被启动时,首先会执行系统的 init 进程 然后通过fork创建Zygote 进程其实也就是app_process进程,这些都 native 代码, 最终会执行到java层的 ZygoteInit中的main方法

ZygoteInit.java 在main方法中会 调用 startSystemServer

 /**
  * Prepare the arguments and fork for the system server process.
  */
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
            throws Zygote.MethodAndArgsCaller, RuntimeException {
        long capabilities = posixCapabilitiesAsBits(
            OsConstants.CAP_IPC_LOCK,
            OsConstants.CAP_KILL,
            OsConstants.CAP_NET_ADMIN,
            OsConstants.CAP_NET_BIND_SERVICE,
            OsConstants.CAP_NET_BROADCAST,
            OsConstants.CAP_NET_RAW,
            OsConstants.CAP_SYS_MODULE,
            OsConstants.CAP_SYS_NICE,
            OsConstants.CAP_SYS_PTRACE,
            OsConstants.CAP_SYS_TIME,
            OsConstants.CAP_SYS_TTY_CONFIG,
            OsConstants.CAP_WAKE_ALARM
        );
        /* Containers run without this capability, so avoid setting it in that case */
        if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
            capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
        }
        /* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

通过 Zygote.java 中的 forkSystemServer方法 最终通过Native方法 创建 system_server进程,同时执行了 com.android.server.SystemServer 中的main方法

main方法 又调用 new SystemServer().run()方法,run方法中有如下代码 ,主要是初始化一系列的 系统服务

 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() 方法 有这么一段代码

// 创建 ActivityManagerService 对象
mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
.........
// 在后面还有 mActivityManagerService.setSystemProcess() 这么一句代码
 // Set up the Application instance for the system process and get started.
traceBeginAndSlog("SetSystemProcess");
mActivityManagerService.setSystemProcess();
traceEnd();

我们到ActivityManagerService.java 中找到这个方法,到此我们就找到了 ActivityManagerService 是怎么注册到
ServiceManager 中的

public void setSystemProcess() {
        try {
            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
            ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
            ServiceManager.addService("meminfo", new MemBinder(this));
            ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
            ServiceManager.addService("dbinfo", new DbBinder(this));
            if (MONITOR_CPU_USAGE) {
                ServiceManager.addService("cpuinfo", new CpuBinder(this));
            }
            ServiceManager.addService("permission", new PermissionController(this));
            ServiceManager.addService("processinfo", new ProcessInfoService(this));

            ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                    "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
            mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());

            synchronized (this) {
                ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
                app.persistent = true;
                app.pid = MY_PID;
                app.maxAdj = ProcessList.SYSTEM_ADJ;
                app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
                synchronized (mPidsSelfLocked) {
                    mPidsSelfLocked.put(app.pid, app);
                }
                updateLruProcessLocked(app, false, null);
                updateOomAdjLocked();
            }
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(
                    "Unable to find android system package", e);
        }
    }

扯了这么多我们继续回到 ActivityManager.getService().startActivity 的代码处,通过前面的分析我们知道了 ActivityManager.getService()得到是 ActivityManagerService对象, 我们到 ActivityManagerService中找到对应的
startActivity方法

  • 通过源码发现 在 startActivity 方法中调用的是 startActivityAsUser 方法然后又调用了
    mActivityStarter.startActivityMayWait
mActivityStarter.startActivityMayWait 方法, 源码中比较复杂我就不细细分析了,这里主要就分析一个流程
final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {
        // Refuse possible leaked file descriptors
            .............省略其他代码

            final ActivityRecord[] outRecord = new ActivityRecord[1];
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);
            .............省略其他代码
    }
startActivityLocked 方法
 int startActivityLocked(IApplicationThread caller,.......) {
        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                container, inTask);

        if (outActivity != null) {
            // mLastStartActivityRecord[0] is set in the call to startActivity above.
            outActivity[0] = mLastStartActivityRecord[0];
        }
        return mLastStartActivityResult;
    }
startActivity
private int startActivity(IApplicationThread caller, Intent intent,.........) {
        return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
    }
继续调用 重载 的 startActivity
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        } finally {
            // If we are not able to proceed, disassociate the activity from the task. Leaving an
            // activity in an incomplete state can lead to issues, such as performing operations
            // without a window container.
            if (!ActivityManager.isStartResultSuccessful(result)
                    && mStartActivity.getTask() != null) {
                mStartActivity.getTask().removeActivity(mStartActivity);
            }
            mService.mWindowManager.continueSurfaceLayout();
        }

        postStartActivityProcessing(r, result, mSupervisor.getLastStack().mStackId,  mSourceRecord,
                mTargetStack);

        return result;
    }
startActivityUnchecked
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
            ...........
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            ...........
        return START_SUCCESS;
    }
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);
boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        return false;
    }
targetStack.resumeTopActivityUncheckedLocked(target, targetOptions)
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }
        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        return result;
    }
resumeTopActivityInnerLocked()
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    .............省略其他代码
    mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
mStackSupervisor.startSpecificActivityLocked(next, true, true)
void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        .................省略其他代码
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        if (app != null && app.thread != null) {
            try {
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }
        .................省略其他代码
    }
realStartActivityLocked(r, app, andResume, checkConfig)

app.thread 是啥呢? 其实就是 IApplicationThread 这是一个接口,它的实现类就是 ActivityThread 中的 ApplicationThread 内部类
ActivityThread 又是啥? 简单来说就是一个APP的入口,启动一个App 都从这个类的main方法开始

 final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
     app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    // TODO: Have this take the merged configuration instead of separate global and
                    // override configs.
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);
}
ApplicationThread.scheduleLaunchActivity 这方法内部就是通过 Handle 发送了一个 LAUNCH_ACTIVITY 的消息
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

            updateProcessState(procState, false);
            ........省略其他代码
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

在 ActivityThread 中有一个 Handler 内部类 private class H extends Handler {},我们来到 Handler中的 handleMessage方法

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        case LAUNCH_ACTIVITY:
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

            r.packageInfo = getPackageInfoNoCheck(
                    r.activityInfo.applicationInfo, r.compatInfo);
            handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
   }
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason)
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);
        ........省略其他代码
}
performLaunchActivity(r, customIntent);
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            // 创建 通过 mInstrumentation 反射创建 Activity 对象
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

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

            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
            if (localLOGV) Slog.v(
                    TAG, r + ": app=" + app
                    + ", appName=" + app.getPackageName()
                    + ", pkg=" + r.packageInfo.getPackageName()
                    + ", comp=" + r.intent.getComponent().toShortString()
                    + ", dir=" + r.packageInfo.getAppDir());

            if (activity != null) {
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                appContext.setOuterContext(activity);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                checkAndBlockForNetworkAccess();
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }
                // 调用Activity 的 onCreate方法
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
                // 我们在 Activity 的声明周期方法中必须要调用父类的,不调用就会抛异常, 判断的源码就是在这里
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onCreate()");
                }
                r.activity = activity;
                r.stopped = true;
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }
                if (!r.activity.mFinished) {
                    activity.mCalled = false;
                    if (r.isPersistable()) {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
                                r.persistentState);
                    } else {
                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
                    }
                    if (!activity.mCalled) {
                        throw new SuperNotCalledException(
                            "Activity " + r.intent.getComponent().toShortString() +
                            " did not call through to super.onPostCreate()");
                    }
                }
            }
            r.paused = true;

            mActivities.put(r.token, r);

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }

        return activity;
    }

到此Activity的启动流程分析完毕,经过源码分析我们不得不感叹源码的复杂,通过前面那么多步准备工作,才创建了Activity的对象

通过上面的分析,我们知道了Activity 是怎么被创建和启动的,我们进入下一个话题

启动一个 未安装apk中的Activity

思路:

  • 我们知道要想打开一个Activity必须在 manifest中声明,但是插件中的Activity肯定是没有在我们的 manifest中声明的,我们怎么做到了? 我们可以使用 占坑 的思想来实现这个
  • 什么是占坑呢? 占坑就是在我们 app 的 manifest中注册一个Activity,欺骗系统通过系统系统的效验,当创建Activity实例时替换成插件中的Activity 达到启动插件Activity的目的
实现流程

我们通过分析知道了Activity在创建的时候 是通过 mInstrumentation.newActivity 来创建Activity实例的,
我们可以 hook ActivityThread 中的 mInstrumentation 字段 替换成我们的代理对象

 //获取 ActivityThread 的实例对象
    Object currentActivityThread =
        Reflect.tryReadField(Reflect.tryGetClass(ACTIVITY_THREAD_CLASS_NAME),
            "sCurrentActivityThread");
    // 获取ActivityThread 中的 mInstrumentation变量,并修改为代理对象
    Instrumentation instrumentation =
        Reflect.tryReadField(currentActivityThread, "mInstrumentation");
    Reflect.tryWriteField(currentActivityThread, "mInstrumentation",
        new PluginInstrumentation(instrumentation));

替换了 mInstrumentation 之后我们还需替换 ClassLoader 因为默认的classloader 中是没有插件 app中的 类的,
ActivityThread 中有一个 存储包信息的 ArrayMap key 是包名,值是 包信息

//获取 ActivityThread 中的 apk包信息
    ArrayMap<String, WeakReference<?>> mPackages =
        Reflect.tryReadField(currentActivityThread, "mPackages");
    // 获取到 LoadedApk
    Object loadedApk = mPackages.get(context.getPackageName()).get();
    // 获取 LoadedApk 中的classloader
    ClassLoader classLoader = Reflect.tryReadField(loadedApk, "mClassLoader");
    dynamicClassLoader =
        new PluginClassLoader("", context.getExternalCacheDir().getAbsolutePath(), "", classLoader);
    Reflect.tryWriteField(loadedApk, "mClassLoader", dynamicClassLoader);
代理ClassLoader
public class PluginClassLoader extends DexClassLoader {

  private ClassLoader classLoader;

  public PluginClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath,
      ClassLoader parent) {
    super(dexPath, optimizedDirectory, librarySearchPath, parent);
  }
  /**
   * 查找类
   */
  public Class findClass(String pluginName, String className) throws ClassNotFoundException {
    // 获取的是插件的ClassLoader,插件在安装时会创建 一个ClassLoader 优先插件的ClassLoader加载类,插件无法加载时,用宿主的ClassLoader 加载
    classLoader = PluginManager.get().getClassLoader(pluginName);
    if (classLoader == null) return loadClass(className);
    Class<?> aClass = classLoader.loadClass(className);
    if (aClass == null) {
      return loadClass(className);
    }
    return aClass;
  }
}
PluginInstrumentation 的实现,在PluginInstrumentation 重写所有的 public 方法,调用base的实现
public class PluginInstrumentation extends Instrumentation {

  private final Instrumentation base;

  public PluginInstrumentation(Instrumentation base) {
    this.base = base;
  }
  @Override public void callActivityOnStart(Activity activity) {
    base.callActivityOnStart(activity);
  }

  @Override public void onCreate(Bundle arguments) {
    base.onCreate(arguments);
  }
  // 我们知道 Activity 创建时会调用此方法
  @Override public Activity newActivity(ClassLoader cl, String className, Intent intent)
      throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    if(intent.hasExtra(PluginManager.EXTRA_TARGET_ACTIVITY)) {
      className = intent.getStringExtra(PluginManager.EXTRA_TARGET_ACTIVITY);
      String packageName = intent.getStringExtra(PluginManager.EXTRA_TARGET_PLUGIN_NAME);
      intent.setExtrasClassLoader(PluginManager.get()
          .getDynamicClassLoader());
       // 调用 自定义 ClassLoader中的 findClass 方法创建 Activity 对象
      return (Activity) PluginManager.get()
          .getDynamicClassLoader()
          .findClass(packageName, className)
          .newInstance();
    }
    return base.newActivity(cl, className, intent);
  }
  ......省略其他代码
安装插件
 public void install(String pluginName, String apkPath) {
    // 为每一个插件创建 ClassLoader
    DexClassLoader dexClassLoader =
        new DexClassLoader(apkPath, context.getExternalCacheDir().getAbsolutePath(), null,
            dynamicClassLoader);
    PackageManager pm = context.getPackageManager();
    // 获取 插件包信息
    PackageInfo packageArchiveInfo = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES
        | PackageManager.GET_SERVICES
        | PackageManager.GET_PROVIDERS
        | PackageManager.GET_RECEIVERS
        | PackageManager.GET_META_DATA);
    try {
     // 设置 资源路径 为 apk地址
      packageArchiveInfo.applicationInfo.publicSourceDir = apkPath;
      packageArchiveInfo.applicationInfo.sourceDir = apkPath;
      // 获取Resources 对象
      Resources resources = pm.getResourcesForApplication(packageArchiveInfo.applicationInfo);
      pluginMaps.put(pluginName, new PluginInfo(dexClassLoader, resources));
    } catch (PackageManager.NameNotFoundException e) {
      e.printStackTrace();
    }
基础Activity 的封装
public class ProxyActivity extends AppCompatActivity {

  @Override
  public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
    ComponentName component = intent.getComponent();
    intent.putExtra(PluginManager.EXTRA_TARGET_ACTIVITY, component.getClassName());
    intent.putExtra(PluginManager.EXTRA_TARGET_PLUGIN_NAME, component.getPackageName());
    // 这里启动 代理的 Activity,系统效验完成之后在替换成我们真实需要启动的Activity
    intent.setComponent(
        new ComponentName(getPackageName(), ProxyActivity.class.getCanonicalName()));
    super.startActivityForResult(intent, requestCode, options);
  }
}
MainActivity
public class MainActivity extends ProxyActivity {

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

  public void test(View view) {
    Intent intent = new Intent();
    // 启动一个插件Activity
    intent.setComponent(new ComponentName("app", "com.liwg.src.mybasiclib.MainActivity"));
    startActivity(intent);
  }
}
我们来看插件的代码
插件 的base Activity
public class PluginBaseActivity extends AppCompatActivity {
  Resources resources;
  // 通过宿主获取插件对应的 resources对象
  private Resources loadResources() {
    if (resources != null) return resources;
    Object pluginManager =
        Reflect.tryInvokeMethod("com.liwg.src.dynamicandroid.PluginManager", "get");
    resources = (Resources) Reflect.tryInvokeMethod(pluginManager, "getResources", "app");
    return resources;
  }

  // 插件的 Resources
  public Resources getPluginResources() {
    return resources;
  }
  // 重写 LayoutInflater 服务,替换Resources
  @Override public Object getSystemService(String name) {
    if (Context.LAYOUT_INFLATER_SERVICE.equals(name)) {
      LayoutInflater layoutInflater = (LayoutInflater) super.getSystemService(name);
      return layoutInflater
          .cloneInContext(new ContextWrapper(getBaseContext()) {
            @Override public Resources getResources() {
              return loadResources();
            }
          });
    }
    return super.getSystemService(name);
  }
}
插件中的Activity
public class MainActivity extends PluginBaseActivity {
  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
        new Toastor(getApplicationContext()).showLongToast("这是插件:" + getPluginResources().getString(R.string.plugin_name));
      }
    });
  }
}

这样就实现了 启动一个未安装 apk中的Activity

Activity-plugin.gif

https://github.com/lwugang/DynamicAndroid

总结

  • 这个案例主要是用于学习,开发中肯定是不能这么用的,很多细节都未处理
  • 插件中必须要用 getPluginResources() 获取资源,如果直接重写 Activity中的 getResources 方法会出现找不到v7主题的问题,暂时没想到解决办法 (在这请教各位)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容