Android存儲(chǔ)挖坑記 (轉(zhuǎn))

Android存儲(chǔ)挖坑記

[URL](http://blog.desmondyao.com/2016/05/04/android-storage/) 

最近在搞Android存儲(chǔ)相關(guān)的業(yè)務(wù)幔嗦,什么Internal/External/Primary/Secondary搞得我都看懵了虎敦,國(guó)內(nèi)也沒(méi)什么好的文章系統(tǒng)的講這個(gè)仿粹,我就挖挖各類(lèi)資料搁吓,整理一下原茅。

  1. Internal vs External
    對(duì)于Internal Storage 與 External Storage吭历,官方文檔上有這么一段話,描述得很詳細(xì)了擂橘,我翻譯了一段下來(lái):

所有的Android設(shè)備都有兩塊存儲(chǔ)區(qū)域:Internal Storage和External Storage晌区。它們的名稱(chēng)來(lái)源于早期的Android系統(tǒng),那時(shí)候大家的手機(jī)都內(nèi)置(Permanent)一塊較小存儲(chǔ)板(即Internal Storage)通贞,并配上一個(gè)的外置的(Removable)儲(chǔ)存卡(即External Storage)朗若。后來(lái)部分手機(jī)開(kāi)始將最初定義的“Internal Storage”,即內(nèi)置存儲(chǔ)昌罩,分成Internal和External兩部分哭懈。這樣一來(lái)就算沒(méi)有外置儲(chǔ)存,手機(jī)也有Internal和External兩塊存儲(chǔ)區(qū)域茎用。這兩塊存儲(chǔ)區(qū)域的區(qū)別是:

Internal Storage External Storage
可信度 永遠(yuǎn)可用(Permanent) 可能不可用遣总,最典型的當(dāng)設(shè)備作為USB存儲(chǔ)被mount時(shí)不可用

訪問(wèn)權(quán)限 App存儲(chǔ)內(nèi)容僅App本身(或共享uid的App)可訪問(wèn)(Root除外 App存儲(chǔ)內(nèi)容全局可讀

內(nèi)容持久 App存儲(chǔ)內(nèi)容隨App卸載而消失 當(dāng)App卸載時(shí),只有存在getExternalFilesDir()路徑下的文件會(huì)消失

適應(yīng)情況
存儲(chǔ)內(nèi)容僅App自己訪問(wèn)時(shí)的最佳選擇
存儲(chǔ)內(nèi)容希望與其他App共享或傳到電腦上轨功,但是不想申請(qǐng)任何權(quán)限時(shí)的最佳選擇

注:此處討論的訪問(wèn)權(quán)限是應(yīng)用路徑下的權(quán)限旭斥。

總結(jié)下來(lái),External存儲(chǔ)區(qū)域有幾個(gè)好處:

  1. 可以傳到電腦上古涧;
  2. 可以與其他app共享垂券;
  3. 在4.4之后的App路徑(Android/data/包名)下讀寫(xiě)不需任何權(quán)限;
  4. 存在App路徑之外的文件不會(huì)隨App卸載羡滑。

相應(yīng)的菇爪,也有幾個(gè)缺點(diǎn):

  1. 可能不可用;
  2. 會(huì)被其他應(yīng)用讀到;
  3. 在非App路徑下寫(xiě)柒昏、修改文件需要權(quán)限凳宙。

1.1 External Storage的權(quán)限
在Internal Storage的App路徑下(/data/data/包名下),App的讀寫(xiě)操作無(wú)需任何權(quán)限昙楚,我們只需要總結(jié)一下External Storage的情況:
Android版本讀寫(xiě)

4.4以下
無(wú)需權(quán)限
需要申請(qǐng)WRITE_EXTERNAL_STORAGE

4.4及以上
無(wú)需權(quán)限
在App目錄之外寫(xiě)近速,需要申請(qǐng)WRITE_EXTERNAL_STORAGE

關(guān)于讀External的權(quán)限,在Android Developer上有這樣一段話:
目前堪旧,所有App都可以讀External存儲(chǔ)而不需要任何權(quán)限削葱,這一點(diǎn)可能會(huì)在未來(lái)做出改變。如果你希望讀External存儲(chǔ)淳梦,那最好申請(qǐng)一下READ_EXTERNAL_STORAGE
權(quán)限析砸。另外,寫(xiě)權(quán)限已經(jīng)默認(rèn)包含了讀權(quán)限了爆袍。

正常情況下首繁,你用任何文件管理器作郭,點(diǎn)開(kāi)的根目錄就是你的External存儲(chǔ)。你可以到它下面的應(yīng)用目錄弦疮,你會(huì)發(fā)現(xiàn)夹攒,就算是各個(gè)包名下的文件,你也是看得到的胁塞。

1.2 多用戶
在4.2及以上的Android系統(tǒng)中引入了多用戶機(jī)制咏尝。你可能會(huì)發(fā)現(xiàn)在存儲(chǔ)路徑后面有’0’/‘1’的字樣(如/storage/emulated/0/),這后面的數(shù)字表示用戶啸罢。主用戶后面為0编检。

  1. Primary vs Secondary
    這個(gè)Primary和Secondary是怎么來(lái)的呢?實(shí)際上最開(kāi)始Android也沒(méi)有考慮這個(gè)區(qū)分扰才,但是后來(lái)有一個(gè)情況發(fā)生了允懂,就是上面所說(shuō)到的:
    后來(lái)部分手機(jī)開(kāi)始將最初定義的“Internal Storage”,即內(nèi)置存儲(chǔ)衩匣,分成Internal和External兩部分蕾总。

那么如果這個(gè)時(shí)候手機(jī)再插入sd卡,那不是有多個(gè)External Storage了嗎舵揭?
這個(gè)時(shí)候谤专,從Internal Storage里面分出來(lái)的那塊“External Storage”我們稱(chēng)之為主存儲(chǔ)(Primary Storage),插入的外置儲(chǔ)存稱(chēng)之為副存儲(chǔ)(Secondary Storage)午绳。
主存儲(chǔ)路徑的獲取方式非常簡(jiǎn)單置侍,可以通過(guò)Environment.getExternalStorageDirectory()
或者Context.getExternalFilesDir(null)
來(lái)獲取。
副存儲(chǔ)路徑在4.4及以上的Android系統(tǒng)中拦焚,可以使用Context.getExternalFilesDirs(null)(注意最后多了一個(gè)’s’)蜡坊,它返回的是一個(gè)字符串?dāng)?shù)組。第0個(gè)就是主存儲(chǔ)路徑赎败,第1個(gè)是副存儲(chǔ)路徑(如果有的話)秕衙。
4.4及以下系統(tǒng)中,的副存儲(chǔ)的獲取方式就是一個(gè)大坑了僵刮,一個(gè)一個(gè)介紹一下筆者看到過(guò)的方法据忘。

