將system_server進程配置成Android Application進程

這篇blog主要是介紹Android是怎樣將system_server這個系統(tǒng)進程配置成android的application的運行環(huán)境的。
其中會涉及到framework-res.apk , SettingsProvider.apk

注: 該篇代碼是基本 Android M 6.0.1

這篇文章最早發(fā)表于我的個人主頁github乓旗,現(xiàn)在只是將它移到簡書上。
轉載請標注來處: http://www.reibang.com/p/4378ebb1847f

一颁督、framework-res.apk

framework-res.apk是android framework相關的資源文件apk, 里面保存了framework使用到的layout渣触、圖片、string等資源蟋字, 同時也會聲明一些系統(tǒng)級的Activity.
代碼地址: frameworks/base/core/res

1.1 Android.mk

LOCAL_PACKAGE_NAME := framework-res
LOCAL_CERTIFICATE := platform
LOCAL_EXPORT_PACKAGE_RESOURCES := true  

LOCAL_EXPORT_PACKAGE_RESOURCES 為true, 表示允許framework-res.apk里的資源可以被其它app使用.

1.2 AndroidManifest.mk

  • 配置成system sharedUserId
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android"
    coreApp="true"
    android:sharedUserId="android.uid.system"
    <!--system權限-->
    android:sharedUserLabel="@string/android_system_label"
>

從AndroidManifest里可以看出framework-res.apk的package name為 “android”, 且要運行在system進程中.

  • 定義protected-broadcast
<protected-broadcast android:name="android.intent.action.SCREEN_OFF" />
<protected-broadcast android:name="android.intent.action.SCREEN_ON" />

pretected-broadcast廣播只能由系統(tǒng)級應用發(fā)出, 它是由PackageManagerService解析.
在Android系統(tǒng)運作起來之后稿蹲,如果某個不具有系統(tǒng)權限的APP試圖發(fā)送系統(tǒng)中的“保護性廣播”,那么AMS的broadcastIntentLocked()會攔截鹊奖,AMS會拋出異常

java.lang.SecurityException: Permission Denial: not allowed to send broadcast
android.intent.action.SCREEN_OFF from pid=3225, uid=10068
  • 定義permission與permission-group
<!-- Allows an application to send SMS messages.
     <p>Protection level: dangerous
-->
<permission android:name="android.permission.SEND_SMS"
    android:permissionGroup="android.permission-group.SMS"
    android:label="@string/permlab_sendSms"
    android:description="@string/permdesc_sendSms"
    android:permissionFlags="costsMoney"
    android:protectionLevel="dangerous" />

    <!-- Allows an application to receive SMS messages.
         <p>Protection level: dangerous
    -->
<permission android:name="android.permission.RECEIVE_SMS"
    android:permissionGroup="android.permission-group.SMS"
    android:label="@string/permlab_receiveSms"
    android:description="@string/permdesc_receiveSms"
    android:protectionLevel="dangerous"/>

permission-element用來作為安全權限限制訪問一些特殊的模塊或者features或者其它應用程序苛聘。
若APP要使用,必須要聲明

    <use-permission />
  • 定義主application
<application android:process="system"  
    android:persistent="true"   //persistent進程
    android:hasCode="false"  //沒有application的code,
    android:label="@string/android_system_label"
    android:allowClearUserData="false"
    android:backupAgent="com.android.server.backup.SystemBackupAgent"
    android:killAfterRestore="false"
    android:icon="@drawable/ic_launcher_android"
    android:supportsRtl="true">

    <!--定義一些activity-->
    <activity android:name="com.android.internal.app.ChooserActivity"
        android:theme="@style/Theme.DeviceDefault.Resolver"
        android:finishOnCloseSystemDialogs="true"
        android:excludeFromRecents="true"
        android:documentLaunchMode="never"
        android:relinquishTaskIdentity="true"

默認所有的components都運行在system進程, 當然前提是有相同的shared User ID, 和相同的簽名(Android.mk里定義了platform)

