Activityの起動プロセスのstartActivityソース解析

57756 ワード

転載は出典を明記してください.http://blog.csdn.net/guangzq/article/details/74295752祝起光のブログより
一.概要
本明細書ではapi 24 startActivity簡略化版フローチャートActivity的启动过程之startActivity源码解析_第1张图片に基づく
二.ソース解析
startActivityを入口として
方法:Activity->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) {
    startActivityForResult(intent, requestCode, null);                                  
}                                                                                                                                                                                                    

最終的な方法はすべて呼び出したstartActivity ForResultです.続けてみてください.
方法:Acticity->startActivity ForResult
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,                                                 
                                   @Nullable Bundle options) {                                                                         
    //mParent   ActivityGroup,  ActivityGroup   ,     Activity                                                                         
    if (mParent == null) {                                                                                                             
        //      Activity,      mMainThread.getApplicationThread()。Instrumentation      system application    。     activity
        //      Instrumentation                         
        Instrumentation.ActivityResult ar =                                                                                            
                mInstrumentation.execStartActivity(                                                                                    
                        this, mMainThread.getApplicationThread(), mToken, this,                                                        
                        intent, requestCode, options);                                                                                 
        if (ar != null) {                                                                                                              
            //    onActivityResult                                                                                                     
            mMainThread.sendActivityResult(                                                                                            
                    mToken, mEmbeddedID, requestCode, 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.                                                                     
            //      : result       acitity  , onCreate  onResume       acticity  ,                                                     
            mStartedActivity = true;                                                                                                   
        }                                                                                                                              
        cancelInputsAndStartExitTransition(options);                                                                                   
        // TODO Consider clearing/flushing other event sources and events for child windows.                                           
    } else {                                                                                                                           
        //ActitityGroup   Activity     ,                                                                                               
        if (options != null) {                                                                                                         
            mParent.startActivityFromChild(this, intent, requestCode, options);                                                        
        } else {                                                                                                                       
            // Note we want to go through this method for compatibility with                                                           
            // existing applications that may have overridden it.                                                                      
            mParent.startActivityFromChild(this, intent, requestCode);                                                                 
        }                                                                                                                              
    }                                                                                                                                  
}

本当にActivityを開くのはexecStartActivityで実現されている以上、execStartActivityを見てみましょう.
方法:Instrumentation->execStartActivity
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;                
    if (referrer != null) {                                                           
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);                             
    }                                                                                 
    if (mActivityMonitors != null) {                                                  
        synchronized (mSync) {                                                        
            //  ActivityMonitor,       Activity                                       
            final int N = mActivityMonitors.size();                                   
            for (int i=0; ifinal ActivityMonitor am = mActivityMonitors.get(i);                  
                if (am.match(who, null, intent)) {                                    
                    am.mHits++;                                                       
                    //  //  monitor  activity  ,     Activity       return                                         
                    if (am.isBlocking()) {                                            
                        return requestCode >= 0 ? am.getResult() : null;              
                    }                                                                 
                    //                                                                
                    break;                                                            
                }                                                                     
            }                                                                         
        }                                                                             
    }                                                                                 
    try {                                                                             
        intent.migrateExtraStreamToClipData();                                        
        intent.prepareToLeaveProcess(who);                                            
        //   startActivity   ,       whoThread scheduleLaunchActivity                 
        int result = ActivityManagerNative.getDefault()                               
            .startActivity(whoThread, who.getBasePackageName(), intent,               
                    intent.resolveTypeIfNeeded(who.getContentResolver()),             
                    token, target != null ? target.mEmbeddedID : null,                
                    requestCode, 0, null, options);                                   
        //      Activity     ,     Activity  AndroidManifest  ,                       
        //    “...have you declared this activity in your AndroidManifest.xml?”       
        checkStartActivityResult(result, intent);                                     
    } catch (RemoteException e) {                                                     
        throw new RuntimeException("Failure from system", e);                         
    }                                                                                 
    return null;                                                                      
}                                                                                     

