Android中的四大组件详解

Android中的四大组件详解

我们都知道Android系统应用层框架中,为开发者提供了四大组件来便于应用的开发,它们是Activity、Service、BroadcastReceiver、ContentProvider。
它们用于在应用开发过程中,不同场景的功能实现。

Activity:Activity是开发中最常用的,也是最复杂的一个组件。它是用户可以专注做一些事情的东西。它的主要功能就是可以和用户进行交互操作,所以几乎所有的Activity都会负责创建一个显示窗口,然后通过setContentView显示特定的UI。

Service:除了Activity,Service是第二复杂的组件。和Activity相比,Service是一种处于后台长时间运行的组件,它没有UI界面,不需要与用户交互。它被设计用来后台执行耗时任务或者为其他应用程序提供功能调用的服务。

BroadcastReceiver:广播接收者,这个组件比较简单,比较好理解了。类似于观察者模式,应用程序可以添加自己关心的广播事件,从而为用户提供更好的使用体验。这些广播可以是来自于操作系统、其他的应用程序、甚至是自己的应用程序。例如网络连接变化、电池电量变化、开机启动等。

ContentProvider:内容提供者,它被设计用来在不同的应用程序之间共享数据。例如电话程序中的联系人数据,就可以被其他应用程序读取。如果仅仅是在同一个程序中存取数据的话,用SQLiteDatabase接口就可以了。

四大组件的使用方法,官网有比较详细的说明和示例,这里主要是分析他们的实现原理和注意事项。

一般性问题

系统是如何管理四大组件的

除了BroadcastReceiver可以动态注册外,四大组件在使用之前必须先在 AndroidManifest.xml清单文件中进行声明。类似下面代码:

//Activity声明
<activity
  android:name=".xxxActivity"
  android:screenOrientation="portrait"
  android:windowSoftInputMode="adjustPan">
  <intent-filter android:label="@string/app_name">
      <action android:name="android.intent.action.VIEW" />

      <category android:name="android.intent.category.DEFAULT" />
      <category android:name="android.intent.category.BROWSABLE" />
      <data
          android:host="host"
          android:scheme="scheme" />
  </intent-filter>
</activity>

//Service声明
<service
  android:name=".xxxService"
  android:exported="true" />

//BroadcastReceiver声明  
<receiver android:name=".xxxReceiver">
  <intent-filter>
      <action android:name="android.intent.action.BOOT_COMPLETED" />
      <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
      <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
      <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
  </intent-filter>
</receiver>

//ContentProvider声明
<provider
  android:name="androidx.core.content.FileProvider"
  android:authorities="${PACKAGE_NAME}.fileprovider"
  android:exported="false"
  android:grantUriPermissions="true">
  <meta-data
      android:name="android.support.FILE_PROVIDER_PATHS"
      android:resource="@xml/sharesfilepaths" />
</provider>

在应用程序安装时,应用安装程序通过PackageInstaller服务解析应用安装包,并将AndroidManifest.xml中声明的四大组件信息保存到PackageManagerService中。

public class PackageManagerService extends IPackageManager.Stub
        implements PackageSender {
    
    ...
    
    //组件解析器,存储了系统所有应用程序的四大组件信息
    private final ComponentResolver mComponentResolver;
    
}

public class ComponentResolver {
    /** All available activities, for your resolving pleasure. */
    @GuardedBy("mLock")
    private final ActivityIntentResolver mActivities = new ActivityIntentResolver();

    /** All available providers, for your resolving pleasure. */
    @GuardedBy("mLock")
    private final ProviderIntentResolver mProviders = new ProviderIntentResolver();

    /** All available receivers, for your resolving pleasure. */
    @GuardedBy("mLock")
    private final ActivityIntentResolver mReceivers = new ActivityIntentResolver();

    /** All available services, for your resolving pleasure. */
    @GuardedBy("mLock")
    private final ServiceIntentResolver mServices = new ServiceIntentResolver();
    
    ...
}

什么是Context

Context是关于应用程序环境的全局信息接口,Context是一个抽象类,它的实现都是由系统类实现的。Context允许访问应用程序特定的资源和类,如

  1. 资源管理器AssetsManager、
  2. 包管理器PackageManager、
  3. 文本图片主题资源Resource、
  4. 主线程消息循环Looper
  5. 四大组件操作,如启动Activity、BroadcastReceiver,接收Intent
  6. SharedPreferences操作
  7. 私有目录文件操作
  8. 数据库创建、删除操作
  9. 获取系统服务
  10. 权限操作
//android.content.Context

public abstract class Context {
    public abstract AssetManager getAssets();
    
    public abstract Resources getResources();
    
    public abstract PackageManager getPackageManager();

    public abstract ContentResolver getContentResolver();
    
    public abstract Looper getMainLooper();
    
    public final CharSequence getText(@StringRes int resId) {
        return getResources().getText(resId);
    }
    
    public final String getString(@StringRes int resId) {
        return getResources().getString(resId);
    }
    
    public abstract String getPackageName();
}

Context的实现类为ContextImpl,ContextImpl为Activity或其他应用程序组件提供了基础的Context实现。

//android.app.ContextImpl

class ContextImpl extends Context {

    //ContextImpl的构造方法是私有的,只能通过几个静态方法创建ContextImpl实例
    private ContextImpl(@Nullable ContextImpl container, 
                        @NonNull ActivityThread mainThread,
                        @NonNull LoadedApk packageInfo, 
                        @Nullable String splitName,
                        @Nullable IBinder activityToken, 
                        @Nullable UserHandle user, int flags,
                        @Nullable ClassLoader classLoader, 
                        @Nullable String overrideOpPackageName) {
        ...
    }

    ....

    //创建系统应用的上下文
    @UnsupportedAppUsage
    static ContextImpl createSystemContext(ActivityThread mainThread) {
        LoadedApk packageInfo = new LoadedApk(mainThread);
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null, null);
        context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), ontext.mResourcesManager.getDisplayMetrics());
        return context;
    }
    
    //基于系统应用Context创建的用于UI的系统上下文,此上下文具有可以主题化的资源
    static ContextImpl createSystemUiContext(ContextImpl systemContext, 
                                            int displayId) {
        final LoadedApk packageInfo = systemContext.mPackageInfo;
        ContextImpl context = new ContextImpl(null, systemContext.mMainThread, 
                                packageInfo, null,null, null, 0, null, null);
        context.setResources(createResources(null, packageInfo, null, displayId, 
                                null,packageInfo.getCompatibilityInfo()));
        context.updateDisplay(displayId);
        return context;
    }
    
    //创建普通应用级别的上下文,packageInfo指定了某个已安装的应用
    static ContextImpl createAppContext(ActivityThread mainThread, 
                                        LoadedApk packageInfo,
                                        String opPackageName) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
        ContextImpl context = new ContextImpl(null, mainThread, packageInfo,        
                                                null, null, null, 0,
                                                 null, opPackageName);
        context.setResources(packageInfo.getResources());
        return context;
    }
    
    //创建Activity级别的上下文
    static ContextImpl createActivityContext(ActivityThread mainThread,
                                       LoadedApk packageInfo, 
                                       ActivityInfo activityInfo, 
                                       IBinder activityToken, //代表一个Activity
                                       int displayId,
                                       Configuration overrideConfiguration) {
        if (packageInfo == null) 
            throw new IllegalArgumentException("packageInfo");

        String[] splitDirs = packageInfo.getSplitResDirs();
        ClassLoader classLoader = packageInfo.getClassLoader();

        if (packageInfo.getApplicationInfo().requestsIsolatedSplitLoading()) {
            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "SplitDependencies");
            try {
           classLoader=packageInfo.getSplitClassLoader(activityInfo.splitName);
                splitDirs = packageInfo.getSplitPaths(activityInfo.splitName);
            } catch (NameNotFoundException e) {
        // Nothing above us can handle a NameNotFoundException, better crash.
                throw new RuntimeException(e);
            } finally {
                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
            }
        }

        ContextImpl context = new ContextImpl(null, mainThread, packageInfo, 
            activityInfo.splitName,activityToken, null, 0, classLoader, null);

        // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY.
        displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : 
                                                    Display.DEFAULT_DISPLAY;

        final CompatibilityInfo compatInfo = (displayId == 
                                            Display.DEFAULT_DISPLAY)
                                    ? packageInfo.getCompatibilityInfo()
                                : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;

        final ResourcesManager resourcesManager =ResourcesManager.getInstance();

        // Create the base resources for which all configuration contexts for this Activity
        // will be rebased upon.
        context.setResources(resourcesManager.createBaseActivityResources(
                activityToken,
                packageInfo.getResDir(),
                splitDirs,
                packageInfo.getOverlayDirs(),
                packageInfo.getApplicationInfo().sharedLibraryFiles,
                displayId,
                overrideConfiguration,
                compatInfo,
                classLoader));
        context.mDisplay = resourcesManager.getAdjustedDisplay(displayId,
                context.getResources());
        return context;
    }
    ...
}

