天天看點

AMS和WMS部分知識點

1. 在WindowMangerImpl中調用addView方法是,需要擷取Display對象,那麼Display是從哪裡來的?

WindowMangerImpl的addView方法

@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    applyDefaultToken(params);
    mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
}
           

在ContextImpl的getDisplay()方法中獲得

//ContextImpl.java
Display getDisplay() {
        if (mDisplay != null) {
            return mDisplay;
        }
        return ResourcesManager.getInstance().getAdjustedDisplay(
                Display.DEFAULT_DISPLAY, mDisplayAdjustments);
    }
           
  1. SystemServiceRegistry

    類是一個為Context提供擷取各種系統服務在App中的包裝類,例如WMS在App中的包裝類是WindowManger
//服務注冊,在靜态代碼塊中完成
registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
            //建立WindowManagerImpl,和Display
                return new WindowManagerImpl(ctx.getDisplay());
            }});
            
//ContextImpl中擷取系統服務的方法
@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
}
           
  1. ActivitManagerNative對應AIDL中Stub類
  2. 所有的系統服務都是在SystemServer類中建立的
// Create the system service manager.
 //所有服務的管理類
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);

// Start services.
try {
    //建立AMS,PMS等服務
    startBootstrapServices();
    //建立BatteryService,WebViewUpdateService等
    startCoreServices();
    //建立IMS,WMS等服務
    startOtherServices();
} catch (Throwable ex) {
    
    throw ex;
}
           
  1. 在Handler中有個隐藏的

    runWithScissors(Runnabler, int timeout)

    方法,這是一個同步的方法,等待r執行完後再返還,在WMS建立過程中執行main()方法時有使用,目的是在未完成WMS建立之前阻塞SystemServer線程
public static WindowManagerService main(final Context context,
        final InputManagerService im,
        final boolean haveInputMethods, final boolean showBootMsgs,
        final boolean onlyCore) {
    final WindowManagerService[] holder = new WindowManagerService[1];
    DisplayThread.getHandler().runWithScissors(new Runnable() {
        @Override
        public void run() {
            holder[0] = new WindowManagerService(context, im,
                    haveInputMethods, showBootMsgs, onlyCore);
        }
    }, 0);
    return holder[0];
}
           

其中DisplayThread 繼承自 ServiceThread,實際上是一個HandlerTread,目的是系統服務可以在自己的Looper中執行;

6. View的

invalidate()

方法執行過程:

invalidate()會調用到invalidateInternal方法;

其實postInvlidate()方法最後調用的也是invalidate()方法,隻不過是通過ViewRootImpl内的handler做了延遲處理

void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
        boolean fullInvalidate) {
    
    //省略代碼
        // Propagate the damage rectangle to the parent view.
        final AttachInfo ai = mAttachInfo;
        //mParent的值是在哪裡來的???
        final ViewParent p = mParent;
        if (p != null && ai != null && l < r && t < b) {
            final Rect damage = ai.mTmpInvalRect;
            damage.set(l, t, r, b);
            //執行視圖的重繪
            p.invalidateChild(this, damage);
        }

    //省略代碼   
    }
}
           

View的重繪是在ViewRootImpl的

scheduleTraversals()

方法中開始的,是以這個mParent一定是一個ViewRootImpl(實作了ViewParent接口)對象,但是它是在哪裡被指派的呢?在View類中有一個

assignParent(ViewParent parent)

方法,查詢這個方法被調用的地方是在ViewRootImple中的

setView(View view, WindowManager.LayoutParams attrs, View panelParentView)

方法内執行的

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;

                //省略代碼
                mAdded = true;
                int res; /* = WindowManagerImpl.ADD_OKAY; */

                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
               
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    //向WMS發起添加視窗的請求
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } catch (RemoteException e) {
                    //省略代碼
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }

                //省略代碼

                if (view instanceof RootViewSurfaceTaker) {
                    mInputQueueCallback =
                        ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
                }
                if (mInputChannel != null) {
                    if (mInputQueueCallback != null) {
                        mInputQueue = new InputQueue();
                        mInputQueueCallback.onInputQueueCreated(mInputQueue);
                    }
                    //接收輸入事件,觸摸等
                    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
                            Looper.myLooper());
                }
                //省略代碼
                
                //将ViewRootImpl回傳給view
                view.assignParent(this);
                //省略代碼
            }
        }
    }
           

View重繪的時機包括,invalidate(),requestLayout(),requsetFoust()

ViewRootImpl的setView方法是在WindowMangerGlobal的addView方法内執行的,WindowMangerGlobal是一個單例,每一個App隻包含一個;

而WindowMangerGlobal的addView()方法是被WindowMangerImpl的addView方法内調用的;

  1. WindowManger的建立時在Activity的attach(…)方法内,建立了Window對象,并調用window的setWindowManger()方法建立了一個WindowMangerImpl的對象