2.1 副儲(chǔ)存路徑-StorageManager
在Android中可以通過(guò)context.getSystemService(STORAGE_SERVICE)
來(lái)獲取到StorageManager
,但是很可惜的是搞糕,它里面有價(jià)值的方法都是hide的勇吊。。
慶幸的是還有反射窍仰。我們可以調(diào)用getVolumeList()
函數(shù)汉规,這個(gè)返回的List里面,主存儲(chǔ)是第0個(gè)驹吮,副存儲(chǔ)(如果有的話)是第1個(gè)针史。你可以看到Environment.getExternalStorageDirectory()
里面就是用它實(shí)現(xiàn)的晶伦,可以說(shuō)這個(gè)方法是目前最穩(wěn)妥的。它通過(guò)系統(tǒng)的MountService來(lái)獲取已mount上來(lái)的設(shè)備啄枕,并且能夠通過(guò)StorageVolume
知道該存儲(chǔ)是否removable婚陪、是否是emulated、mount狀態(tài)等等射亏。
涉及到存儲(chǔ)近忙,由于Android rom千奇百怪,不可能是萬(wàn)全的智润。如果反射出來(lái)的方法缺少變量、方法未辆,或者有別的什么坑窟绷,那只能試一下其他方法來(lái)保底。
靠譜程度:99%

2.2 副存儲(chǔ)路徑-讀配置xml
讀com.android.internal.R.xml.storage_list.xml可以獲取到系統(tǒng)的VolumeList咐柜,但是這種方法是行不通的兼蜈,我們可以從源碼中看看。
在6.0以前的MountService上面看到readStorageList()
這個(gè)函數(shù)拙友,它在構(gòu)造函數(shù)里面就會(huì)被調(diào)用为狸,就是在讀取這個(gè)xml文件。但是我們可以看到它并沒(méi)有在Volume改變的時(shí)候被動(dòng)態(tài)寫(xiě)入遗契。
并且參考AOSP Document,這個(gè)xml文件里面存儲(chǔ)的就是廠商配置的分區(qū)辐棒,它根本無(wú)法更新removable存儲(chǔ)的熱插拔信息
注意:這個(gè)xml在6.0被移除了(參考AOSP Document)

靠譜程度:0%