除了ContextImpl类外,ContextWrapper类也继承了Context,但是ContextWrapper类并不自己实现了Context的方法,而是通过构造方法,代理给另外一个Context的实现。这样ContextWrapper的子类就可以在不修改ContextWrapper类的情况下,修改其调用方法的实现。

public class ContextWrapper extends Context {
    Context mBase;
    
    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    
    ...
}

我们在开发中用到的Activity、Application、Service类都是集成自ContextWrapper类的,然后在构建出实例后,通过ContextWrapper的attachBaseContext(Context)方法,将真正的Context实现类添加进去。这样就可以动态控制Activity、Application、Service类调用Context的方法实现了。

例如创建Application的过程:

//android.app.LoadedApk

public Application makeApplication(boolean forceDefaultAppClass,
                                    Instrumentation instrumentation) {
    Application app = null;    
    String appClass = mApplicationInfo.className;
    java.lang.ClassLoader cl = getClassLoader();
    //创建一个普通应用的上下文
    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread,
                                 this);
    //通过Instrumentation类创建Application,并设置上下文
    app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
}
public Application newApplication(ClassLoader cl, String className, 
                                Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
   Application app = getFactory(context.getPackageName())
           .instantiateApplication(cl, className);
   app.attach(context);
   return app;
}
final void attach(Context context) {
   attachBaseContext(context);
   mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

最终通过Application类的attach(Context)方法将上下文的实现类设置给ContextWrapper。

Hook四大组件的实例化过程

我们都知道,四大组件或者Application类的实例都是在ActivityThread中,通过反射调用无参构造函数创建的,那么我们可不可以控制这个创建过程呢?例如添加一个带参数的构造函数。
答案是AppComponentFactory类。我们可以通过继承该类,并重写Application、Activity等创建的方法就可以了。
然后再AndroidManifest.xml文件中,指定Application标签的android:appComponentFactory="xxxAppComponentFactory"属性即可。

AppComponentFactory类的定义如下:

//android.app.AppComponentFactory

public class AppComponentFactory {
    public @NonNull ClassLoader instantiateClassLoader(@NonNull ClassLoader cl,
            @NonNull ApplicationInfo aInfo) {
        return cl;
    }
    
    public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
            @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Application) cl.loadClass(className).newInstance();
    }
    
    public @NonNull Activity instantiateActivity(@NonNull ClassLoader cl, @NonNull String className,
            @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Activity) cl.loadClass(className).newInstance();
    }
    
    public @NonNull BroadcastReceiver instantiateReceiver(@NonNull ClassLoader cl,
            @NonNull String className, @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (BroadcastReceiver) cl.loadClass(className).newInstance();
    }
    
    public @NonNull Service instantiateService(@NonNull ClassLoader cl,
            @NonNull String className, @Nullable Intent intent)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Service) cl.loadClass(className).newInstance();
    }
}

但是AppComponentFactory接口只能在Api28以上的系统版本中使用。

Activity、ContentProvider、Service三者的启动顺序

一个新的应用启动时,会优先初始化其Application类,创建了Application实例后,会立即调用其attach方法。
然后就会初始化应用中声明的ContentProvider:

if (!data.restrictedBackupMode) {
 if (!ArrayUtils.isEmpty(data.providers)) {
     installContentProviders(app, data.providers);
     // For process that contains content providers, we want to
     // ensure that the JIT is enabled "at some point".
     mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
 }
}

ContentProvider初始化完成后,会再调用Application类的onCreate方法。

AMS在初始化完客户端的Application类后,会检查是否有需要运行的Service和BroadcastReceiver。

// Find any services that should be running in this process...
if (!badApp) {
  try {
      didSomething |= mServices.attachApplicationLocked(app, processName);
      checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
  } catch (Exception e) {
      Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
      badApp = true;
  }
}

// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
  try {
      didSomething |= sendPendingBroadcastsLocked(app);
      checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
  } catch (Exception e) {
      // If the app died trying to launch the receiver we declare it 'bad'
      Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
      badApp = true;
  }
}

所以初始化顺序是Application.attach() > ContentProvider> Application.onCreate() > Activity/Service/BroadcastReceiver。
ContentProvider比Activity或Service初始化的顺序都要早,所以有些第三方库利用这个特性,通过ContentProvider自动初始化一些功能,而不用在Application中添加初始化代码。

Activity

生命周期

protected void onCreate(Bundle savedInstanceState);
Activity创建,用于初始化数据

protected void onStart();
Activity UI可见

protected void onRestart();
Activity UI从不可见变为可见

protected void onResume();
Activity UI可操作

protected void onPause();
Activity 暂停,UI可见,不可操作

protected void onStop();
Activity停止,UI不可见

protected void onDestroy();
Activity销毁

创建和管理

  1. 通过Activity或ContextImpl的startActivity启动指定的Activity,这里的区别是在非Activity上下文启动Activity时,会判断是否指定了Intent.FLAG_ACTIVITY_NEW_TASK标识。
  2. 经过Instrumentation监控类转发
  3. 通过进程间通信调用到ActivityManagerService中
  4. 根据Intent从PackageManagerService中找出对应的Activity信息,前面提到应用安装时会把四大组件信息解析出来存储到PackageManagerService中
  5. 找到目标Activity对应的进程ProcessRecord,通过ApplicationThread这个Binder接口,告知客户端进程创建指定的Activity。

在这个过程中涉及到了几个数据模型类和操作类:

ProcessRecord:代表一个当前运行的进程全部信息,在创建新进程前,由ActivityManagerServer创建ProcessRecord实例,并存储到ActivityManagerServer中ProcessMap。ProcessRecord中的IApplicationThread thread属性是一个Binder接口,用于AMS向客户端进程发送控制消息。

ActivityRecord:代表一个Activity任务栈中的Activity实例,包含对应Activity信息(从Manifest解析出来)、Activity所属Application的信息、真正的Activity组件信息、运行在哪个进程的名称、包名、用于和WindowManager交互的token、所属的AMS实例、谁启动的这个Activity、当前Activity的运行状态(stopped/finishing)等

TaskRecord:代表一个任务栈,每个任务栈中包含多个Activity记录。

ActivityStarter:负责如何通过Intent和Flags来启动Activity。也可以说是AMS的辅助类,承载了启动Activity请求的后续操作(权限检查、运行时权限申请、语音交互判断、
延时启动判断(点Home键退出,显示悬浮窗,点击悬浮窗再返回原应用,会延迟5s))。当需要启动一个新的Activity时,会创建一个ActivityRecord记录

ActivityStack:Activity任务栈管理器,管理了一个App中所有的TaskRecord,并负责管理所有ActivityRecord的状态变化。当新启动一个Activity时,由ActivityStack负责找到合适的TaskRecord,并添加进去。

ActivityStackSupervisor:管理ActivityStack的。系统中会存在多个Activity栈,ActivityStackSupervisor记录了桌面应用的ActivityStack mHomeStack,还有当前活跃的ActivityStack mFocusedStack。同时,如果需要启动新的Activity,还会通过ApplicationThread Binder接口通知客户端创建新的Activity实例。

AMS和客户端进程通过IApplicationToken.Sub的子类Token来标识一个ActivityRecord,这样双方通过传递这个Token,就可以知道需要操作的ActivityRecord是哪一个。

客户端进程收到启动Activity的消息后,就创建对应Activity实例,并逐一调用其attach、onCreate、onStart、onRestoreInstanceState、onPostCreate、(onNewIntent)、onResume生命周期函数。
之后就是UI显示的逻辑了,创建Window、DecorView、ViewRootImpl,通过WindowManagerService添加DecorView。

最后,如果整个Activity显示的过程都正常,还要通知AMS,这个Activity已经成功Resume了。AMS需要通过ActivityStack修改这个Activity的一些状态。

ActivityStarter 创建ActivityRecord
final int startActivityLocked(IApplicationThread caller, Intent intent, 
                                Intent ephemeralIntent,
                                String resolvedType, ActivityInfo aInfo, 
                                ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, 
            IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, 
            int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, 
            int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, 
            boolean componentSpecified,
            ActivityRecord[] outActivity,       
            ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
    ...
    
ProcessRecord callerApp = null;
    
     ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid,
                callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, 
                resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, 
                mSupervisor, container,
                options, sourceRecord);
}
处理FLAG_ACTIVITY_SINGLE_TOP情况

如果当前活跃栈栈顶的Activity与目标Activity是同一个,并且启动标识为FLAG_ACTIVITY_SINGLE_TOP,则不会将ActivityRecord添加到ActivityStack中。
只是调用其newIntent回调。

final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
        final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.realActivity.equals(mStartActivity.realActivity)
                && top.userId == mStartActivity.userId
                && top.app != null && top.app.thread != null
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || mLaunchSingleTop || mLaunchSingleTask);
        if (dontStart) {
            ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
            // For paranoia, make sure we have correctly resumed the top activity.
            topStack.mLastPausedActivity = null;
            if (mDoResume) {
                mSupervisor.resumeFocusedStackTopActivityLocked();
            }
            ActivityOptions.abort(mOptions);
            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                // We don't need to start a new activity, and the client said not to do
                // anything if that is the case, so this is it!
                return START_RETURN_INTENT_TO_CALLER;
            }
            top.deliverNewIntentLocked(
                    mCallingUid, mStartActivity.intent, 
                    mStartActivity.launchedFromPackage);

            // Don't use mStartActivity.task to show the toast. We're not starting a new activity
            // but reusing 'top'. Fields in mStartActivity may not be fully initialized.
            mSupervisor.handleNonResizableTaskIfNeeded(
                    top.task, preferredLaunchStackId, topStack.mStackId);

            return START_DELIVERED_TO_TOP;
        }
