android Linker:namespace隔離機(jī)制

為了解決碎片化、升級慢問題,android從8.0開始推出了Project Treble計(jì)劃,詣在分離android framework和硬件驅(qū)動(dòng)的耦合,system分區(qū)只存放原生android相關(guān),vendor分區(qū)存放廠商相關(guān)定制。
主要通過HIDL、VNDK、SELinux來實(shí)現(xiàn)隔離,今天主要介紹VNDK相關(guān)的Linker namespace隔離機(jī)制。

VNDK

為了支持system分區(qū)可以升級到最新版本,而vendor分區(qū)保持不變,這意味著在不同時(shí)間編譯的二進(jìn)制文件必須能夠相互配合使用,因此vendor分區(qū)程序只能訪問system分區(qū)穩(wěn)定的動(dòng)態(tài)庫。

共享庫可分為以下三個(gè)子類別:

  • LL-NDK 庫:是已知穩(wěn)定的框架共享庫。它們的開發(fā)者致力于保持其 API/ABI 穩(wěn)定性。

    • LL-NDK 包含以下庫:libEGL.so、libGLESv1_CM.so、libGLESv2.so、libGLESv3.so、libandroid_net.so、libc.so、libdl.so、liblog.so、libm.so、libnativewindow.so、libneuralnetworks.so、libsync.so、libvndksupport.so 和 libvulkan.so。
  • VNDK 庫 (VNDK): 是指可以安全復(fù)制兩次的框架共享庫??蚣苣K和供應(yīng)商模塊可以與其各自的庫副本相關(guān)聯(lián)。

  • 框架專用庫 (FWK-ONLY) :被視為框架內(nèi)部實(shí)現(xiàn)細(xì)節(jié),不穩(wěn)定,不得由供應(yīng)商模塊訪問。

Same-Process HAL (SP-HAL):是一組預(yù)先確定的 HAL,作為供應(yīng)商共享庫進(jìn)行實(shí)現(xiàn),并被加載到框架進(jìn)程中。SP-HAL 由鏈接器命名空間進(jìn)行隔離。SP-HAL 必須僅依賴于 LL-NDK 和 VNDK-SP。
VNDK-SP:是一部分預(yù)定義的符合條件的 VNDK 庫。SP-HAL 和 VNDK-SP 均由 Google 定義。

Linker:namespace

Linker namespace解決了 Treble VNDK 設(shè)計(jì)中的兩個(gè)難題:

  • 將 SP-HAL 共享庫及其依賴項(xiàng)(包括 VNDK-SP 庫)加載到框架進(jìn)程中。這種情況下應(yīng)該有一些防止
    出現(xiàn)符號沖突的機(jī)制。
  • dlopen() 和 android_dlopen_ext() 可能會(huì)引入一些在編譯時(shí)不可見的運(yùn)行時(shí)依賴項(xiàng),這些依賴項(xiàng)使用
    靜態(tài)分析很難檢測到。

例如:
/system/lib/libcutils.so
/system/lib/vndk-sp/libcutils.so
這兩個(gè)庫可能有不同的符號。它們將加載到不同的鏈接器命名空間中,以便框架模塊可以依賴于 /system/lib/libcutils.so,SP-HAL 共享庫可以依賴于 /system/lib/vndk-sp/libcutils.so。
另一方面,比如libc.so 的依賴項(xiàng)libnetd_client.so被加載到libc.so 所在的命名空間中,其他命名空間將無法訪問這些依賴項(xiàng),可有效防止錯(cuò)綜的依賴。

Namespace實(shí)現(xiàn)原理

簡單來說就是用vector實(shí)現(xiàn)多個(gè)namespace功能的,沒有namespace的linker只有一個(gè)LSPath和ALList,啟用namespace后使用vector實(shí)現(xiàn)多個(gè)LSPath和ALList的相互隔離。

std::vector<android_namespace_t*> namespaces
std::vector<std::string> search_paths_;
soinfo_list_t soinfo_list_;

LSPath:搜索路徑(Library Search Path)
ALList:已加載庫列表(Alread Loaded Library list)


Namespace配置文件

ROM中配置文件位置:/system/etc/ld.config.txt、/system/etc/ld.config.vndk_lite.txt
配置說明:顧名思義,大部分配置即使不解釋也能明白用途,詳細(xì)解釋參考谷歌官方介紹https://source.android.google.cn/devices/architecture/vndk/linker-namespace

dir.system = /system/bin
dir.vendor = /vendor/bin

[system]
additional.namespaces = sphal

namespace.default.isolated = true  //true為僅加載搜索目錄下的庫,flase可以自行指定path
namespace.default.search.paths = /system/${LIB}:/vendor/${LIB} //不搜索子目錄
namespace.default.permitted.paths = /system/${LIB}:/vendor/${LIB} //搜索子目錄