final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
        //建立Window
        mWindow = new PhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        //MotionEvent事件能回調到Activity的關鍵
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
    //省略代碼

        //建立WindowManger,實際是一個WindowMangerImple對象
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }
           
  1. 簡明介紹一個App的啟動過程
    1. 從Launcher中點選App圖示時,會向AMS發送一個啟動Activity C的請求,AMS通過Intent查詢該Activity是否存在,如果存在就建立一個ActivityRecord對象,并通知Launcher可以暫停了;
    2. Launcher調用pause方法,并通知AMS自己暫停了;
    3. AMS就檢查Activity C所在的App是否已經啟動,如果沒有啟動就建立一個新的程序,并調用ActivityThread的main()方法,在main()方法内會建立ActivityThread對象并調用attach方法,裡面會将目前ActivityThread内的ApplicationThread對象作為IBinder傳遞給AMS;
    4. AMS會建立一個ProcessRecord對象儲存App的程序資訊;然後調用ApplicationThread的bindApplication,并取出之前儲存的ActivityRecord對象,調用ApplicationThread的scheduleLaunchActivity()方法啟動Activity
    5. 在handleBindApplicaton方法内會完成App環境的初始化,建立Application對象和Instrumentation對象
    6. scheduleLaunchActivity()會建立Activity對象,并調用onCreate()方法
  2. Activity的

    handleBindApplicaton

    在執行完成後為什麼沒有通知AMS自己已經建立完成了??

    因為在

    handleBindApplicaton

    ,

    performLaunchActivity

    ,

    handleCreateService

    ,

    handleReciver

    方法内部都會通過LoadApk内的makeApplication方法檢測Application對象是否已經建立
private void handleCreateService(CreateServiceData data) {
       //省略
        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            //擷取Application對象
            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);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                // nothing to do.
            }
        }
        」
           

LoadApk内的makeApplication方法

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
            //檢查Application是否已經建立
        if (mApplication != null) {
            return mApplication;
        }
        //否則執行建立Application
        Application app = null;

        //省略代碼
        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
        
        }
    

       //省略代碼
        return app;
    }
           

LoadApk作為存儲加載的.apk的資訊類,是通過WeakReference儲存在一個ArrayMap的數組内,其中map的key是目前apk的packageName

performLaunchActivity

等方法的内部都是通過

getPackageInfoNoCheck

方法來擷取LoadApk對象的,LoadApk對象的建立過程

private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
            boolean registerPackage) {
        final boolean differentUser = (UserHandle.myUserId() != UserHandle.getUserId(aInfo.uid));
        synchronized (mResourcesManager) {
            WeakReference<LoadedApk> ref;
            if (differentUser) {
                // Caching not supported across users
                ref = null;
            } else if (includeCode) {
                ref = mPackages.get(aInfo.packageName);
            } else {
                ref = mResourcePackages.get(aInfo.packageName);
            }

            LoadedApk packageInfo = ref != null ? ref.get() : null;
            if (packageInfo == null || (packageInfo.mResources != null
                    && !packageInfo.mResources.getAssets().isUpToDate())) {
                if (localLOGV) Slog.v(TAG, (includeCode ? "Loading code package "
                        : "Loading resource-only package ") + aInfo.packageName
                        + " (in " + (mBoundApplication != null
                                ? mBoundApplication.processName : null)
                        + ")");
                packageInfo =
                    new LoadedApk(this, aInfo, compatInfo, baseLoader,
                            securityViolation, includeCode &&
                            (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage);
                            
        //省略代碼
}
           
  1. AMS中的ActivityRecord是在ActivityStackSupervisor的

    startActivityLocked

    方法内建立的

    ActivityRecord

    的構造函數内會建立一個

    appToken = new Token(this, service);

    ,這個Token實作了IApplicationToken.Stub接口
  2. 在ActivityStackSupervisor的

    startSpecificActivityLocked

    方法内會檢查需要啟動的Activity的程序是否存在,不存在就調用AMS的startProcess方法啟動程序
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
           
  1. 在AMS的attachApplication()内,除了調用ApplicationThread的bindApplication外,還會啟動棧頂的Activity
private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
//省略代碼  
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());
//省略代碼

// See if the top visible activity is waiting to run in this process...
        if (normalMode) {
            try {
            //啟動棧頂的Activity
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }
//省略代碼
}

//attachApplicationLock
boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        boolean didSomething = false;
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!isFrontStack(stack)) {
                    continue;
                }
                //擷取棧頂
                ActivityRecord hr = stack.topRunningActivityLocked(null);
                if (hr != null) {
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
                        //啟動Activity
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                            Slog.w(TAG, "Exception in new application when starting activity "
                                  + hr.intent.getComponent().flattenToShortString(), e);
                            throw e;
                        }
                    }
                }
            }
        }
        if (!didSomething) {
            ensureActivitiesVisibleLocked(null, 0);
        }
        return didSomething;
    }