处理FLAG_ACTIVITY_NEW_TASK情况

根据FLAG_ACTIVITY_NEW_TASK标识创建一个新的任务栈TaskRecord

// Should this be considered a new task?
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
      && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
    newTask = true;
    setTaskFromReuseOrCreateNewTask(taskToAffiliate);   
}    
处理FLAG_ACTIVITY_CLEAR_TOP情况

如果没有设置FLAG_ACTIVITY_NEW_TASK标识,则判断是否可以添加到源Activity所属的任务栈中TaskRecord。

private int setTaskFromSourceRecord() {
    final TaskRecord sourceTask = mSourceRecord.task;
    
    ...
    
    if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
        // 存在FLAG_ACTIVITY_CLEAR_TOP标识,并且栈中已经存在目标Activity,
        //则清除顶部的Activity,并调用目标Activity的newIntent回调,然后resume
        ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, 
                                                                mLaunchFlags);
        
        if (top != null) {
            top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, 
                                        mStartActivity.launchedFromPackage);
            if (mDoResume) {
                mSupervisor.resumeFocusedStackTopActivityLocked();
            }
        }
    }
}
处理FLAG_ACTIVITY_REORDER_TO_FRONT

FLAG_ACTIVITY_REORDER_TO_FRONT启动方式是为Intent单独设置的,不能在Manifest文件中设置。
意思是将已经存在的Activity实例移动到栈顶来,而不是创建新的。

else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
final ActivityRecord top=sourceTask.findActivityInHistoryLocked(mStartActivity);
    if (top != null) {
      final TaskRecord task = top.task;
      //移动到栈顶
      task.moveActivityToFrontLocked(top);
      top.updateOptionsLocked(mOptions);
      ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task);
      top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, 
                                    mStartActivity.launchedFromPackage);
      mTargetStack.mLastPausedActivity = null;
      if (mDoResume) {
          mSupervisor.resumeFocusedStackTopActivityLocked();
      }
      return START_DELIVERED_TO_TOP;
  }
}
处理默认情况,也就是标准启动模式

如果前面几个启动模式都不满足,就是默认启动方式,在当前栈中创建新的实例。

// An existing activity is starting this new activity, so we want to keep the new one in
// the same task as the one that is starting it.
mStartActivity.setTask(sourceTask, null);
真正的添加到任务栈中

前面几步只是为目标Activity寻找合适TaskRecord,但是并没有真正的添加进去。
接下来会通过ActivityStack,在其管理的TaskRecord集合中遍历出匹配的TaskRecord,然后添加进去。

//ActivityStack.java

final void startActivityLocked(ActivityRecord r, boolean newTask, 
                                boolean keepCurTransition,
                                ActivityOptions options) {
    TaskRecord rTask = r.task;
    final int taskId = rTask.taskId;
    
    for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
        task = mTaskHistory.get(taskNdx);
         if (task.getTopActivity() == null) {
             // All activities in task are finishing.
             continue;
         }
         if (task == r.task) {
             // Here it is!  Now, if this is not yet visible to the
             // user, then just add it without starting; it will
             // get started when the user navigates back to it.
             if (!startIt) {
                 task.addActivityToTop(r);
                 r.putInHistory();
                 addConfigOverride(r, task);
                 if (VALIDATE_TOKENS) {
                     validateAppTokensLocked();
                 }
                 ActivityOptions.abort(options);
                 return;
             }
             break;
         } else if (task.numFullscreen > 0) {
             startIt = false;
         }
    }
    
    ...
    //上面是将目标Activity添加到已有任务栈的情况,下面是添加到新的任务栈中的情况
    //1. 新的任务栈要显示一个预览窗口
    //2. 刷新WMS的AppToken

}
启动目标Activity

在启动目标Activity前,还要判断两个条件:
1、目标Activity是否允许获取焦点,也就是是否设置了FLAG_ALWAYS_FOCUSABLE标识
2、当前活动的Activity是否是一直处于顶层,还没有finish完成。

在这两个条件下,目标Activity就不能立即Resume,但是可以允许目标Activity处于可见状态。并执行转场动画。
否则的话,就启动Resume目标Activity。

final ActivityRecord topTaskActivity = mStartActivity.task.topRunningActivityLocked();
if (!mTargetStack.isFocusable()
     || (topTaskActivity != null && topTaskActivity.mTaskOverlay
     && mStartActivity != topTaskActivity)) {
 // If the activity is not focusable, we can't resume it, but still would like to
 // make sure it becomes visible as it starts (this will also trigger entry
 // animation). An example of this are PIP activities.
 // Also, we don't want to resume activities in a task that currently has an overlay
 // as the starting activity just needs to be in the visible paused state until the over is removed.
 mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
 // Go ahead and tell window manager to execute app transition for this activity
 // since the app transition will not be triggered through the resume channel.
 mWindowManager.executeAppTransition();
} else {
 mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
         mOptions);
}
启动目标Activity前,还要先暂停前一个活动的Activity
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
    
    ...
    
    //先暂停当前处于Resume状态的Activity
    //然后将目标Activity的ApplicationThread Binder通信存储到LRU缓存中,方便继续执行Resume操作
    if (mResumedActivity != null) {
      pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
    }
    if (pausing) {
        if (next.app != null && next.app.thread != null) {
           mService.updateLruProcessLocked(next.app, true, null);
       }
       return true;
    }
    
    ...
    //前一个Activity暂停完成后,还会走到该方法中,启动目标Activity
    else {
       // Whoops, need to restart this activity!
       if (!next.hasBeenLaunched) {
           next.hasBeenLaunched = true;
       } else {
           if (SHOW_APP_STARTING_PREVIEW) {
               next.showStartingWindow(null, true);
           }
           if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
       }
       mStackSupervisor.startSpecificActivityLocked(next, true, true);
   }
   
   return true;
}

最终启动目标Activity的操作就是ActivityStackSupervisor中的startSpecificActivityLocked方法。它会根据是否存在目标Activity所在的应用进程来决定是直接启动目标Activity,还是先启动新的进程。

Service

Service是一种应用程序组件,用于两种使用场景:

  1. 后台执行长时间的任务,而不需要与用户交互。例如后台播放音乐
  2. 将本应用的功能通过接口的形式暴露给其他应用程序调用

Service运行在当前进程的主线程,可以指定其运行在不同的进程。

public abstract class Service extends ContextWrapper 
                            implements ComponentCallbacks2 {
    //Service第一次创建时回调
    public void onCreate() {
    }
    
    //每次调用startService后的回调
    public @StartResult int onStartCommand(Intent intent, 
                                            @StartArgFlags int flags, 
                                            int startId) {
        onStart(intent, startId);
        return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
    }
    
    public abstract IBinder onBind(Intent intent);
    
    //设置Service为前台服务
    public final void startForeground(int id, Notification notification) {
        try {
            mActivityManager.setServiceForeground(
                    new ComponentName(this, mClassName), mToken, id,
                    notification, 0, FOREGROUND_SERVICE_TYPE_MANIFEST);
        } catch (RemoteException ex) {
        }
    }
    
    //Service销毁时的回调
    public void onDestroy() {
    }
}

两种启动Service的方式:
1、startService,Service会执行onCreate和onStartCommand。多次启动同一个Service不会多次执行onCreate,会多次执行onStartCommand
2、bindService,Service会执行onBind方法,返回给调用者一个Binder对象,用于功能接口调用。

Service优先级:
Service所在进程的优先级仅次于前台进程的优先级,系统会尽量避免杀死该进程,除非内存压力非常大。如果被系统杀死了,系统会稍后尝试重启该Service,并重新将Intent数据发送Service来恢复杀死之前的状态。

onStartCommand方法的返回值,决定Service被系统杀死后的操作

  1. START_NOT_STICKY 被系统杀死后不会被重启
  2. START_STICKY 被系统杀死后会重建,但是会发送一个null给onStartCommand
  3. START_REDELIVER_INTENT 被系统杀死后会重建,并且会逐一发送等待处理的Intent给onStartCommand

startService

  1. 请求到ActivityManagerService来启动对应Service。
private ComponentName startServiceCommon(Intent service, UserHandle user) {
   try {
       validateServiceIntent(service);
       service.prepareToLeaveProcess(this);
       ComponentName cn = ActivityManagerNative.getDefault().startService(
           mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                       getContentResolver()), getOpPackageName(), user.getIdentifier());
       if (cn != null) {
           if (cn.getPackageName().equals("!")) {
               throw new SecurityException(
                       "Not allowed to start service " + service
                       + " without permission " + cn.getClassName());
           } else if (cn.getPackageName().equals("!!")) {
               throw new SecurityException(
                       "Unable to start service " + service
                       + ": " + cn.getClassName());
           }
       }
       return cn;
   } catch (RemoteException e) {
       throw e.rethrowFromSystemServer();
   }
}

