SystemUI起動プロセスと主体レイアウト紹介

22429 ワード

http://www.jianshu.com/p/0ab1279465fa
本論文ではAndroid 6.0コードに基づいて、system UIの起動ローディングフローを分析し、system UIのいくつかのキービューのレイアウトと機能を紹介する.
一.SystemUI本体フレーム起動フロー
Androidデバイス上で電気的にブートをブートしてboot(通常はuboot)に入り、initramfs、ケネルミラーをロードして、ケネルを起動してから、ユーザー状態プログラムに入ります.最初のユーザ空間プログラムはinitで、PID固定は1.initの基本機能は以下の通りです.
  • 管理装置
  • Android起動スクリプトinit.rc
  • を解析して処理する.
  • は、このinit.rcのサービスをリアルタイムで維持し、Zygote
  • をロードすることを含む.
    ZygoteではSystemServerのコンポーネントを起動します.
    本稿はSystemServerから分析を開始する.SystemServerはシステムサービスプロセスといい、Androidシステムを起動するキーサービスを担当しています.その入り口はSystem Server.mainです.
    /** * The main entry point from zygote. */
        public static void main(String[] args) {
            new SystemServer().run();
        }
    メールでSystemServerオブジェクトを生成してrunメソッドを実行したことが見られます.System Server.run():
    private void run() {
        ......
    
         // Start services.
            try {
                startBootstrapServices();
                startCoreServices();
                startOtherServices();
                ......
           } catch (Throwable ex) {
               ...
                throw ex;
            }
            ...
            // Loop forever.
            Looper.loop();
            throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    まずstartBootstraphServicesを見ます.
     private void startBootstrapServices() {
            ......
            Installer installer = mSystemServiceManager.startService(Installer.class);
    
            // Activity manager runs the show.
            mActivityManagerService = mSystemServiceManager.startService(
                    ActivityManagerService.Lifecycle.class).getService();
            mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
            ......
     }
    startBootstraphServicesでmActivityManagerServiceが起動しました.その後、私たちは再びスターセットを見に行きます.
    private void startOtherServices() {
            final Context context = mSystemContext;
            AccountManagerService accountManager = null;
            ContentService contentService = null;
            .......
    
             mActivityManagerService.systemReady(new Runnable() {
                @Override
                public void run() {
                  ......
    
                    try {
                        startSystemUi(context);
                    } catch (Throwable e) {
                        reportWtf("starting System UI", e);
                    }
             .......
    mActivityManagerService.systemUiを実行するスレッドを作成します.方法名からも分かるように、ここでsystem UIが起動されます.
    static final void startSystemUi(Context context) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.android.systemui",
                        "com.android.systemui.SystemUIService"));
            //Slog.d(TAG, "Starting service: " + intent);
            context.startServiceAsUser(intent, UserHandle.OWNER);
        }
    intent.set Component(new ComponentName);systeemuiプログラムを起動するSystemUICServiceを設定してSystemUICServiceに入ります.
    public class SystemUIService extends Service {
    
        @Override
        public void onCreate() {
            super.onCreate();
            ((SystemUIApplication) getApplication()).startServicesIfNeeded();
        }
    ......
    onCreate方法ではSystemUIAppleオブジェクトを取得し、そのstartServices IfNeedメソッドを呼び出します.
     public void startServicesIfNeeded() {
            final int N = SERVICES.length;
            for (int i=0; i cl = SERVICES[i];
                try {
                    mServices[i] = (SystemUI)cl.newInstance();//    
                } catch (IllegalAccessException ex) {
                    throw new RuntimeException(ex);
                } catch (InstantiationException ex) {
                    throw new RuntimeException(ex);
                }
                mServices[i].mContext = this;
                mServices[i].mComponents = mComponents;
                mServices[i].start();//start  
                if (mBootCompleted) {
                    mServices[i].onBootCompleted();
                }
            }
            mServicesStarted = true;
        }
    start Services IfNeed()循環startが多く見られます.配列SERVICESの定義は以下の通りである.
    private final Class>[] SERVICES = new Class[] {
                com.android.systemui.tuner.TunerService.class, //       
                com.android.systemui.keyguard.KeyguardViewMediator.class,//    
                com.android.systemui.recents.Recents.class,//    
                com.android.systemui.volume.VolumeUI.class,//      
                com.android.systemui.statusbar.SystemBars.class,//     
                com.android.systemui.usb.StorageNotification.class,//Storage    
                com.android.systemui.power.PowerUI.class,//      
                com.android.systemui.media.RingtonePlayer.class,//    
                com.android.systemui.keyboard.KeyboardUI.class,//    
    };
    サブサービスは、TunerService、KeygurdView Mediat、Recents、VolumeUI、SystemBars、StrageNotification、PowerUI Ringtone Player、KeyboardUIを含むことができます.でも、ここのサービスは私たちが普段話している四つのコンポーネントのサービスと違います.ここのサービスはSystemUI類の一般的な対象を継承しただけです.例えばSystemBars:
    public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {
               ......
    }
    リボン:
    ここを見ると、system UIの本体フレームの起動フローをまとめられます.SystemServer起動AndroidコアサービスはActivityManagerService-->ActivityManagerSerServiceが起動されれば、systemUIcevice---SystemUIrviceを起動します.start()SystemUIの各種コアサービスを起動します.
    二.SystemUIキービューの提示
    携帯電話のドロップダウンステータスバー、ロックスクリーン、通知、および最近のジョブリストのオープンなどの機能は、SystemUIが実現しました.主な機能点に対応する画面は下図のようになります.
    上記では、SystemUIの各サービスの起動プロセスを見ましたが、サービスができました.インターフェースビューはどのように現れますか?次にSystemBarsを例にとって、SystemUIの主要なビューである.上記のmServices[i].startはSystemBars.start()を呼び出します.
        @Override
        public void start() {
            if (DEBUG) Log.d(TAG, "start");
            mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
                    mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
            mServiceMonitor.start();  // will call onNoService if no remote service is found
        }
    startでServiceMonitorのインスタンスを作成してstart()を作成します.コメントでは、サービスが起動していない場合、ServiceMonitorはSystemBarsのオン・ノサーヴィスに戻ります.だからSystemBarsのオン・ノ・サービスを見に行きます.
        @Override
        public void onNoService() {
            if (DEBUG) Log.d(TAG, "onNoService");
            createStatusBarFromConfig();  // fallback to using an in-process implementation
        }
    
        private void createStatusBarFromConfig() {
            final String clsName = mContext.getString(R.string.config_statusBarComponent);
            if (clsName == null || clsName.length() == 0) {
                throw andLog("No status bar component configured", null);
            }
            Class> cls = null;
            try {
                cls = mContext.getClassLoader().loadClass(clsName);
            } catch (Throwable t) {
                throw andLog("Error loading status bar component: " + clsName, t);
            }
            try {
                mStatusBar = (BaseStatusBar) cls.newInstance();
            } catch (Throwable t) {
                throw andLog("Error creating status bar component: " + clsName, t);
            }
            mStatusBar.mContext = mContext;
            mStatusBar.mComponents = mComponents;
            mStatusBar.start();
        }
    CsNameで得られたstringはcomp.android.system.statusbar.phone.Phone Status BarでSystemBars.start()を実行した後、反射機構によって最終的にBaseStatus Barオブジェクトを得ることができます.ここで説明したいのは、BaseStatusBarはPhone Status Barの父類です.上記のmSttusBar.startはPhone Status Bar.startです.
        public void start() {
                ......
                super.start(); // calls createAndAddWindows()
                ......
        }
    またBaseStartsBar.startに行きます.
    public void start() {
            mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
            mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
            mDisplay = mWindowManager.getDefaultDisplay();
            mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
                    Context.DEVICE_POLICY_SERVICE);
    
            mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
    
            mNotificationData = new NotificationData(this);
    
            mAccessibilityManager = (AccessibilityManager)
                    mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
    
            mDreamManager = IDreamManager.Stub.asInterface(
                    ServiceManager.checkService(DreamService.DREAM_SERVICE));
            mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
    
            .......
            //         systemui     ,  ,Manager,Observer  
            .......
    
            createAndAddWindows(); //       
    createAndAddWindowsを見る():
     protected abstract void createAndAddWindows();
    抽象的な方法です.明らかにBaseStatusBarのサブクラス、つまりPhone Status BarのcreateAndAddWindowsを呼び出しました.
     @Override
     public void createAndAddWindows() {
            addStatusBarWindow();
     }
    
     private void addStatusBarWindow() {
            makeStatusBarView();//    ,  StatusBarView
            mStatusBarWindowManager = new StatusBarWindowManager(mContext);
            mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
     }
    ポイントは、makeStatus BarViewを作成し、Status BarViewを作成し、その後、mStatus BarWindowManagerが追加し、ユーザーに提示するmakeStatus BarViewのコードは長いですが、主要コードはこの文です.
    protected PhoneStatusBarView makeStatusBarView()
    {
        ......
        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                    R.layout.super_status_bar, null);
        ......
    }
    super_を認識することによってstatusbar.xmlはSystemBarsの大体の構成を知ることができます.以下は部分省略のsuper_です.statusbarファイル
    
    .android.systemui.statusbar.phone.StatusBarWindowView
        android:fitsSystemWindows="true">
    
        .android.systemui.statusbar.BackDropView
                android:id="@+id/backdrop"
                sysui:ignoreRightInset="true">
        .android.systemui.statusbar.BackDropView>
    
        .android.systemui.statusbar.ScrimView 
            android:id="@+id/scrim_behind"
            android:importantForAccessibility="no"/>
    
        .android.systemui.statusbar.AlphaOptimizedView
            android:id="@+id/heads_up_scrim"
            android:importantForAccessibility="no"/>
    
        "@layout/status_bar"
            android:layout_width="match_parent"
    
        "@+id/brightness_mirror">
            background="@drawable/brightness_mirror_background">
                "@layout/quick_settings_brightness_dialog"
                         android:layout_height="wrap_content" />
            
        
    
        .android.systemui.statusbar.phone.PanelHolder
            android:id="@+id/panel_holder"
            "@layout/status_bar_expanded"
                android:visibility="gone" />
        .android.systemui.statusbar.phone.PanelHolder>
    
        .android.systemui.statusbar.ScrimView android:id="@+id/scrim_in_front"
            android:importantForAccessibility="no"
            sysui:ignoreRightInset="true"
            />
    
    .android.systemui.statusbar.phone.StatusBarWindowView>
    上記のviewレイアウト及びmakeStatus BarView関連コードにより、mStatus BarWindow(Status BarWindow View)には以下の4つの部分が含まれていることが分かります.
  • ScrimView
  • Phone Status BarView layout->status_bar
  • Panel Holder id->Panel Holder
  • ScrimView
  • 実はここに重要なviewが漏れています.bouncerは直接にlayoutレイアウトに加入したのではなく、ユーザーがロックスクリーン保護を設定してからしか見えません.
    Status BarWindowView
    ここでは主にPhone Status BarView、Panel HolderとKeygurd Bouncerを調べます.
    Phone Status BarViewは携帯電話の一番上の状態欄で、主にシステムの状態を表示するために用いられます.通知などは主にnotification iconsとstatus bar iconsを含みます.
    Phone Status BarView
    Panel Holder Panel Holderはユーザがstatus barを引いて得たviewです.それは主にQuickSettingsとNotification panelの二つの部分を含んでいます.Panel HolderはFrame Layoutから引き継がれたカスタムviewで、その内容はinclude statusを通じて(u)です.bar_expanded.xmlを充填します.Panel Holderはレイアウトが複雑で、viewの重用性を高めるためにincludeラベルを多く使いました.
    Panel Holder
    QuickSettings及びNotification panelインタフェースのレイアウト及び機能に関する文書はそれぞれQSPanel及びNotificationPanel Viewを修正する.
    KeygurardBouncer KeygardBouncerは、スクリーンロック解除インターフェースであり、ユーザーが設定したロック解除方式によって異なるロック解除モードを示しています.まずKeygurard Bouncerの長さを見てください.
    ロック画面:
    Notification Keygard
    スライドしてスクリーンをロックした後:
    Keygurard Bouncer
    注意したいのはKeygur dBouncerには様々な形があり、上の図には図の解錠が示されています.暗号解除のためにKeygurdBouncerがデジタルキーボードとして表示されます.いずれの形式もKeygurd Bouncerにロードされます.
    public class KeyguardBouncer { 
    private ViewGroup mRoot; 
    private ViewGroup mContainer; 
    private KeyguardHostView mKeyguardView;
    private void inflateView() {        
           mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
           mKeyguardView =(KeyguardHostView)mRoot.findViewById(R.id.keyguard_host_view);
           mKeyguardView.setLockPatternUtils(mLockPatternUtils);
           mKeyguardView.setViewMediatorCallback(mCallback); 
           mContainer.addView(mRoot,mContainer.getChildCount());
    }
    KeygurardBouncerのViewツリーは以下の通りです.
    Keygurard Bouncer
    リボン:
    SystemBarsのプレゼンテーションの流れを分析することによって、Phone Status BarView、Panel Holder、keygurdbouncerの3つのよくあるSystemUIのインターフェースレイアウトと関連機能を紹介しました.もちろん、SystemUIのレイアウトはまだ複雑で、上述は主要なビューだけを大きな方向から分析しました.SystemUIは、最近のアプリケーションビュー、ボトムナビゲーションバー、大域ボリューム管理Dialogなどのいくつかのレイアウトだけでなく、ここでは紹介されていません.
    まとめ:
    本論文は、SystemUI本体フレーム起動プロセスとSystemUIキービューのインターフェースレイアウト提示プロセスをそれぞれ2つの部分に分けて紹介する.以上の説明により、今後SystemUIに関する問題が発生した場合、まず問題Viewがどの大きな分類に属するかを特定し、次に図例に関連して提供されるidに関連して位置決め範囲を縮小することができる.