補足checkStartActivity Resultメソッドは,内部実装が様々な場合に投げ出す必要がある異常情報である.
public static void checkStartActivityResult(int res, Object intent) {                       
    if (res >= ActivityManager.START_SUCCESS) {                                             
        return;                                                                             
    }                                                                                       

    switch (res) {                                                                          
        case ActivityManager.START_INTENT_NOT_RESOLVED:                                     
        case ActivityManager.START_CLASS_NOT_FOUND:                                         
            if (intent instanceof Intent && ((Intent)intent).getComponent() != null)        
                throw new ActivityNotFoundException(                                        
                        "Unable to find explicit activity class "                           
                        + ((Intent)intent).getComponent().toShortString()                   
                        + "; have you declared this activity in your AndroidManifest.xml?");
            throw new ActivityNotFoundException(                                            
                    "No Activity found to handle " + intent);                               
        case ActivityManager.START_PERMISSION_DENIED:                                       
            throw new SecurityException("Not allowed to start activity "                    
                    + intent);                                                              
        case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:                            
            throw new AndroidRuntimeException(                                              
                    "FORWARD_RESULT_FLAG used while also requesting a result");             
        case ActivityManager.START_NOT_ACTIVITY:                                            
            throw new IllegalArgumentException(                                             
                    "PendingIntent is not an activity");                                    
        case ActivityManager.START_NOT_VOICE_COMPATIBLE:                                    
            throw new SecurityException(                                                    
                    "Starting under voice control not allowed for: " + intent);             
        case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:                                
            throw new IllegalStateException(                                                
                    "Session calling startVoiceActivity does not match active session");    
        case ActivityManager.START_VOICE_HIDDEN_SESSION:                                    
            throw new IllegalStateException(                                                
                    "Cannot start voice activity on a hidden session");                     
        case ActivityManager.START_CANCELED:                                                
            throw new AndroidRuntimeException("Activity could not be started for "          
                    + intent);                                                              
        default:                                                                            
            throw new AndroidRuntimeException("Unknown error code "                         
                    + res + " when starting " + intent);                                    
    }                                                                                       
}

前述のstartActivityに続いて、ActivityManagerNativeクラスにおける内部クラスActivityManagerProxyを定義するインタフェースIActivityManagerを定義する方法である
方法:Activity Management Proxy->startActivity
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,  
        String resolvedType, IBinder resultTo, String resultWho, int requestCode,          
        int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
    Parcel data = Parcel.obtain();                                                         
    Parcel reply = Parcel.obtain();                                                        
    data.writeInterfaceToken(IActivityManager.descriptor);                                 
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);                     
    data.writeString(callingPackage);                                                      
    intent.writeToParcel(data, 0);                                                         
    data.writeString(resolvedType);                                                        
    data.writeStrongBinder(resultTo);                                                      
    data.writeString(resultWho);                                                           
    data.writeInt(requestCode);                                                            
    data.writeInt(startFlags);                                                             
    if (profilerInfo != null) {                                                            
        data.writeInt(1);                                                                  
        profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);        
    } else {                                                                               
        data.writeInt(0);                                                                  
    }                                                                                      
    if (options != null) {                                                                 
        data.writeInt(1);                                                                  
        options.writeToParcel(data, 0);                                                    
    } else {                                                                               
        data.writeInt(0);                                                                  
    }                                                                                      
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);                          
    reply.readException();                                                                 
    int result = reply.readInt();                                                          
    reply.recycle();                                                                       
    data.recycle();                                                                        
    return result;                                                                         
}

パラメータは多く、ここではIApplicationThreadパラメータに重点を置いており、インタフェースであり、重要な方法はscheduleLaunchActivityであり、実現と継承は以下の通りである.
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread
private class ApplicationThread extends ApplicationThreadNative

方法:Activity Thread->ApplicationThread->scheduleLaunchActivity
@Override                                                                                
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,        
        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,        
        CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, 
        int procState, Bundle state, PersistableBundle persistentState,                  
        List pendingResults, List pendingNewIntents,         
        boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {              

    updateProcessState(procState, false);                                                

    ActivityClientRecord r = new ActivityClientRecord();                                 

    r.token = token;                                                                     
    r.ident = ident;                                                                     
    r.intent = intent;                                                                   
    r.referrer = referrer;                                                               
    r.voiceInteractor = voiceInteractor;                                                 
    r.activityInfo = info;                                                               
    r.compatInfo = compatInfo;                                                           
    r.state = state;                                                                     
    r.persistentState = persistentState;                                                 

    r.pendingResults = pendingResults;                                                   
    r.pendingIntents = pendingNewIntents;                                                

    r.startsNotResumed = notResumed;                                                     
    r.isForward = isForward;                                                             

    r.profilerInfo = profilerInfo;                                                       

    r.overrideConfig = overrideConfig;                                                   
    updatePendingConfiguration(curConfig);                                               

    sendMessage(H.LAUNCH_ACTIVITY, r);                                                   
} 