如果没有启动权限,会返回包名为!/!!的ComponentName。

  1. 转到ActiveServices类
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
       String resolvedType, String callingPackage, int userId)
       throws TransactionTooLargeException {
       //用户ID在99000~99999范围内才可以调用startService,完全独立的沙盒进程
   enforceNotIsolatedCaller("startService");
   // Refuse possible leaked file descriptors
   if (service != null && service.hasFileDescriptors() == true) {
       throw new IllegalArgumentException("File descriptors passed in Intent");
   }

   if (callingPackage == null) {
       throw new IllegalArgumentException("callingPackage cannot be null");
   }

   synchronized(this) {
       final int callingPid = Binder.getCallingPid();
       final int callingUid = Binder.getCallingUid();
       final long origId = Binder.clearCallingIdentity();
       //mService是ActiveServices的实例,在AMS构造函数中初始化
       ComponentName res = mServices.startServiceLocked(caller, service,
               resolvedType, callingPid, callingUid, callingPackage, 
               userId);
       Binder.restoreCallingIdentity(origId);
       return res;
   }
}

ComponentName startServiceLocked(IApplicationThread caller, Intent service, 
                                String resolvedType,
                                int callingPid, 
                                int callingUid, 
                                String callingPackage, 
                                final int userId)
            throws TransactionTooLargeException {
    
    //寻找是否存在目标Service的ServiceRecord,如果不存在就新创建一个ServiceRecord
    ServiceLookupResult res =
            retrieveServiceLocked(service, resolvedType, callingPackage,
                    callingPid, callingUid, userId, true, callerFg, false);
    
    //为目标Service添加一个启动待办事项
    //如果我们多次调用startService方法,这里会添加多个启动待办事项
    r.lastActivity = SystemClock.uptimeMillis();
    r.startRequested = true;
    r.delayedStop = false;
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, 
                                               r.makeNextStartId(),
                                               service, neededGrants));
                    
    ...
    
    //之后并不是直接目标Service,而是判断调用者是否是前台应用并且目标Service所在进程是否存在
    //也就是说,通过后台新启动一个Service进程,会将这个请求被加入延迟启动队列,
    //防止有多个后台服务启动请求
    
    if (!callerFg 
        && r.app == null
        && mAm.mUserController.hasStartedUserState(r.userId)) {
        ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, 
                            r.appInfo.uid, false);
            if (proc == null || proc.curProcState > 
                 ActivityManager.PROCESS_STATE_RECEIVER) {
                //mMaxStartingBackground代表后台同时启动的Service最大数量
                //这个值是可以配置的,默认根据Ram容量分为1或8
                if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                    // Something else is starting, delay!
                    smap.mDelayedStartList.add(r);
                    r.delayed = true;
                    return r.name;
                }
                addToStarting = true;
            }
    }
    
    //其他情况就是直接启动目标Service
    return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
目标Service所在进程存在,并且目标Service已启动
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, 
                                    boolean execInFg,
                                    boolean whileRestarting, 
                                    boolean permissionsReviewRequired)
                                    throws TransactionTooLargeException {
    if (r.app != null && r.app.thread != null) {
        //向目标进程发送启动Service的命令
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }
}

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
    final int N = r.pendingStarts.size();
   if (N == 0) {
       return;
   }
    
   //遍历所有的待办请求,通过ApplicationThread Binder通知客户端进程
   while (r.pendingStarts.size() > 0) {
   
       ...
       r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, 
                                            si.intent);
       ... 
        
   }    
}

在将调用请求发送给客户端前,还会通过Handler添加一个操作超时的消息,用来处理客户端进程处理请求超时的情况。这个超时时间一般是20s,如果目标Service所在进程位于后台,超时时间为20*10s。

下面看一下,客户端进程是如何处理重复调用scheduleServiceArgs调用的。

private void handleServiceArgs(ServiceArgsData data) {
   Service s = mServices.get(data.token);
   if (s != null) {
       try {
           if (data.args != null) {
               data.args.setExtrasClassLoader(s.getClassLoader());
               data.args.prepareToEnterProcess();
           }
           int res;
           if (!data.taskRemoved) {
               res = s.onStartCommand(data.args, data.flags, data.startId);
           } else {
               s.onTaskRemoved(data.args);
               res = Service.START_TASK_REMOVED_COMPLETE;
           }

           QueuedWork.waitToFinish();

           try {
               ActivityManagerNative.getDefault().serviceDoneExecuting(
                       data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
           } catch (RemoteException e) {
               throw e.rethrowFromSystemServer();
           }
           ensureJitEnabled();
       } catch (Exception e) {
           if (!mInstrumentation.onException(s, e)) {
               throw new RuntimeException(
                       "Unable to start service " + s
                       + " with " + data.args + ": " + e.toString(), e);
           }
       }
   }
}
  1. 根据token获取已经启动的Service实例
  2. 判断是否是任务删除的调用
  3. 调用Service实例的onStartCommand方法
  4. 告知AMS操作完成,AMS收到操作完成的通知后,会移除操作超时的消息处理
目标Service所在进程不存在,先启动进程,再启动Service
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
           
    ... 
            
    // Not running -- get it started, and enqueue this service record
   // to be executed when the app comes up.
   //目标进程不存在,先启动它,然后将启动Service的请求添加队列中,等待目标进程启动完成之后再执行
   if (app == null && !permissionsReviewRequired) {
        //进程创建的流程
       if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
               "service", r.name, false, isolated, false)) == null) {
           String msg = "Unable to launch app "
                   + r.appInfo.packageName + "/"
                   + r.appInfo.uid + " for service "
                   + r.intent.getIntent() + ": process is bad";
           Slog.w(TAG, msg);
           bringDownServiceLocked(r);
           return msg;
       }
       if (isolated) {
           r.isolatedProc = app;
       }
   }

   if (!mPendingServices.contains(r)) {
       mPendingServices.add(r);
   }
   
   ...
}

前面提到过,一个新的客户单进程在创建完成后,会将一个ApplicationThread的binder接口发送给AMS,然后AMS会通过这个接口告知客户端进程初始化Application类。Application类初始化完成后,AMS就会判断是否有Service或BroadcastReceiver等待着在这个新进程中执行。
其中Service执行的判断也是在ActiveServices类中完成的。

boolean attachApplicationLocked(ProcessRecord proc, String processName)
            throws RemoteException {
    boolean didSomething = false;
    if (mPendingServices.size() > 0) {
        for (int i=0; i<mPendingServices.size(); i++) {
          sr = mPendingServices.get(i);
          if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                  || !processName.equals(sr.processName))) {
              continue;
          }

          mPendingServices.remove(i);
          i--;
          proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
                  mAm.mProcessStats);
         //真正的去启动目标Service
          realStartServiceLocked(sr, proc, sr.createdFromFg);
          didSomething = true;
          if (!isServiceNeeded(sr, false, false)) {
              bringDownServiceLocked(sr);
          }
      }
    }
    
    //重新启动Service的请求
    if (mRestartingServices.size() > 0) {
       ServiceRecord sr;
       for (int i=0; i<mRestartingServices.size(); i++) {
           sr = mRestartingServices.get(i);
           if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                   || !processName.equals(sr.processName))) {
               continue;
           }
           mAm.mHandler.removeCallbacks(sr.restarter);
           mAm.mHandler.post(sr.restarter);
       }
   }
}

这里有两个列表的遍历:
一个启动目标Service的请求列表,这个请求是在前面请求Service时但进程没启动情况下添加到列表中的。
第二个是重新启动Service的请求列表,这个重新启动的请求不是客户端程序调用的,而是当Service被意外杀死后,如果Service的onStartCommand方法的返回值是START_STICKY或START_REDELIVER_INTENT,由系统负责重启该Service的。

目标进程存在,第一次启动Service

当目标进程成功启动后,接下来就是第一次启动Service的逻辑了。

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
    
    ...
    
    //通过ApplicationThread Binder接口告知客户端进程创建对应Service
    app.thread.scheduleCreateService(r, 
                                    r.serviceInfo,
    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                                    app.repProcState);
                                    
    ...
    
    //启动成功后:
    //如果是bindService启动的方式,还会回调onBind方法
    requestServiceBindingsLocked(r, execInFg);
    
    //如果startService启动的方法,还会onStartCommand方法
    sendServiceArgsLocked(r, execInFg, true);
    ...
}

下面看一下客户端进程如何响应Service创建的调用的。

private void handleCreateService(CreateServiceData data) {
    LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
    Service service = null;
    java.lang.ClassLoader cl = packageInfo.getClassLoader();
    service = (Service) cl.loadClass(data.info.name).newInstance();
    
    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);
    
    ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
  1. 创建Service实例
  2. 调用Service的attach方法
  3. 调用Service的onCreate方法
  4. 以token为key保存到Map中,方便后续多次调用onStartCommand
  5. 告知AMS启动完成

bindService

bindService与startService不同的地方是,bindService需要提供一个ServiceConnection的回调接口,用来告知调用者已连接或断开连接。

