微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

android5系统源码分析点击app图标启动过程

从点击桌面app图片开始看,代码如下:

//源码路径D:\dow\android-5.1.1_r1\android-5.1.1_r1\packages\apps\Launcher2\src\com\android\launcher2\Launcher.java
    public void onClick(View v) {
        // Make sure that rogue clicks don‘t get through while allapps is launching,or after the
        // view has detached (it‘s possible for this to happen if the view is removed mid touch).
        if (v.getwindowToken() == null) {
            return;
        }

        if (!mWorkspace.isFinishedSwitchingState()) {
            return;
        }

        Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
            // Open shortcut
            final Intent intent = ((ShortcutInfo) tag).intent;
            int[] pos = new int[2];
            v.getLocationOnScreen(pos);
            intent.setSourceBounds(new Rect(pos[0],pos[1],pos[0] + v.getWidth(),pos[1] + v.getHeight()));

            boolean success = startActivitySafely(v,intent,tag);

            if (success && v instanceof BubbleTextView) {
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStaypressed(true);
            }
        } else if (tag instanceof FolderInfo) {
            if (v instanceof FolderIcon) {
                FolderIcon fi = (FolderIcon) v;
                handleFolderClick(fi);
            }
        } else if (v == mAllAppsButton) {
            if (isAllAppsVisible()) {
                showWorkspace(true);
            } else {
                onClickAllAppsButton(v);
            }
        }
    }

android5系统源码分析点击app图标启动过程


然后就是调用startActivitySafely方法代码如下:

boolean startActivitySafely(View v,Intent intent,Object tag) {
        boolean success = false;
        try {
            success = startActivity(v,tag);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this,R.string.activity_not_found,Toast.LENGTH_SHORT).show();
            Log.e(TAG,"Unable to launch. tag=" + tag + " intent=" + intent,e);
        }
        return success;
    }

android5系统源码分析点击app图标启动过程


调用startActivity方法代码如下 :

boolean startActivity(View v,Object tag) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        try {
            // Only launch using the new animation if the shortcut has not opted out (this is a
            // private contract between launcher and may be ignored in the future).
            boolean useLaunchAnimation = (v != null) &&
                    !intent.hasExtra(INTENT_EXTRA_IGnorE_LAUNCH_ANIMATION);
            UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
            LauncherApps launcherApps = (LauncherApps)
                    this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
            if (useLaunchAnimation) {
                ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v,v.getMeasuredWidth(),v.getMeasuredHeight());
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                    // Could be launching some bookkeeping activity
                    startActivity(intent,opts.toBundle());
                } else {
                    launcherApps.startMainActivity(intent.getComponent(),user,intent.getSourceBounds(),opts.toBundle());
                }
            } else {
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                    startActivity(intent);
                } else {
                    launcherApps.startMainActivity(intent.getComponent(),null);
                }
            }
            return true;
        } catch (SecurityException e) {
            Toast.makeText(this,"Launcher does not have the permission to launch " + intent +
                    ". Make sure to create a MAIN intent-filter for the corresponding activity " +
                    "or use the exported attribute for this activity. "
                    + "tag="+ tag + " intent=" + intent,e);
        }
        return false;
    }

android5系统源码分析点击app图标启动过程


然后调用activity.java中的startActivity方法代码如下:

//路径:D:\dow\android-5.1.1_r1\android-5.1.1_r1\frameworks\base\core\java\android\app\Activity.java
    @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);
        }
    }

android5系统源码分析点击app图标启动过程


然后调用startActivityForResult方法代码如下:

public void startActivityForResult(Intent intent,int requestCode,@Nullable Bundle options) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this,mMainThread.getApplicationThread(),mToken,this,requestCode,options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken,mEmbeddedID,ar.getResultCode(),ar.getResultData());
            }
            if (requestCode >= 0) {
                // If this start is requesting a result,we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time,to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished,no matter what happens to it.
                mStartedActivity = true;
            }

            final View decor = mWindow != null ? mWindow.peekDecorView() : null;
            if (decor != null) {
                decor.cancelPendingInputEvents();
            }
            // Todo Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this,options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this,requestCode);
            }
        }
        if (options != null && !isTopOfTask()) {
            mActivityTransitionState.startExitOutTransition(this,options);
        }
    }

android5系统源码分析点击app图标启动过程


然后调用Instrumentation.java的execStartActivity方法返回ActivityManagerService的远程接口,代码如下:

public ActivityResult execStartActivity(
            Context who,IBinder contextThread,IBinder token,Activity target,Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    if (am.match(who,null,intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData();
            intent.preparetoLeaveProcess();
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread,who.getBasePackageName(),intent.resolveTypeIfNeeded(who.getContentResolver()),token,target != null ? target.mEmbeddedID : null,options);
            checkStartActivityResult(result,intent);
        } catch (remoteexception e) {
        }
        return null;
    }

调用ActivityManagerNative.java的getDefault()方法代码如下:

路径:D:\dow\android-5.1.1_r1\android-5.1.1_r1\frameworks\base\core\java\android\app\ActivityManagerNative.java

    static public IActivityManager getDefault() {
        return gDefault.get();
    }