この方法は主にactivityの様々なパラメータを記録し、activityを起動するメッセージを送信し、このメッセージの実装を見る.
private class H extends Handler {
    ...
    public void handleMessage(Message msg) {                                         
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));  
    switch (msg.what) {                                                          
        case LAUNCH_ACTIVITY: {                                                  
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); 
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;       

            r.packageInfo = getPackageInfoNoCheck(                               
                    r.activityInfo.applicationInfo, r.compatInfo);
            //  LAUNCH_ACTIVITY                  
            handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");                    
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    
        } break;
        ...                                                                 
}

本格的な処理がActivityのロジックを起動した
方法:ActvityThread->performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {                                                
    // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");             
    //    Activity     ,  component packageInfo                                                                                      
    ActivityInfo aInfo = r.activityInfo;                                                                                             
    if (r.packageInfo == null) {                                                                                                     
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,                                                          
                Context.CONTEXT_INCLUDE_CODE);                                                                                       
    }                                                                                                                                

    ComponentName component = r.intent.getComponent();                                                                               
    if (component == null) {                                                                                                         
        component = r.intent.resolveActivity(                                                                                        
            mInitialApplication.getPackageManager());                                                                                
        r.intent.setComponent(component);                                                                                            
    }                                                                                                                                

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

    try {                                                                                                                            
        //  Application                                                                                                              
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);                                                    

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

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

            if (customIntent != null) {                                                                                              
                activity.mIntent = customIntent;                                                                                     
            }                                                                                                                        
            r.lastNonConfigurationInstances = null;                                                                                  
            activity.mStartedActivity = false;                                                                                       
            int theme = r.activityInfo.getThemeResource();                                                                           
            if (theme != 0) {                                                                                                        
                activity.setTheme(theme);                                                                                            
            }                                                                                                                        

            activity.mCalled = false;                                                                                                
            if (r.isPersistable()) {                                                                                                 
                //  mInstrumentation callActivityOnCreate       activity onCreate                                                    
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);                                         
            } else {                                                                                                                 
                mInstrumentation.callActivityOnCreate(activity, r.state);                                                            
            }                                                                                                                        
            if (!activity.mCalled) {                                                                                                 
                throw new SuperNotCalledException(                                                                                   
                    "Activity " + r.intent.getComponent().toShortString() +                                                          
                    " did not call through to super.onCreate()");                                                                    
            }                                                                                                                        
            r.activity = activity;                                                                                                   
            r.stopped = true;                                                                                                        
            if (!r.activity.mFinished) {                                                                                             
                activity.performStart();                                                                                             
                r.stopped = false;                                                                                                   
            }                                                                                                                        
            if (!r.activity.mFinished) {                                                                                             
                if (r.isPersistable()) {                                                                                             
                    if (r.state != null || r.persistentState != null) {                                                              
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,                                       
                                r.persistentState);                                                                                  
                    }                                                                                                                
                } else if (r.state != null) {                                                                                        
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);                                          
                }                                                                                                                    
            }                                                                                                                        
            if (!r.activity.mFinished) {                                                                                             
                activity.mCalled = false;                                                                                            
                if (r.isPersistable()) {                                                                                             
                    mInstrumentation.callActivityOnPostCreate(activity, r.state,                                                     
                            r.persistentState);                                                                                      
                } else {                                                                                                             
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);                                                    
                }                                                                                                                    
                if (!activity.mCalled) {                                                                                             
                    throw new SuperNotCalledException(                                                                               
                        "Activity " + r.intent.getComponent().toShortString() +                                                      
                        " did not call through to super.onPostCreate()");                                                            
                }                                                                                                                    
            }                                                                                                                        
        }                                                                                                                            
        r.paused = true;                                                                                                             

        mActivities.put(r.token, r);                                                                                                 

    } catch (SuperNotCalledException e) {                                                                                            
        throw e;                                                                                                                     

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

    return activity;                                                                                                                 
}

performLaunchActivityの主な論理は3つあります.
  • Activityの起動に関する情報を解析し、componentとpackageInfo
  • を含む.
  • ClassLoaderを介してターゲットactivityをロードし、activityオブジェクト
  • をインスタンス化する
  • mInstrumentationのcallActivity OnCreateによってターゲットactivityのonCreateメソッドを間接的に呼び出し、activityの宣言サイクルを実行します.
    3.まとめ
    startActivity全体のソースコード解析はこれで終わり、よく使われているapiについてもっと深く認識したのではないでしょうか.