private boolean bindServiceCommon(Intent service, ServiceConnection conn, 
                                    int flags, 
                                    Handlerhandler, 
                                    UserHandle user) {
    //将ServiceConnection封装成ServiceDispatcher,
    //并返回一个Binder接口对象IServiceConnection,用于AMS调用客户端
    IServiceConnection sd;
    sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler,
                                         flags);
    
    //将bindService请求发送给AMS
    //其中必须要传入一个Activity的标识,也就是必须在Activity的上下文调用bindService
    int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());                                     
}

AMS收到bindService的请求后,和startService一样会走到bringUpServiceLocked方法中,所以Service启动流程和startService是一致的,都是依次调用Service类的attach、onCreate

//ActiveServices.java

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) 
            throws TransactionTooLargeException {
            
    ...
    if ((flags&Context.BIND_AUTO_CREATE) != 0) {
         s.lastActivity = SystemClock.uptimeMillis();
         //和startService一样的启动流程
         if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                 permissionsReviewRequired) != null) {
             return 0;
         }
    }
    
    ...
    
    if (s.app != null && b.intent.received) {
        // Service is already running, so we can immediately
        // publish the connection.
        //Service已经启动了,并且已经拿到Service的binder接口,
        //那么立即告诉客户端连接成功了
        //否则就回调目标Service的onBind方法
        try {
            c.conn.connected(s.name, b.intent.binder);
        } catch (Exception e) {
           Slog.w(TAG, "Failure sending service " + s.shortName
                   + " to connection " + c.conn.asBinder()
                   + " (in " + c.binding.client.processName + ")", e);
        }
           
       // If this is the first app connected back to this binding,
       // and the service had previously asked to be told when
       // rebound, then do so.
       if (b.intent.apps.size() == 1 && b.intent.doRebind) {
          requestServiceBindingLocked(s, b.intent, callerFg, true);
       }
   } else if (!b.intent.requested) {
       requestServiceBindingLocked(s, b.intent, callerFg, false);
   }
    
}
第一次绑定目标Service
private final boolean requestServiceBindingLocked(ServiceRecord r,
                                             IntentBindRecord i,
                                            boolean execInFg, 
                                            boolean rebind) 
                                            throws TransactionTooLargeException{
    if ((!i.requested || rebind) && i.apps.size() > 0) {
        bumpServiceExecutingLocked(r, execInFg, "bind");
        r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
        r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                                            r.app.repProcState);
        if (!rebind) {
            i.requested = true;
        }
        i.hasBound = true;
        i.doRebind = false;
    }
}

客户端响应Service绑定的请求。

private void handleBindService(BindServiceData data) {
    Service s = mServices.get(data.token);
    if (s != null) {
        data.intent.setExtrasClassLoader(s.getClassLoader());
        data.intent.prepareToEnterProcess();
        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);
        }
    }
}

这里区分了第一次绑定和重复绑定的请求。
如果是第一次绑定,调用Service的onBind方法,并将一个Binder接口的返回值告诉AMS。
如果一个Service已经被客户端绑定过了,那么第二个客户端再次绑定该Service时,AMS就不会回调Service的onBind方法了,因为已经拿到了该Service的Binder接口了,直接返回给调用者即可。

如果是重新绑定,就调用Service的onRebind方法,然后告诉AMS执行完成。重复绑定的场景是,有一个客户端之前绑定过该Service,但是解绑后又发起绑定请求。这时Service就没有必要再向AMS发送一次Binder接口了,因为AMS已经有记录了。所以只需要告诉Service,你又被重新绑定了一次。
如果Service想要收到onRebind的回调,必须在onUnbind的方法中返回true。

Service启动时的生命周期

多次调用startService

执行一次Service的onCreate
多次执行Service的onStartCommand

多次调用bindService

执行一次Service的onCreate
执行一次Service的onBind
调用方的ServiceConnection也只会回调一次

Service和AMS的调用时序

客户端进程AMS进程Service进程
第一次startService记录请求事项,创建目标进程进程创建成功
创建目标Service回调onCreate方法
发送调用参数回调onStartCommand方法
第二次startService发送调用参数回调onStartCommand方法
第一次bindService记录请求事项(Connection),创建目标进程进程创建成功
创建目标Service回调onCreate方法
绑定目标Service回调onBind方法
获取并存储目标Service的Binder接口
回调onServiceConnected
第二次bindService(不同的ServiceConnection)查询存储的Service Binder接口记录
回调onServiceConnected
第二次bindService(相同的ServiceConnection)查询存储的Service Binder接口记录
接收到AMS返回Binder接口,但是会根据目标Service组件名称查询本地存储的有效连接,如果存在就不会再回调onServiceConnected了

ContentProvider

ContentProvider用于在不同应用程序间提供数据,它在内部实现了跨进程的调用,不需要数据提供者或调用者关心。

public abstract class ContentProvider implements ContentInterface, ComponentCallbacks2 {

    //应用启动时,回调该方法,代表ContentProvider的创建,运行在主线程
    public abstract boolean onCreate();
    
    //增删改查的操作可能会运行在任何线程,需要做到线程安全
    //查询数据
    public abstract @Nullable Cursor query(@NonNull Uri uri, 
                                            @Nullable String[] projection,
            @Nullable String selection, @Nullable String[] selectionArgs,
            @Nullable String sortOrder);
            
    //插入数据
    @Override
    public abstract @Nullable Uri insert(@NonNull Uri uri, 
                                            @Nullable ContentValues values);
    
    //删除数据                                        
    @Override
    public abstract int delete(@NonNull Uri uri, @Nullable String selection,
            @Nullable String[] selectionArgs);
            
    //更新数据        
    @Override
    public abstract int update(@NonNull Uri uri, @Nullable ContentValues values,
            @Nullable String selection, @Nullable String[] selectionArgs);
     
    
    //返回查询数据的类型MIME       
    @Override
    public abstract @Nullable String getType(@NonNull Uri uri);
}

调用者通过URI向ContentProvider查询数据。

前面提到了在一个应用进程初始化的时候就会初始化该应用声明的ContentProvider,初始化时机是在Application类创建完成,执行attach()方法之后。

//ActivityThread.java

private void handleBindApplication(AppBindData data) {
    
    ...
    Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;
    
    if (!data.restrictedBackupMode) {
        if (!ArrayUtils.isEmpty(data.providers)) {
          installContentProviders(app, data.providers);
          // For process that contains content providers, we want to
          // ensure that the JIT is enabled "at some point".
          mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
        }
    }
}

//安装ContentProvider
private void installContentProviders(Context context, 
                                        List<ProviderInfo> providers) {
   final ArrayList<IActivityManager.ContentProviderHolder> results =
       new ArrayList<IActivityManager.ContentProviderHolder>();

   for (ProviderInfo cpi : providers) {
       IActivityManager.ContentProviderHolder cph = installProvider(context, 
                                                   null, 
                                                   cpi,
                                                   false /*noisy*/, 
                                                   true /*noReleaseNeeded*/, 
                                                   true /*stable*/);
       if (cph != null) {
           cph.noReleaseNeeded = true;
           results.add(cph);
       }
   }

   try {
       ActivityManagerNative.getDefault().publishContentProviders(
           getApplicationThread(), results);
   } catch (RemoteException ex) {
       throw ex.rethrowFromSystemServer();
   }
}
初始化ContentProvider类
private IActivityManager.ContentProviderHolder installProvider(Context context,
            IActivityManager.ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
    
    ...
    Context c = null;
    //反射创建ContentProvider实例
    final java.lang.ClassLoader cl = c.getClassLoader();
    localProvider = (ContentProvider)cl.loadClass(info.name).newInstance();
    provider = localProvider.getIContentProvider();
    
    //调用ContentProvider的attachInfo方法,告诉它它是谁,例如读写权限、是否导出等
    //attachInfo方法中会回调ContentProvider的onCreate()方法
    localProvider.attachInfo(c, info);
    
    //然后将ContentProvider记录存储到ActivityThread类的多个字典属性中
    //final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
    //    = new ArrayMap<ProviderKey, ProviderClientRecord>();
    //final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
    //    = new ArrayMap<IBinder, ProviderRefCount>();
    //final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
    //    = new ArrayMap<IBinder, ProviderClientRecord>();
    //final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
    //        = new ArrayMap<ComponentName, ProviderClientRecord>();
    
    //他们可以按照不同的key值存储对应的ProviderClientRecord
    
    IActivityManager.ContentProviderHolder retHolder;
    
    IBinder jBinder = provider.asBinder();
    if (localProvider != null) {
        ComponentName cname = new ComponentName(info.packageName, info.name);
        ProviderClientRecord pr = mLocalProvidersByName.get(cname);
        if (pr != null) {
            provider = pr.mProvider;
        } else {
            holder = new IActivityManager.ContentProviderHolder(info);
            holder.provider = provider;
            holder.noReleaseNeeded = true;
            pr = installProviderAuthoritiesLocked(provider, localProvider,
                                                 holder);
            mLocalProviders.put(jBinder, pr);
            mLocalProvidersByName.put(cname, pr);
        }
        retHolder = pr.mHolder;
    }
        
    return retHolder;
}
发布给AMS
private void installContentProviders(Context context, 
                                     List<ProviderInfo> providers) {
                                     
    final ArrayList<IActivityManager.ContentProviderHolder> results =
            new ArrayList<IActivityManager.ContentProviderHolder>();                                     

    ...
    try {
        ActivityManagerNative.getDefault().publishContentProviders(
                                    getApplicationThread(), results);
    } catch (RemoteException ex) {
       throw ex.rethrowFromSystemServer();
    }
}