2.3 副存儲(chǔ)路徑-mount命令
執(zhí)行Linux shell下的mount命令牍蜂,遍歷每個(gè)mount點(diǎn)漾根,從中找到副存儲(chǔ)。
目前鲫竞,它確實(shí)能夠列出副存儲(chǔ)辐怕。但是同時(shí)會(huì)列出很多很多mount點(diǎn),包括系統(tǒng)mount點(diǎn)从绘,目前好像沒(méi)有已知的靠譜方法能夠從中準(zhǔn)確找出副存儲(chǔ)寄疏。副存儲(chǔ)的命名是沒(méi)有規(guī)律的,枚舉排除系統(tǒng)mount點(diǎn)的方法不能夠100%確保準(zhǔn)確性僵井。
靠譜程度:10%

2.4 副存儲(chǔ)路徑-讀vold.fstab文件
解析/etc/void.fstab陕截,從中找到副存儲(chǔ)位置。
Vold(Volume Daemon)是ServiceManager與kernel層之間的橋梁驹沿,它對(duì)于Volume的信息維護(hù)在/etc/vold.fstab中艘策。
一聽(tīng)就是一個(gè)奇怪的方法,文件位置渊季、信息也可能被各類(lèi)廠商篡改朋蔫,還可能存在瞬時(shí)不一致的情況罚渐,不要考慮它。有興趣的同學(xué)可以研究一下android-storage-vold驯妄。
靠譜程度:0%

總結(jié)
總結(jié)出Android手機(jī)目前的幾種存儲(chǔ)方式:

在6.0之前
6.0之前荷并,所有的存儲(chǔ)類(lèi)型都是Traditional Storage。它支持多用戶青扔、模擬External存儲(chǔ)源织。由于是MBR分區(qū),存儲(chǔ)上線為2TB微猖。
Physical Primary 最原始的樣子是只有機(jī)身自帶的Internal存儲(chǔ)和以External存在的外置存儲(chǔ)谈息,這時(shí)候只有一個(gè)主存儲(chǔ),并且它是Physical的凛剥。

Emulated Primary (Optional Physical Secondary) 之前所說(shuō)侠仇,從Internal Storage分出一塊來(lái)給External Storage。這塊存儲(chǔ)空間就是在Permanent存儲(chǔ)版中”模擬“上去的犁珠。所以你可以看到主存儲(chǔ)經(jīng)常有emulated
字樣逻炊。 如果這時(shí)候還能再插SD卡,則會(huì)多一個(gè)Physical的Secondary存儲(chǔ)犁享。

在6.0之后
正常情況下余素,它的存儲(chǔ)方式與之前的兩種相同,不過(guò)多了一種新的存儲(chǔ)方式:Adoptable Storage

Adoptable Storage
由于External Storage的缺點(diǎn)(有時(shí)不可用炊昆,存儲(chǔ)內(nèi)容沒(méi)有被保護(hù))桨吊,在6.0之后多出了Adoptable存儲(chǔ)方式。
當(dāng)Android系統(tǒng)Adopt了一塊External存儲(chǔ)區(qū)域的時(shí)候窑眯,它會(huì)被視為Internal Storage屏积,同時(shí)會(huì)被格式化與加密。格式化之后是GPT分區(qū)磅甩,存儲(chǔ)上線為9ZB炊林。
當(dāng)你在一個(gè)支持Adoptable Storage的手機(jī)上插入一個(gè)sd卡,它會(huì)提示你是否將這個(gè)sd卡格式化并用作Internal Storage卷要,或者正常作為External Storage使用渣聚。
推薦一篇文章:
CommonsWare’s post,從不同角度詮釋了Internal&External Storage僧叉, 非常不錯(cuò)奕枝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瓶堕,隨后出現(xiàn)的幾起案子隘道,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谭梗,死亡現(xiàn)場(chǎng)離奇詭異忘晤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)激捏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)设塔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人远舅,你說(shuō)我怎么就攤上這事闰蛔。” “怎么了图柏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵序六,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我爆办,道長(zhǎng)难咕,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任距辆,我火速辦了婚禮,結(jié)果婚禮上暮刃,老公的妹妹穿的比我還像新娘跨算。我一直安慰自己,他們只是感情好椭懊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布诸蚕。 她就那樣靜靜地躺著,像睡著了一般氧猬。 火紅的嫁衣襯著肌膚如雪背犯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天盅抚,我揣著相機(jī)與錄音漠魏,去河邊找鬼。 笑死妄均,一個(gè)胖子當(dāng)著我的面吹牛柱锹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丰包,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼禁熏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了邑彪?” 一聲冷哼從身側(cè)響起瞧毙,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后宙彪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體矩动,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年您访,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铅忿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灵汪,死狀恐怖檀训,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情享言,我是刑警寧澤峻凫,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站览露,受9級(jí)特大地震影響荧琼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜差牛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一命锄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧偏化,春花似錦脐恩、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至韵卤,卻和暖如春骗污,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沈条。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工需忿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拍鲤。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓贴谎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親季稳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子擅这,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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