[Nutria] - System App 分析

73 阅读2分钟

System App

system app 是由gecko层的shell.js 引导启动的第一个App,相当于Nutria的界面框架。
capyloon系统的状态栏、导航栏、通知栏、系统开关机等都是有system app 负责管理的。

项目布局

system app 重要文件和目录分别是index.html manifest.webmanifestcomponents文件夹、js文件夹

├── **components**
│   ├── activity_chooser.css
│   ├── activity_chooser.js
│   ├── app_icon.css
│   ├── apps_list.css
│   ├── apps_list.js
│   ├── audio_volume_indicator.css
│   ├── audio_volume_indicator.js
│   ├── browser_action_popup.css
│   ├── browser_action_popup.js
│   ├── confirm_dialog.css
│   ├── confirm_dialog.js
│   ├── content_window.css
│   ├── content_window.js
│   ├── context_menu.css
│   ├── context_menu.js
│   ├── input_method.css
│   ├── input_method.js
│   ├── lock_screen.css
│   ├── lock_screen.js
│   ├── notification.js
│   ├── places_item.css
│   ├── publish_dialog.css
│   ├── publish_dialog.js
│   ├── quick_settings.css
│   ├── quick_settings.js
│   ├── reboot_menu.css
│   ├── reboot_menu.js
│   ├── select_ui.css
│   ├── select_ui.js
│   ├── site_info.css
│   ├── site_info.js
│   ├── status_bar.css
│   ├── status_bar.js
│   ├── status_icons.css
│   ├── status_icons.js
│   ├── text_share.css
│   ├── text_share.js
│   ├── ucan.js
│   ├── ucan_dialog.css
│   ├── url_edit.css
│   ├── url_edit.js
│   ├── web_extensions.js
│   ├── window_manager.css
│   └── window_manager.js
├── index.html
├── **js**
│   ├── actions_dispatcher.js
│   ├── activity_handler.js
│   ├── **audio_volume**
│   │   ├── gonk.js
│   │   └── linux.js
│   ├── battery.js
│   ├── bootstrap.js
│   ├── config.js
│   ├── dependencies.js
│   ├── downloads.js
│   ├── embedding.js
│   ├── estuary.js
│   ├── flashlight.js
│   ├── haptic_feedback.js
│   ├── input_method.js
│   ├── ipfs_publisher.js
│   ├── keys.js
│   ├── notifications.js
│   ├── p2p.js
│   ├── power_manager.js
│   ├── ua_store.js
│   ├── wallpaper_manager.js
│   └── web_extensions_delegate.js
├── **locales**
├── manifest.webmanifest
├── **neterror**
│   ├── config.js
│   ├── index.html
│   ├── main.js
│   └── style.css
├── **resources**
│   ├── default-wallpaper.webp
│   ├── logo-b2g.webp
│   ├── pwalogo.svg
│   └── tor.ico
├── **style**
│   ├── desktop.css
│   ├── device.css
│   └── index.css
└── **swproxy**
    ├── helper.js
    ├── proxy.html
    ├── proxy.js
    └── sw.js

index.html

我们先从index入口开始分析