二忠聚、SettingsProvider.apk

SettingsProvider.apk 是一個ContentProvider, 主要用來提供系統(tǒng)的Settings的值设哗,它是運行
在system進程中的,因為system進程里面有很多service, 這些service都可能需要訪問到SettingsProvider里的值两蟀。
因此將SettingsProvider.apk跑在system進程中可以避免不必要的跨進程間消耗.
參見鄧凡平的android 系統(tǒng)2

2.1 Android.mk

LOCAL_MODULE_TAGS := optional  
LOCAL_SRC_FILES := $(call all-subdir-java-files) \
        src/com/android/providers/settings/EventLogTags.logtags
LOCAL_JAVA_LIBRARIES := telephony-common ims-common
LOCAL_PACKAGE_NAME := SettingsProvider
LOCAL_CERTIFICATE := platform   //platform簽名
LOCAL_PRIVILEGED_MODULE := true //privileged的apk

從上面可以看出, SettingsProvider.apk也是platform簽名

2.2 AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.providers.settings"
    coreApp="true"
    android:sharedUserId="android.uid.system"> <!-- system權限 -->

    <application android:allowClearUserData="false"
        android:label="@string/app_label"
        android:process="system"
        <!--該application下的所有Component運行在 system進程中-->

        android:backupAgent="SettingsBackupAgent"
        android:killAfterRestore="false"
        android:icon="@mipmap/ic_launcher_settings">

        <!-- todo add: android:neverEncrypt="true" -->

        <provider android:name="SettingsProvider"
            android:authorities="settings"
            android:multiprocess="false"
            android:exported="true"  
            <!--其它application可通過 URL訪問該Provider-->
            android:singleUser="true"
            android:initOrder="100" />
    </application>
</manifest>

從AndroidManifest.xml中定義來看网梢,SettingsProvider.apk里所有的組件默認也是運行在system進程,且SettingsProvider.apk這個進程是system權限赂毯。

三战虏、配置 SystemServer為Android application的環(huán)境

接下來這節(jié)主要來介紹如何將SystemServer配置成android應用程序的運行環(huán)境
整個簡化的流程如下所示:

public static void main(String[] args) {
    new SystemServer().run();
}

private void run() {
    …
    // Initialize the system context.
    createSystemContext();
    //初始化系統(tǒng)上下文

    // Set up the Application instance for the system process and get started.
    mActivityManagerService.setSystemProcess();
    //通過AMS,將當前進程設置成android的應用程序的環(huán)境党涕,安裝framework-res.apk,生成進程相關的ProcessRecord

    //安裝系統(tǒng)Providers
    mActivityManagerService.installSystemProviders();

}

3.1 createSystemContext

每個android 應用程序在進行初始化的時候首先都會生成一個全局的Applicaton實例(不管App代碼有沒有去實現(xiàn)這樣一個application).
而createSystemContext創(chuàng)建的系統(tǒng)上下文就是去生成這樣一個Application實例烦感。

private void createSystemContext() {
    ActivityThread activityThread = ActivityThread.systemMain();
    //創(chuàng)建與線程相關的AcivityThread, 并且創(chuàng)建系統(tǒng)context
    mSystemContext = activityThread.getSystemContext();
    …
}
public static ActivityThread systemMain() {
     …
    ActivityThread thread = new ActivityThread();
    //將當前system_server運行的主線程關聯(lián)一個AcivityThread.
    thread.attach(true);
    return thread;
}