IActivityManager.ContentProviderHolder是有关一个ContentProvider的信息和操作连接的包装类,通过序列化后发送给AMS。

public static class ContentProviderHolder implements Parcelable {
        public final ProviderInfo info;
        public IContentProvider provider;
        public IBinder connection;
        public boolean noReleaseNeeded;
    
}

AMS存储客户端进程发送过来的ContentProvider列表。

public final void publishContentProviders(IApplicationThread caller,
                                List<ContentProviderHolder> providers) {
    synchronized (this) {
        final ProcessRecord r = getRecordForAppLocked(caller);
        final int N = providers.size();
        for (int i = 0; i < N; i++) {
            ContentProviderHolder src = providers.get(i);
            
            //进程信息ProcessRecord中存储的ContentProvider信息是在应用进程启动后,
            //由AMS解析应用组件信息并存储起来的。
            //所以和客户端进程发送过来的ContentProviderHolder是一一对应的
            ContentProviderRecord dst = r.pubProviders.get(src.info.name);
            
            if (dst != null) {
                ComponentName comp = new ComponentName(dst.info.packageName,
                                                       dst.info.name);
                mProviderMap.putProviderByClass(comp, dst);
                String names[] = dst.info.authority.split(";");
                for (int j = 0; j < names.length; j++) {
                    mProviderMap.putProviderByName(names[j], dst);
                }
                
                int launchingCount = mLaunchingProviders.size();
                int j;
                boolean wasInLaunchingProviders = false;
                for (j = 0; j < launchingCount; j++) {
                    if (mLaunchingProviders.get(j) == dst) {
                        mLaunchingProviders.remove(j);
                        wasInLaunchingProviders = true;
                        j--;
                        launchingCount--;
                    }
                }
                //将ContentProvider的连接存储到ContentProviderRecord中
                synchronized (dst) {
                    dst.provider = src.provider;
                    dst.proc = r;
                    dst.notifyAll();
                }
            }
        }
    }
}
通过ContentProvider查询数据
context.getContentResolver().query("查询的ContentProviderUri", "返回的列", "过滤行的条件", "过滤行的参数", "返回行数据的排序方式");

通过上下文获取到ContentResolver实例,该实例的类型是ApplicationContentResolver。是在ContextImpl构造函数中初始化的。

private ContextImpl(ContextImpl container, ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, UserHandle user, 
            int flags,Display display, Configuration overrideConfiguration, 
            int createDisplayWithId) {
     ...
     
     mContentResolver = new ApplicationContentResolver(this, mainThread, user);   
}
//ContentResolver.java

@Override
public final @Nullable Cursor query(
                                final @RequiresPermission.Read @NonNull Uri uri,
                                @Nullable String[] projection, 
                                @Nullable Bundle queryArgs,
                                @Nullable CancellationSignal cancellationSignal) {
    
    //根据Uri向AMS查询ContentProvider的Binder连接
    IContentProvider unstableProvider = acquireUnstableProvider(uri);
    
    //查询数据
    //这里命名为unstableProvider意思是:ContentProvider所处的进程可能被杀死了,导致查询失败
    //因为我们在客户端进程(ActivityThread类)缓存了ContentProvider的Binder连接,并不是每次都想AMS查询。
    try {
        qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, 
                        remoteCancellationSignal);
    } catch (DeadObjectException e) {
        //这里会将ActivityThread中存储的binder连接删除掉
        unstableProviderDied(unstableProvider);
        //如果由于远程服务挂掉了导致查询失败,那么就再次向AMS请求一次ContentProvider
        //的Binder连接,此时AMS会负责将远程服务进程拉起来,从而保证查询成功。
        stableProvider = acquireProvider(uri);
        if (stableProvider == null) {
            return null;
        }
        qCursor = stableProvider.query(mPackageName, uri, projection,
              selection, selectionArgs, sortOrder, remoteCancellationSignal);
    }
    
    //将游标对象封装为CursorWrapperInner返回,它包含了与远程ContentProvider的Binder连接
    final IContentProvider provider = (stableProvider != null) ? stableProvider
          : acquireProvider(uri);
    final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
    stableProvider = null;
    qCursor = null;
    return wrapper;
}
//ActivityThread.java

//获取ContentProvider连接的实现
public final IContentProvider acquireProvider(Context c, String auth, int userId,                               
                                            boolean stable) {
    //先查询本地缓存,如果存在就直接返回
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
    if (provider != null) {
        return provider;
    }    
    
    //向AMS查询
    IActivityManager.ContentProviderHolder holder = null;
    try {
        holder = ActivityManagerNative.getDefault().getContentProvider(
               getApplicationThread(), auth, userId, stable);
    } catch (RemoteException ex) {
       throw ex.rethrowFromSystemServer();
    }
    
    //存储到本地,并增加引用计数
    holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
    return holder.provider;
}

BroadcastReceiver

在Manifest.xml文件中注册

<receiver
  android:name=".test.broadcast.MyTestReceiver"
  android:enabled="true"
  android:exported="true">
  <intent-filter>
      <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
      <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
      <action android:name="android.intent.action.SCREEN_ON" />
      <action android:name="android.intent.action.SCREEN_OFF" />
      <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
      <action android:name="android.intent.action.CONFIGURATION_CHANGED" />
      <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
      <action android:name="android.intent.action.USER_PRESENT" />
  </intent-filter>
</receiver>

在Manifesh.xml文件中注册自定义的BroadcastReceiver,当意图过滤器中的动作发生时,会回调BroadcastReceiver中的onRecevie方法.

public class MyTestReceiver extends BroadcastReceiver {
    private static final String TAG = "MyTestReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null) {
            String action = intent.getAction();
            Log.d(TAG, "onReceive: receive action is " + action);
        }
    }
}

代码中动态注册

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);

registerReceiver(new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
      String action = intent == null ? "" : intent.getAction();
      if (Intent.ACTION_SCREEN_OFF.equalsIgnoreCase(action)) {
          Log.i(TAG, "onReceive: 屏幕关闭");
      }
      context.unregisterReceiver(this);
  }
}, intentFilter);

在Activity上下文中调用registerReceiver方法,动态注册一个广播接收者,同时指定了意图过滤器。
这里要注意注册的BroadcastReceiver最好是静态类,防止内存泄漏。否则要及时取消注册。

原理

注册通知
静态注册

通过PackageManagerService安装应用时,会解析安装包中的Manifest.xml文件,存储解析到Receiver标签对应的广播接收器。

通过Unix Socket接收需要安装的Apk文件
//android/os/FileBridge.java

public class FileBridge extends Thread {
    private static final int MSG_LENGTH = 8;
    private final FileDescriptor mServer = new FileDescriptor();
    private final FileDescriptor mClient = new FileDescriptor();
    
    private FileDescriptor mTarget;

    //构造函数
    //创建Unix Domain Socket的客户端和服务端,然后会将代表客户端的文件描述符发送给客户端进程
    public FileBridge() {
        try {
            Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mServer, mClient);
        } catch (ErrnoException e) {
            throw new RuntimeException("Failed to create bridge");
        }
    }
    
    //mTarget文件描述符用来存储客户端进程发送过来的Apk文件数据
    public void setTargetFile(FileDescriptor target) {
        mTarget = target;
    }

    public FileDescriptor getClientSocket() {
        return mClient;
    }
    
    //这是一个线程,不停监听Socket的Server端
    @Override
    public void run() {
        final byte[] temp = new byte[8192];//读缓冲区
        //读取Socket的Server端,如果没有数据会阻塞
        //每次先读取8字节,前4个字节代表数据类型,后4四个字节代表数据长度
        while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) {
            //按照大端序读取前4字节
            final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN);
            //数据写入,将apk文件数据写入到mTraget代表的文件描述中
            if (cmd == CMD_WRITE) {
                int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);
               while (len > 0) {
                   int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len));
                   if (n == -1) {
                       throw new IOException(
                               "Unexpected EOF; still expected " + len + " bytes");
                   }
                   IoBridge.write(mTarget, temp, 0, n);
                   len -= n;
               }
            //数据同步,并回显给客户端确认
            } else if (cmd == CMD_FSYNC) {
                Os.fsync(mTarget);
                IoBridge.write(mServer, temp, 0, MSG_LENGTH);
            //关闭消息通道,并回显给客户端确认
            } else if (cmd == CMD_CLOSE) {
                Os.fsync(mTarget);
               Os.close(mTarget);
               mClosed = true;
               IoBridge.write(mServer, temp, 0, MSG_LENGTH);
               break;
            }
        }
        
    }
}
验证APK合法性
  1. 包名、版本号
  2. 签名(V2+V1)sudo
  3. 其他应用验证package-verifier
  4. 应用申请的权限,需要用户确认
  5. 拷贝安装包到data/data/{包名}/目录下,并且复制Native库到lib目录下