<!DOCTYPE html>
<html lang="en-US">
  <head>
   ...
    <!-- embedding API provider -->
    <script src="chrome://b2g/content/embedding/web-embedder.js"></script>

    <!--
      This will setup Fluent for l10n
      We don't lazy load it because it's needed at startup to localize the boot screen.
    -->
    <script src="js/config.js"></script>

    <script src="js/embedding.js"></script>
    <script src="js/dependencies.js"></script>
    <script src="js/bootstrap.js" type="module"></script>
  </head>
  <body>
    <!-- 开机关机 -->
    <div id="logo" class="starting">
      <div class="title" data-l10n-id="logo-title">Capyloon</div>
      <div class="subtitle" data-l10n-id="logo-subtitle"></div>
      <div class="image"></div>
      <div class="action starting" data-l10n-id="logo-starting"></div>
      <div class="action shutdown" data-l10n-id="logo-shutdown"></div>
      <div class="action reboot" data-l10n-id="logo-reboot"></div>
    </div>
    
    <!-- 主界面框架 -->
    <div id="screen">
       <!-- 顶部状态栏 -->
      <div id="status-top"></div>
      <!-- web complement 应用管理器 - 其他应用都是显示在这里面 -->
      <window-manager id="wm"></window-manager>
      <!-- 底部操作栏 -->
      <status-bar id="statusbar"></status-bar>
    </div>
    
    <!-- shoelace components - 底部快速设置抽屉 -->
    <sl-drawer no-header placement="bottom" id="quick-settings">
      <quick-settings></quick-settings>
    </sl-drawer>

    <!-- shoelace components - 侧边电源菜单抽屉 -->
    <sl-drawer no-header placement="end" id="reboot-menu">
      <reboot-menu></reboot-menu>
    </sl-drawer>

    <!-- shoelace components - 当前页面标题UA相关信息面板 -->
    <sl-drawer no-header placement="bottom" id="site-info">
      <site-info></site-info>
    </sl-drawer>
    
    <!-- shoelace components - ??? -->
    <sl-drawer no-header placement="bottom" id="activity-chooser">
      <activity-chooser></activity-chooser>
    </sl-drawer>

    <!-- app 列表 -->
    <apps-list id="apps-list"></apps-list>

    <!-- 其他全局弹窗 -->
    <context-menu></context-menu>
    <text-share></text-share>
    <confirm-dialog></confirm-dialog>
    <publish-dialog></publish-dialog>
    <ucan-dialog></ucan-dialog>

    <-- 地址输入栏面版 -->
    <url-edit class="offscreen"></url-edit>
    
    <webext-browser-action class="offscreen"></webext-browser-action>

    <!-- 输入法弹窗 -->
    <input-method class="offscreen"></input-method>
    <!-- 锁屏界面 -->
    <lock-screen id="lockscreen" class="unlocked"></lock-screen>
    <!-- 音量 -->
    <audio-volume id="audiovolume" class="offscreen" hidden></audio-volume>
    
    <!-- 权限使用图标 -->
    <status-icons id="status-icons" class="hidden"></status-icons>

    <!-- 提示 -->
    <template id="toaster-template">
      <sl-alert duration="2000" closable>
        <sl-icon slot="icon"></sl-icon>
        <strong></strong>
      </sl-alert>
    </template>
  </body>
</html>

js/config.js

1 preconnect to the api daemon api server.
2 preconnect to the homescreen.
3 加载depGraphLoaded引擎
4 MinuteTimer 一个正秒的事件定时器
5 创建Toaster class, 把html 的Toaster dom 绑定,然后把实例挂载window.toaster 使用show方法。

js/bootstrap.js

DOMContentLoaded 事件进行初始化。
1 等待 embedderSetupDone
2 等待 daemonReady
3 加载 config js 的depGraphLoaded , 加载kDeps
4 等待 依赖 graph.waitForDeps: lockscreen comp phase1 launch
5 keyManager js 注册 按键事件。
6 setupTelephony
7 add  headphones-status-changed 事件
8 等待 manageFTU
9 add geolocation-status 事件。

setupTelephony

1 通过 navigator.b2g?.mobileConnections 控制ril的开启关闭
2 添加事件navigator.b2g.telephony.onincoming

        // Open the dialer when we receive an incoming call.
    navigator.b2g.telephony.onincoming = () => {
      // If the screen is turned off, turn it on.
      actionsDispatcher.dispatch("set-screen-on");

      // If the screen is locked, launch through the lockscreen.
      let url = `http://dialer.localhost:${config.port}/index.html?incoming`;
      if (window.lockscreen.isLocked()) {
        window.lockscreen.launch(url);
      } else {
        window.wm.openFrame(url, {
          activate: true,
        });
      }
    };
  }

manageFTU

1 检查设置的ftu.done标识是否为false
2 通过window.lockscreen.launch 启动ftu

js/embedding.js

    
    // 1 index.html
    // 在index 加载了gecke 层 shell 提供的web-embedder脚本,它提供了 WebEmbedder
    <!-- embedding API provider -->
    <script src="chrome://b2g/content/embedding/web-embedder.js"></script>
    
    // 2 在 中使用了WebEmbedder实例embedder,并放到了window
    const embedder = new WebEmbedder({
    windowProvider,
    processSelector,
    notifications,
    imeHandler,
    activityChooser,
    webExtensions,
    eme,
    });

windowProvider

todo

WindowManager

link [Nutria] - System App 分析 - WindowManager

PowerManagement

link [Nutria] - System App PowerManagement

ContentWindow

[Nutria] - System App 分析 - WindowManager

其他模块 (正在更新)

window 挂载点


config={
platform,
metaOrControl,
ftuDone
}
lockscreen

embedder
wm
processManager
apiDaemon
PowerManagement


QA

Q:System App 是没有csp限制的? or core app 是没有csp限制的?
A:System App 是可以通过ChromeUtils.import方法获取gecko的jsm服务

const { AppConstants } = ChromeUtils.import(
  "resource://gre/modules/AppConstants.jsm"
);
let isDevice = AppConstants.platform === "gonk";

(function () {
  const { Services } = ChromeUtils.import(
    "resource://gre/modules/Services.jsm"
  );
  Services.obs.notifyObservers(null, "force-gmp-provider-startup", null);
})();