// attach 系統(tǒng)進程
private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        …
    } else {
     // Don't set application object here -- if the system crashes,
     // we can't display an alert, we just want to die die die.
        android.ddm.DdmHandleAppName.setAppName("system_process",
                UserHandle.myUserId());
        //將Systemserver進程在DDM里設置名稱為 system_process,這樣就可以在DDMS里看到
        // system server進程了
        try {
            mInstrumentation = new Instrumentation();
            //生成一個Instrumentation遣鼓,這是一個工具類
            ContextImpl context = ContextImpl.createAppContext(
                    this, getSystemContext().mPackageInfo);
            //這個context完全沒用啸盏,只是臨時使用LoadedApk, “android/system”
            mInitialApplication = context.mPackageInfo.makeApplication(true, null);
            //生成應用程序對應的全局的Application
            mInitialApplication.onCreate();
            //進入Application的生命周期 onCreate()
        } catch (Exception e) {
            …
        }
    }

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
        //強制初始化"android.app.Application"
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            initializeJavaContextClassLoader();
        }
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        //這個創(chuàng)建出來的Context是真正的Systemserver的Application里對應的那個Context
        //原來的application實例僅是一個殼
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
        //生成Application, Application是繼承于ContextWrapper重贺,類似于proxy模式骑祟,
        // ContextImpl與Application通過mOuterContext, mBase互相引用
    } catch (Exception e) {
    …
    }
    mActivityThread.mAllApplications.add(app);
    //將當前生成的Application加入到mAllApplications里,
    //可以看出气笙,一個線程是可以跑多個apk的次企,(一個apk對應一個Application)

    mApplication = app;  //用mApplication表示最初始化的Application

    return app;
}

3.2 setSystemProcess

createSystemContext 僅僅是將應用程序的環(huán)境準備好,如ActivityThread, Application潜圃, context等等缸棵。
里面還沒有一些真正意義上的程序、資源谭期,僅僅是一個進程空殼堵第。

AMS setSystemProcess()
//安裝framework-res.apk, 生成systemserver對應的ProcessRecord, 并與ActivityThread進行綁定

public void setSystemProcess() {
    ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
        "android", STOCK_PM_FLAGS);
    //注意,這里的mContext是 mSystemContext, 即系統(tǒng)級的上下文隧出, 查找package name為 “android”
    //的ApplicationInfo踏志,從以上可知package name為 “android”的 apk是 framework-res.apk,
    //即framework的資源文件apk, ApplicationInfo是通過解析framework-res.apk里的AndroidManifest.xml獲得的

    mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
    //開始為ActivityThread 安裝 system application相關信息,將framework-res.apk對應的
    //ApplicationInfo安裝到LoadedApk中的mApplicationInfo

    //為systemserver 主進程開辟一個ProcessRecord來維護進程的相關信息
    synchronized (this) {
        //從framework-res.apk里可以知道info.processName為 “system”進程,即framework-res.apk是要跑在system進程中的胀瞪。
        ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
        app.persistent = true;
        app.pid = MY_PID;  //為ProcessRecord賦值當前進程ID针余,即system_server進程ID
        app.maxAdj = ProcessList.SYSTEM_ADJ;  //這個值跟OOM killer有關,值越小,越不容易被kill來釋放內存
        app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
        //將ProcessRecord與ActivityThread進行關聯(lián)
        synchronized (mPidsSelfLocked) {
            mPidsSelfLocked.put(app.pid, app);
            //將ProcessRecord放到mPidSelfLocked里統(tǒng)一管理
        }
        updateLruProcessLocked(app, false, null);
        updateOomAdjLocked();  //更新oom adj, 沒看
    }
}

//生成 ProcessRecord對象
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
        boolean isolated, int isolatedUid) {
    String proc = customProcess != null ? customProcess : info.processName;
    final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
    if (!mBooted && !mBooting
            && userId == UserHandle.USER_OWNER
            && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
        r.persistent = true; //persistent
    }
    addProcessNameLocked(r);
    return r;
}

3.3 installSystemProviders

為系統(tǒng)安裝settings provider

AMS installSystemProviders() //安裝系統(tǒng)級的Providers

