【Android源码】Intent 源码分析

作者: 指间沙似流年 | 来源:发表于2017-05-30 09:30 被阅读410次

    在Android中,我们经常需要使用到Intent类,它用于跳转Activity、启动Service、发布广播等功能,它是系统各组件之间的纽带,也可以通过Intent传递数据,因为有Intent才使得Android的组件耦合度降低。

    原型模式

    首先我们跳转到Intent.java:

    public class Intent implements Parcelable, Cloneable {
    }
    

    我们可以发现Intent实现了Cloneable接口,所以我们可以得出一个结论,Intent使用了原型设计模式,(原型设计模式介绍参考:点击此处)我们搜索clone()方法:

    @Override
    public Object clone() {
       return new Intent(this);
    }
    
    public Intent(Intent o) {
       this.mAction = o.mAction;
       this.mData = o.mData;
       this.mType = o.mType;
       this.mPackage = o.mPackage;
       this.mComponent = o.mComponent;
       this.mFlags = o.mFlags;
       this.mContentUserHint = o.mContentUserHint;
       if (o.mCategories != null) {
           this.mCategories = new ArraySet<String>(o.mCategories);
       }
       if (o.mExtras != null) {
           this.mExtras = new Bundle(o.mExtras);
       }
       if (o.mSourceBounds != null) {
           this.mSourceBounds = new Rect(o.mSourceBounds);
       }
       if (o.mSelector != null) {
           this.mSelector = new Intent(o.mSelector);
       }
       if (o.mClipData != null) {
           this.mClipData = new ClipData(o.mClipData);
       }
    }
    

    Intent如何工作

    Intent在使用的时候,可以通过添加flag、category还有需要跳转的对象等来实现功能,那么Intent是如何通过查找并匹配所需要跳转的Activity呢?

    1. app信息表的构建

      参见PackageManagerService 浅析

    2. 匹配

      当app信息表被构建好之后,Intent就可以通过信息表来匹配。

      我们以启动某个具体的Activity来分析,首先我们启动的代码是这样的:

      // 显式Intent
      Intent intent = new Intent(this, SecondActivity.class);
      startActivity(intent);
      
      // 隐式Intent
      Intent intent = new Intent(Intent.ACTION_SENDTO);
      startActivity(intent);
      

      startActivity方法,通过一系列的调用:

      @Override
      public void startActivity(Intent intent) {
         this.startActivity(intent, null);
      }
      @Override
      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) {
              // 启动Activity
             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());
             }
             cancelInputsAndStartExitTransition(options);
         } else {
         }
      }
      

      最终调用的是startActivityForResult方法,在这个方法中直接调用execStartActivity方法启动Activity:

      public ActivityResult execStartActivity(
             Context who, IBinder contextThread, IBinder token, Activity target,
             Intent intent, int requestCode, Bundle options) {
         IApplicationThread whoThread = (IApplicationThread) contextThread;
         Uri referrer = target != null ? target.onProvideReferrer() : null;
         try {
              // 将Intent数据添加到剪切板上
             intent.migrateExtraStreamToClipData();
              // 准备离开当前进程
             intent.prepareToLeaveProcess(who);
              // 调用ActivityManagerService的startActivity方法
             int result = ActivityManagerNative.getDefault()
                 .startActivity(whoThread, who.getBasePackageName(), intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
                         token, target != null ? target.mEmbeddedID : null,
                         requestCode, 0, null, options);
              // 检查并回调给调用者
             checkStartActivityResult(result, intent);
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
         }
         return null;
      }
      

      execStartActivity方法里面其实就是调用了ActivityManagerService的startActivity方法:

      final int startActivity(Intent intent, ActivityStackSupervisor.ActivityContainer container) {
          enforceNotIsolatedCaller("ActivityContainer.startActivity");
          final int userId = mUserController.handleIncomingUser(Binder.getCallingPid(),
                  Binder.getCallingUid(), mStackSupervisor.mCurrentUser, false,
                  ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
      
          // TODO: Switch to user app stacks here.
          String mimeType = intent.getType();
          final Uri data = intent.getData();
          if (mimeType == null && data != null && "content".equals(data.getScheme())) {
              mimeType = getProviderMimeType(data, userId);
          }
          container.checkEmbeddedAllowedInner(userId, intent, mimeType);
      
          intent.addFlags(FORCE_NEW_TASK_FLAGS);
          return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null,
                  null, 0, 0, null, null, null, null, false, userId, container, null);
      }
      

      这个方法会调用ActivityStarter的startActivityMayWait方法,这个方法中又会调用ActivityStackSupervisor.resolveIntent方法,而这个方法就是调用的PMS的resolveIntent方法:

      // ActivityStackSupervisor.java
      ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
         try {
             return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
                     PackageManager.MATCH_DEFAULT_ONLY | flags
                     | ActivityManagerService.STOCK_PM_FLAGS, userId);
         } catch (RemoteException e) {
         }
         return null;
      }   
      
      // PackageManagerService.java
      @Override
      public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
      
             if (!sUserManager.exists(userId)) return null;
             flags = updateFlagsForResolve(flags, userId, intent);
             enforceCrossUserPermission(Binder.getCallingUid(), userId,
                     false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
      
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
             // 获取列表
             final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                     flags, userId);
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                  // 通过列表选择出最合适的info对象
             final ResolveInfo bestChoice =
                     chooseBestActivity(intent, resolvedType, flags, query, userId);
      
             if (isEphemeralAllowed(intent, query, userId)) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
                 final EphemeralResolveInfo ai =
                         getEphemeralResolveInfo(intent, resolvedType, userId);
                 if (ai != null) {
                     if (DEBUG_EPHEMERAL) {
                         Slog.v(TAG, "Returning an EphemeralResolveInfo");
                     }
                     bestChoice.ephemeralInstaller = mEphemeralInstallerInfo;
                     bestChoice.ephemeralResolveInfo = ai;
                 }
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
             return bestChoice;
         } finally {
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
      }   
      

      queryIntentActivitiesInternal方法返回的结果就是符合intent的ActivityInfo列表:

      private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, int userId) {
         // 获取Intent的Component对象
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
                 intent = intent.getSelector();
                 comp = intent.getComponent();
             }
         }
          // 不为空,是显式Intent,直接获取到ActivityInfo返回
         if (comp != null) {
             final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
             final ActivityInfo ai = getActivityInfo(comp, flags, userId);
             if (ai != null) {
                 final ResolveInfo ri = new ResolveInfo();
                 ri.activityInfo = ai;
                 list.add(ri);
             }
             return list;
         }
          
         // 为空,是隐式Intent
         synchronized (mPackages) {
             final String pkgName = intent.getPackage();
             if (pkgName == null) {
                 // 代码省略
                 return result;
             }
             // 通过包名获取到Package对象
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
                  // 在获取到ActivityInfo对象
                 return filterIfNotSystemUser(
                         mActivities.queryIntentForPackage(
                                 intent, resolvedType, flags, pkg.activities, userId),
                         userId);
             }
             return new ArrayList<ResolveInfo>();
         }
      }   
      

      上面这个方法就是Intent获取到ActivityInfo的核心,它的大致过程如下:

      1. 首先获取Intent的Component对象,如果不为空,说明指定了Componet,那么就直接通过Componet找到ActivityInfo列表,并且这个列表size为1,所以这个ActivityInfo就是指定需要跳转的组件。
      2. 如果没有指定Component,那就是隐式Intent调用,接着获取Intent传递的需要跳转的包名。
      3. 如果包名为空,则会通过ActivityIntentResolver等进行模糊匹配,比如根据Action、Category等。
      4. 如果包名不为空,则直接根据包名来获取到对应的ActivityInfo对象,而mActivities就是PMS存储的activity信息表。

    相关文章

      网友评论

        本文标题:【Android源码】Intent 源码分析

        本文链接:https://www.haomeiwen.com/subject/dzzlfxtx.html