android5系统源码分析点击app图标启动过程

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager","default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager","default service = " + am);
            }
            return am;
        }
    };

android5系统源码分析点击app图标启动过程


可以看到 它其它是前面说的返回ActivityManagerService调用他的startActivity:

IBinder b = ServiceManager.getService("activity");
 int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread,options);

现在我们去看这个服务的源码:

路径:D:\dow\android-5.1.1_r1\android-5.1.1_r1\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java
    public final int startActivity(IApplicationThread caller,String callingPackage,String resolvedType,IBinder resultTo,String resultWho,int startFlags,ProfilerInfo profilerInfo,Bundle options) {
        return startActivityAsUser(caller,callingPackage,resolvedType,resultTo,resultWho,startFlags,profilerInfo,options,UserHandle.getCallingUserId());
    }

android5系统源码分析点击app图标启动过程


调用startActivityAsUser继续调用startActivityMayWait:

public final int startActivityAsUser(IApplicationThread caller,Bundle options,int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(),Binder.getCallingUid(),userId,false,ALLOW_FULL_ONLY,"startActivity",null);
        // Todo: Switch to user app stacks here.
        return mStackSupervisor.startActivityMayWait(caller,null);
    }

android5系统源码分析点击app图标启动过程

//D:\dow\android-5.1.1_r1\android-5.1.1_r1\frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
    final int startActivityMayWait(IApplicationThread caller,int callingUid,IVoiceInteractionSession voiceSession,IVoiceInteractor voiceInteractor,WaitResult outResult,Configuration config,int userId,IActivityContainer iContainer,TaskRecord inTask) {
        // Refuse possible leaked file descriptors
        if (intent != null && intent.hasFileDescriptors()) {
            throw new IllegalArgumentException("File descriptors passed in Intent");
        }
        boolean componentSpecified = intent.getComponent() != null;

android5系统源码分析点击app图标启动过程


解析Intent然后进入startActivityLocked方法检测机制:

//D:\dow\android-5.1.1_r1\android-5.1.1_r1\frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
                            ResolveInfo rInfo =
                                AppGlobals.getPackageManager().resolveIntent(
                                        intent,PackageManager.MATCH_DEFAULT_ONLY
                                        | ActivityManagerService.STOCK_PM_FLAGS,userId);
                            aInfo = rInfo != null ? rInfo.activityInfo : null;
                            aInfo = mService.getActivityInfoForUser(aInfo,userId);
                        } catch (remoteexception e) {
                            aInfo = null;
                        }
                    }
                }
            }

            int res = startActivityLocked(caller,aInfo,voiceSession,voiceInteractor,callingPid,callingUid,realCallingPid,realCallingUid,componentSpecified,container,inTask);

            Binder.restoreCallingIdentity(origId);

android5系统源码分析点击app图标启动过程


创建即将要启动的Activity相关信息:

//D:\dow\android-5.1.1_r1\android-5.1.1_r1\frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java
    final int startActivityLocked(IApplicationThread caller,ActivityInfo aInfo,int callingPid,int realCallingPid,int realCallingUid,boolean componentSpecified,ActivityRecord[] outActivity,ActivityContainer container,TaskRecord inTask) {
        int err = ActivityManager.START_SUCCESS;

        Proce***ecord callerApp = null;
        if (caller != null) {
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                callingPid = callerApp.pid;
    .............
            ActivityRecord r = new ActivityRecord(mService,callerApp,mService.mConfiguration,resultRecord,options);
        if (outActivity != null) {
            outActivity[0] = r;
        }

        final ActivityStack stack = getFocusedStack();
        if (voiceSession == null && (stack.mResumedActivity == null
                || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
            if (!mService.checkAppSwitchAllowedLocked(callingPid,"Activity start")) {
                PendingActivityLaunch pal =
                        new PendingActivityLaunch(r,sourceRecord,stack);
                mPendingActivityLaunches.add(pal);
                ActivityOptions.abort(options);
                return ActivityManager.START_SWITCHES_CANCELED;
            }
        }

android5系统源码分析点击app图标启动过程


android5系统源码分析点击app图标启动过程


继续调用startActivityUncheckedLocked方法

mService.mDidAppSwitch = true;
        }

        doPendingActivityLaunchesLocked(false);

        err = startActivityUncheckedLocked(r,true,inTask);

android5系统源码分析点击app图标启动过程


然后通知WindowManagerService服务后判断参数doResume的值是为true。

// sure we have correctly resumed the top activity.
                        if (doResume) {
                            resumetopActivitiesLocked(targetStack,options);

                            // Make sure to notify Keyguard as well if we are not running an app
                            // transition later.
                            if (!movedToFront) {
                                notifyActivityDrawnForKeyguard();
                            }
                        } else {
                            ActivityOptions.abort(options);
                        }
                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                    }
                    if ((launchFl

android5系统源码分析点击app图标启动过程

后面就把它放到 Activity栈顶层,然后交给Activity调度器显示

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