namespace.sphal.isolated = true
namespace.sphal.visible = true    //visible 為 true,該程序?qū)⒛軌颢@取鏈接器命名空間句柄,該句柄隨后可傳遞到 android_dlopen_ext()。
namespace.sphal.search.paths = /vendor/${LIB}
namespace.sphal.links = default //如果無法加載到 sphal 命名空間,則動(dòng)態(tài)鏈接器會(huì)嘗試從 default 命名空間加載此共享庫。
namespace.sphal.link.default.shared_libs = libc.so:libm.so //如果請求的庫不是 libc.so、libm.so,則動(dòng)態(tài)鏈接器會(huì)忽略從 sphal 到 default 命名空間的鏈接。

[vendor]
namespace.default.isolated = false
namespace.default.search.paths = /vendor/${LIB}:/system/${LIB}
namespace.default.permitted.paths = /system/${LIB}/vndk-28

Namespace:system|vendor/bin

bin程序啟動(dòng)時(shí)linker會(huì)根據(jù)配置文件初始化namespace,得到默認(rèn)namespace:

static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
static const char* const kLdConfigVndkLiteFilePath = "/system/etc/ld.config.vndk_lite.txt";
//初始化namespace,從/proc/self/exe確定路徑
std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path);

so加載時(shí)調(diào)用的System.loadLibrary()、dlopen()、android_dlopen_ext()最終都走到do_dlopen():

  • void* caller_addr = __builtin_return_address(0);//得到當(dāng)前函數(shù)返回地址
  • soinfo* const caller = find_containing_library(caller_addr);//查找地址所在的動(dòng)態(tài)庫
  • android_namespace_t* ns = get_caller_namespace(caller);//ns為調(diào)用庫所在命名空間

也就是說新加載so的namespace與加載者保持一致。關(guān)鍵代碼如下:

void* dlopen(const char* filename, int flag) {
  const void* caller_addr = __builtin_return_address(0);//得到當(dāng)前函數(shù)返回地址
  return __loader_dlopen(filename, flag, caller_addr);
}

void* do_dlopen(const char* name, int flags,
                const android_dlextinfo* extinfo,
                const void* caller_addr) {
  soinfo* const caller = find_containing_library(caller_addr);//查找地址所在的動(dòng)態(tài)庫
  android_namespace_t* ns = get_caller_namespace(caller);//ns為調(diào)用庫所在命名空間

  soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);//根據(jù)ns來find
}
//根據(jù)ns來load
if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {
  return true;
}

struct soinfo {
  soinfo(android_namespace_t* ns, const char* name, const struct stat* file_stat,
         off64_t file_offset, int rtld_flags);
  android_namespace_t* primary_namespace_;
  android_namespace_list_t secondary_namespaces_;
}

Namespace:APK

System.loadLibrary()--> nativeLoad() -->Runtime.c::Runtime_nativeLoad()-->JVM_NativeLoad()-->Openjdkjvm.cc::JVM_NativeLoad()-->java_vm_ext.cc::LoadNativeLibrary()-->native_loader.cpp::OpenNativeLibrary()-->android_dlopen_ext()--> libdl.cpp::android_dlopen_ext()

System.loadLibrary()走到OpenNativeLibrary() 將創(chuàng)建一個(gè) classloader- namespace命名空間,并將它們鏈接到 default 命名空間。

static constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
const char* namespace_name = kClassloaderNamespaceName;

android_namespace_t* ns = android_create_namespace(namespace_name,
                                                 nullptr,
                                                 library_path.c_str(),
                                                 namespace_type,
                                                 permitted_path.c_str(),
                                                 parent_ns.get_android_ns());

if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) { //nullptr將取default namespace
*error_msg = dlerror();
return false;
}

//system_exposed_libraries
static constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] =
    "/etc/public.libraries.txt";
static constexpr const char kPublicNativeLibrariesVendorConfig[] =
    "/vendor/etc/public.libraries.txt";

apk namespace 補(bǔ)充

system APP可以訪問/system/lib,但是update后不能訪問。
必須訪問public.txt導(dǎo)出的庫,否則update后加載so將crash。

frameworks/base/core/java/android/app/LoadedApk.java:

boolean isBundledApp = mApplicationInfo.isSystemApp()
        && !mApplicationInfo.isUpdatedSystemApp();

if (isBundledApp) {
    libraryPermittedPath += File.pathSeparator
            + Paths.get(getAppDir()).getParent().toString();
    // This is necessary to grant bundled apps access to
    // libraries located in subdirectories of /system/lib
    libraryPermittedPath += File.pathSeparator + defaultSearchPaths;
}

VNDK升級架構(gòu)概覽

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,514評論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,373評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,743評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,199評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,414評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,951評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,780評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,218評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,673評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內(nèi)容