解析Apk文件
  1. 添加apk文件路径到AssetManager管理中
  2. 解析Manifest.xml文件信息到Package类中,区分是多个apk文件安装,还是单个apk文件安装
  3. 验证该安装包是否只用于测试
  4. 为Package类填充证书和签名信息
  5. 是否覆盖安装,需要验证签名是否一致、包配置是否一致等。还要替换应用资源
//frameworks/base/core/java/android/content/pm/PackageParser.java

private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
    ... 
    
    final int innerDepth = parser.getDepth();
    int type;
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
          && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth))     
          {
         String tagName = parser.getName();
          if (tagName.equals("activity")) {
              Activity a = parseActivity(owner, res, parser, flags, outError, 
                                        false,owner.baseHardwareAccelerated);
              owner.activities.add(a);
          } else if (tagName.equals("receiver")) {
              Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
              owner.receivers.add(a);
        
          } else if (tagName.equals("service")) {
          ...
    }
}

从上面解析过程可以看出,Android系统把Activity和BroadcastReceiver都当做了Activity类型来存储的。
parseActivity方法中,还会继续解析里面的intent-filter标签,以及其action/category/data等子标签。
所有从Manifest.xml文件中解析出来的数据,会存储到Package类中。

 public final static class Package {
    public String packageName;
    public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
    public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
    ...
 }
保存组件信息

将Package类中的四大组件信息以及整个Package信息保存到PackageManagerService中。同时还会保存到Settings类中,Settings类代表了系统的动态设置信息。

//PackageManagerService.java

//系统中所有程序信息
final ArrayMap<String, PackageParser.Package> mPackages =
            new ArrayMap<String, PackageParser.Package>();

// 系统中所有程序的四大组件信息
final ActivityIntentResolver mActivities =
       new ActivityIntentResolver();
final ActivityIntentResolver mReceivers =
       new ActivityIntentResolver();
final ServiceIntentResolver mServices = new ServiceIntentResolver();
final ProviderIntentResolver mProviders = new ProviderIntentResolver();

//扫描包信息
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
            final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
            throws PackageManagerException {
    // Add the new setting to mSettings
    mSettings.insertPackageSettingLPw(pkgSetting, pkg);
    // Add the new setting to mPackages
    mPackages.put(pkg.applicationInfo.packageName, pkg);
    
    
    ...
    
    //保存Package中的BroadcastReceiver信息
    N = pkg.receivers.size();
    r = null;
    for (i=0; i<N; i++) {
        //这里把Receiver当做Activity来处理
        PackageParser.Activity a = pkg.receivers.get(i);
        a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                a.info.processName, pkg.applicationInfo.uid);
        mReceivers.addActivity(a, "receiver");
        if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
            if (r == null) {
            
                r = new StringBuilder(256);
            } else {
                r.append(' ');
            }
            r.append(a.info.name);
        }
    }
}

动态注册
通过ActivityManagerServer注册
//frameworks/base/core/java/android/app/ContextImpl.java

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

我们在Context上下文中调用registerReceiver(BroadcastReceiver, IntentFilter)方法动态注册一个广播时,会先保存到ActivityManagerServer中。

//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
    
    ...
    
    //如果调用者传入BroadcastReceiver是null,代表想要获得一个粘性广播
    //粘性广播直接通过registerReceiver方法的返回值返回给调用者。
    Intent sticky = allSticky != null ? allSticky.get(0) : null;
    if (receiver == null) {
      return sticky;
    }

    //将BroadcastReceiver存储到一个HashMap中
    ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
    if (rl == null) {
        //ReceiverList是一个ArrayList子类,用来存储BroadcastReceiver和对应的过滤器
    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
       userId, receiver);
        if (rl.app != null) {
            rl.app.receivers.add(rl);
        } else {
            try {
               receiver.asBinder().linkToDeath(rl, 0);
            } catch (RemoteException e) {
               return sticky;
            }
            rl.linkedToDeath = true;
        }
        mRegisteredReceivers.put(receiver.asBinder(), rl);
    }
    //保存过滤器到IntentResolver中
    BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
    rl.add(bf);  
    mReceiverResolver.addFilter(bf);
}
发送、接收通知

当应用程序或系统程序发出一个广播时,会调用到ActivityManagerService中,ActivityManagerService会从自己保存的BroadcastReceiver列表和PackageManagerService保存的BroadcastReceiver列表中找出符合意图过滤器的广播接收者,然后向其发送广播。

//ActivityManagerService.java

final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
            
    //1. 默认不给已经stopped停止的应用发送广播
    
    //2. 如果没有完成开机操作,例如正在升级系统,只允许注册广播,不能发送
    
    //3. 如果广播指定的目的用户,那么这个用户必须处于运行状态
    
    //4. 验证是否是系统应用发出的受保护的广播。受保护的广播只能由系统应用发出。
    //系统应用的判断标准是用户id:ROOT_UID/SYSTEM_UID/PHONE_UID/BLUETOOTH_UID/NFC_UID,或者是常驻应用
    
    //5. 窗口小部件的配置和更新广播也不能由应用发出。由于历史原因,它们并不是受保护的广播,需要单独判断
    
    //6. 对特殊广播的处理:由PackageManager发出的应用被删除或变更的广播,
    //需要ActivityManagerService作出对应的操作,例如从最近使用应用中删除它们的Activity。
    //特殊类型的广播处理完成后,就直接返回了
    
    //7. 从PackageManagerService中查询符合过滤器条件的广播接受者List<ResolveInfo>,这里就是应用安装时,解析出来的静态注册的广播接受者。
     List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                        .queryIntentReceivers(intent, resolvedType, pmFlags,
                                                 user).getList();
    
    //8. 从ActivityManagerService的ContentResolver中查询符合条件的广播接受者,这里代表通过代码动态注册的广播接受者
     registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false, userId);
   
    
    //9. 将两个列表按照优先级合并成一个列表
    
    //10. 构造一个BroadcastRecord,添加到队列BroadcastQueue中,然后开始调度执行。
}

//BroasdcastQueue.java

public final class BroadcastQueue {

    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();

    //11. BroadcastQueue中的广播被分为并发广播和顺序广播。并发广播会立即被执行,而不需要等待其他的广播执行完毕。顺序广播则会逐一执行。
    //我们在注册广播时可以指定是否是顺序广播,或者粘性广播被认为是并发广播
    
    
    final void processNextBroadcast(boolean fromMsg) {
        BroadcastRecord r;
        
        //12. 开始处理列表中的广播。先处理并发广播
        
        //13. 如果处理广播的进程不存在,还需要等待进程的创建
        
        //14. 处理动态注册的广播,在BroadcastQueue中以BroadcastFilter形式存储
        performReceiveLocked(filter.receiverList.app, 
                            filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
                        
        //15. 处理静态注册的广播,如果需要,还要提前唤起对应进程。如果目标进程开始运行后,再分发对应的广播
        String targetProcess = info.activityInfo.processName;
        ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
                        info.activityInfo.applicationInfo.uid, false);
        app.addPackage(info.activityInfo.packageName,
                            info.activityInfo.applicationInfo.versionCode, 
                            mService.mProcessStats);
        processCurBroadcastLocked(r, app);
        
        
    }
}

performReceiveLocked方法代码如下:

void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
    if (app != null) {
        app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser,
                             app.repProcState);
    } else {
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
    }
}

processCurBroadcastLocked方法如下:

private final void processCurBroadcastLocked(BroadcastRecord r,
            ProcessRecord app) throws RemoteException {
            
    app.thread.scheduleReceiver(new Intent(r.intent), 
                            r.curReceiver,
                            mService.compatibilityInfoForPackageLocked(
                            r.curReceiver.applicationInfo),
                            r.resultCode, 
                            r.resultData, 
                            r.resultExtras, 
                            r.ordered, 
                            r.userId,
                            app.repProcState);
}
取消注册
取消动态注册的广播接收器

前面说过动态注册的广播接收器是存储在ActivityManagerService中的,那么取消注册的时候,也是通过跨进程通信,告知ActivityManagerService移除指定的广播接收器。

//ActivityManagerService.java

final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

public void unregisterReceiver(IIntentReceiver receiver) {
   final long origId = Binder.clearCallingIdentity();
   try {
       boolean doTrim = false;

       synchronized(this) {
           ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
           if (rl != null) {
               final BroadcastRecord r = rl.curBroadcast;
               if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) {
                   final boolean doNext = r.queue.finishReceiverLocked(
                           r, r.resultCode, r.resultData, r.resultExtras,
                           r.resultAbort, false);
                   if (doNext) {
                       doTrim = true;
                       r.queue.processNextBroadcast(false);
                   }
               }

               if (rl.app != null) {
                   rl.app.receivers.remove(rl);
               }
               //从HashMap中移除BroadcastReceiver
               //从IntentResolver中移除对应的过滤器
               removeReceiverLocked(rl);
               if (rl.linkedToDeath) {
                   rl.linkedToDeath = false;
                   rl.receiver.asBinder().unlinkToDeath(rl, 0);
               }
           }
       }

       // If we actually concluded any broadcasts, we might now be able
       // to trim the recipients' apps from our working set
       if (doTrim) {
           trimApplications();
           return;
       }

   } finally {
       Binder.restoreCallingIdentity(origId);
   }
}