public final void installSystemProviders() {
    List<ProviderInfo> providers;
    synchronized (this) {
        ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
        //這里是查找system進程的ProcessRecord圆雁,即 3.2節(jié) 生成的
        providers = generateApplicationProvidersLocked(app);
        //根據app.processName “system” 來查看Providers, 在這里是SettingsProvider
        if (providers != null) {
            for (int i=providers.size()-1; i>=0; i--) {
                ProviderInfo pi = (ProviderInfo)providers.get(i);
                if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                    Slog.w(TAG, "Not installing system proc provider " + pi.name
                            + ": not system .apk");
                    //這里只安裝系統(tǒng)級的Providers
                    providers.remove(i);
                }
            }
        }
    }
    if (providers != null) {
        mSystemThread.installSystemProviders(providers);
    }

    mCoreSettingsObserver = new CoreSettingsObserver(this);

    //mUsageStatsService.monitorPackages();
}

//往ActivityThread里安裝SystemProviders, mInitialApplication即是systemserver進程的Application, 前面有講
mSystemThread.installSystemProviders(providers);
installContentProviders(mInitialApplication, providers);

private void installContentProviders(
        Context context, List<ProviderInfo> providers) {
    final ArrayList<IActivityManager.ContentProviderHolder> results =
        new ArrayList<IActivityManager.ContentProviderHolder>();

    for (ProviderInfo cpi : providers) {
        if (DEBUG_PROVIDER) {
            StringBuilder buf = new StringBuilder(128);
            buf.append("Pub ");
            buf.append(cpi.authority);
            buf.append(": ");
            buf.append(cpi.name);
            Log.i(TAG, buf.toString());
        }
        //具體安裝到 ActivityThread里的mProviderMap

        IActivityManager.ContentProviderHolder cph = installProvider(context, null,
                cpi,  false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
        if (cph != null) {
            cph.noReleaseNeeded = true;
            results.add(cph);
        }
    }

    try {
        ActivityManagerNative.getDefault().publishContentProviders(
            getApplicationThread(), results);
    } catch (RemoteException ex) {
    }
}

四忍级、 SystemServer的ActivityThread安裝圖

圖1 SystemServer的ActivityThread的安裝圖
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市伪朽,隨后出現(xiàn)的幾起案子轴咱,更是在濱河造成了極大的恐慌,老刑警劉巖烈涮,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗦玖,死亡現(xiàn)場離奇詭異,居然都是意外死亡跃脊,警方通過查閱死者的電腦和手機宇挫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來酪术,“玉大人器瘪,你說我怎么就攤上這事』嫜悖” “怎么了橡疼?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長庐舟。 經常有香客問我欣除,道長,這世上最難降的妖魔是什么挪略? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任历帚,我火速辦了婚禮,結果婚禮上杠娱,老公的妹妹穿的比我還像新娘挽牢。我一直安慰自己,他們只是感情好摊求,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布禽拔。 她就那樣靜靜地躺著,像睡著了一般室叉。 火紅的嫁衣襯著肌膚如雪睹栖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天茧痕,我揣著相機與錄音野来,去河邊找鬼。 笑死凿渊,一個胖子當著我的面吹牛梁只,可吹牛的內容都是我干的缚柳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼搪锣,長吁一口氣:“原來是場噩夢啊……” “哼秋忙!你這毒婦竟也來了?” 一聲冷哼從身側響起构舟,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤灰追,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后狗超,有當地人在樹林里發(fā)現(xiàn)了一具尸體弹澎,經...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年努咐,在試婚紗的時候發(fā)現(xiàn)自己被綠了苦蒿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡渗稍,死狀恐怖佩迟,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情竿屹,我是刑警寧澤报强,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站拱燃,受9級特大地震影響秉溉,放射性物質發(fā)生泄漏。R本人自食惡果不足惜碗誉,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一召嘶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧诗充,春花似錦苍蔬、人聲如沸诱建。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俺猿。三九已至茎匠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間押袍,已是汗流浹背诵冒。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谊惭,地道東北人汽馋。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓侮东,卻偏偏與公主長得像,于是被迫代替她去往敵國和親豹芯。 傳聞我的和親對象是個殘疾皇子悄雅,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內容