void removeReceiverLocked(ReceiverList rl) {
   mRegisteredReceivers.remove(rl.receiver.asBinder());
   for (int i = rl.size() - 1; i >= 0; i--) {
       mReceiverResolver.removeFilter(rl.get(i));
   }
}
取消静态注册的广播接收器

静态注册的广播接收者理论上是无法取消注册的,因为它们是写死在Manifest.xml文件中,并在应用安装时就被记录到PackageManagerService中的,并且PackageManagerService类并没有提供移除Receiver信息的接口。

那么静态注册的广播接收器就不能取消了么?
当然不是,这里我们可以采用迂回的方式达到目的。
在从PackageManagerService中查询符合条件的广播接收器列表时,IntentResolver会检查每个过滤器对应的BroadcastReceiver是否被禁用了,如果被禁用了就会忽略掉这个BroadcastReceiver,从而达到和取消注册同样的效果。

下面是禁用或启动某个组件的代码:

//禁用xxx.class代表的组件,如果是广播接收器,则不会再接收到广播
ComponentName componentName = new ComponentName(this, xxx.class);
getPackageManager().setComponentEnabledSetting(componentName,   
                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 
                                PackageManager.DONT_KILL_APP);

//启用xxx.class代表的组件
ComponentName componentName = new ComponentName(this, xxx.class);
getPackageManager().setComponentEnabledSetting(componentName, 
                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 
                        PackageManager.DONT_KILL_APP);

当我们通过PackageManagerService禁用某个组件时,PackageManagerService做了两件事:

  1. 前面在静态注册流程中提到,从Manifest.xml解析出来的组件也会存储到Setting中一份,标识了组件的状态。所以第一个要先修改Setting中的组件状态。如下面代码所示:
//PackageManagerService.java

private void setEnabledSetting(final String packageName, String className, int newState,
            final int flags, int userId, String callingPackage) {
    PackageSetting pkgSetting;
    pkgSetting = mSettings.mPackages.get(packageName);
    pkgSetting.setEnabled(newState, userId, callingPackage);
}

将某个组件的状态改为禁用后,当再次向PackageManagerService查询静态注册的组件时就会把禁用掉的组件过滤掉,不会返回给ActivityManagerService。

//PackageManagerService.java

//ActivityIntentResolver类的方法
//根据ActivityIntentInfo创建一个ResolveInfo
@Override
protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
      int match, int userId) {
      
      //向Setting类查询对应的组件是否被启用了
      if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {
           return null;
       }
}
  1. 第二件事会调用通过ActivityManagerService发送一个Intent.ACTION_PACKAGE_CHANGED类型的广播,告知ActivityManagerService有个组件被禁用了,如果有正在排队发送的广播需要移除掉。

这个流程和普通应用发送广播的流程是一样的,区别是ActivityManagerService在检查到此类型的广播时,会自己处理掉,而不会真正的发送出去,为你Intent.ACTION_PACKAGE_CHANGED广播属于受保护的广播,只能系统代码能发送。

ActivityManagerService的处理逻辑如下:

//ActivityManagerService.java

private void cleanupDisabledPackageComponentsLocked(
            String packageName, int userId, boolean killProcess, String[] changedClasses) {
        
    //1. 遍历禁用的组件,从PackageManagerService中查询对应组件是否已经被禁用
    //找出还没有被禁用的组件,如果已经禁用了就不管了
    try {
          enabled = pm.getComponentEnabledSetting(
                  new ComponentName(packageName, changedClass),
                  (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM);
      } catch (Exception e) {
          // As above, probably racing with uninstall.
          return;
      }
      if (enabled != PackageManager.COMPONENT_ENABLED_STATE_ENABLED
              && enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
          if (disabledClasses == null) {
              disabledClasses = new ArraySet<>(changedClasses.length);
          }
          //disabledClasses代表了实际将要被禁用的组件
          disabledClasses.add(changedClass);
      }
      

  //遍历ActivityManagerService存储的广播接收器,查看是否有需要禁用的
   for (int i = mBroadcastQueues.length - 1; i >= 0; i--) {
       mBroadcastQueues[i].cleanupDisabledPackageReceiversLocked(
               packageName, disabledClasses, userId, true);
   }
               
}

通过以上两个步骤就实现了禁用静态注册的广播接收器的目的。

与LocalBroadcastReceiver区别

LocalBroadcastReceiver就比较简单了,就是一个单例类+消息转发。不需要与ActivityManagerService或PackageManagerService服务进行跨进程通信。
LocalBroadcastReceiver是线程安全的,注册或发送广播时都是用Synchronized关键字包裹起来。

获取LocalBroadcastReceiver单例
@NonNull
public static LocalBroadcastManager getInstance(@NonNull Context context) {
   synchronized (mLock) {
       if (mInstance == null) {
           mInstance = new LocalBroadcastManager(context.getApplicationContext());
       }
       return mInstance;
   }
}

private LocalBroadcastManager(Context context) {
   mAppContext = context;
   mHandler = new Handler(context.getMainLooper()) {

       @Override
       public void handleMessage(Message msg) {
           switch (msg.what) {
               case MSG_EXEC_PENDING_BROADCASTS:
                   executePendingBroadcasts();
                   break;
               default:
                   super.handleMessage(msg);
           }
       }
   };
}

在构造LocalBroadcastReceiver实例时,会创建一个Handler,用于在主线程发送通知。

注册广播
private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceivers
            = new HashMap<>();
private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();

public void registerReceiver(@NonNull BroadcastReceiver receiver,
            @NonNull IntentFilter filter) {
   synchronized (mReceivers) {
        //使用ReceiverRecord记录一个BroadcastReceiver和IntentFilter
        //使用HashMap记录一个BroadcastReceiver与多个ReceiverRecord关系
        //因为对同一个BroadcastReceiver允许注册多次
       ReceiverRecord entry = new ReceiverRecord(filter, receiver);
       ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
       if (filters == null) {
           filters = new ArrayList<>(1);
           mReceivers.put(receiver, filters);
       }
       filters.add(entry);
       for (int i=0; i<filter.countActions(); i++) {
           String action = filter.getAction(i);
        //使用HashMap记录每个Action和多个ReceiverRecord的关系
        //便于发送广播时查找对应的Receiver
           ArrayList<ReceiverRecord> entries = mActions.get(action);
           if (entries == null) {
               entries = new ArrayList<ReceiverRecord>(1);
               mActions.put(action, entries);
           }
           entries.add(entry);
       }
   }
}
发送广播
在主线程接收广播
private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>();

public boolean sendBroadcast(@NonNull Intent intent) {
    
    ...
    
    //找出接受者,存储到列表mPendingBroadcasts中,等待被发送
    mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
    //向主线程发送一个消息,开始分发mPendingBroadcasts中的广播
    if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
        mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
    }
}
在当前调用线程接收广播
public void sendBroadcastSync(@NonNull Intent intent) {
   if (sendBroadcast(intent)) {
        //找到符合条件的接受者后,立即在当前线程去执行分发逻辑,而不等待主线程分发
        //也就是此方法会BroadcastReceiver的onReceive方法执行后,才会返回
       executePendingBroadcasts();
   }
}
  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android Jetpack是Google提供的一套用于加速Android应用开发的工具包,其包括了许多架构组件,其之一就是ViewModel。 ViewModel是一种设计模式,用于保存和管理与UI相关的数据。在传统的Android开发,当屏幕旋转或者因为其他原因导致Activity或Fragment重建时,之前保存的临时数据就会丢失。而ViewModel的出现解决了这个问题。 ViewModel的主要作用是将数据与UI组件分离。它的工作方式是创建一个ViewModel类,并在其保存需要与UI组件交互的数据。这样,当屏幕旋转或重建时,ViewModel实例不会销毁,数据也会得到保留。然后,在Activity或Fragment,通过获取ViewModel实例,可以轻松地访问这些数据。 使用ViewModel的好处有很多。首先,它可以避免内存泄漏,因为ViewModel的生命周期与Activity或Fragment无关。其次,它可以节省资源,因为当Activity或Fragment销毁时,ViewModel实例可以被系统缓存起来,下次再创建时可以直接返回该实例。另外,由于ViewModel保存了与UI相关的数据,可以减少因为屏幕旋转导致的数据重复加载的问题。 在使用ViewModel时,你可以选择使用Android Jetpack的其他架构组件来进一步提高开发效率,比如通过LiveData实现数据的观察和通知,或者通过DataBinding来实现UI与数据的自动绑定。 总之,ViewModel是Android Jetpack非常重要的一个架构组件,它的出现实现了数据与UI的解耦,提高了开发效率,并且解决了数据丢失的问题。希望通过这篇文档的详解,你对ViewModel有了更深入的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值