Põhjalik uurimine SDCardFS-ist, Google'i FUSE-i asendajast ja sellest, kuidas selle rakendamine vähendab sisend-väljundkulusid.
Mitu kuud tagasi lisas Google midagi nimega "SDCardFS” Linuxi kerneli ametlikesse AOSP filiaalidesse. Tol ajal märkas kolimist vaid mõned kerneli arendajad, kuid muidu lendas enamiku kasutajate radari alla. See pole üllatav, arvestades asjaolu, et enamik kasutajaid, sealhulgas mina, ei tea tegelikult, mis Android OS-i ja selle tuuma kapoti all toimub.
Kuid kõige värskem episood Androidi arendajad lava taga podcast taastas huvi selle teema vastu. Chet Haase (Google'i vanemtarkvarainsener) juhitud taskuhäälingusaade uuris hiljutisi ja tulevasi tuumas tehtud muudatusi. Saates oli Androidi meeskonnas töötav Linuxi tuuma arendaja Rom Lemarchand. Duo arutas peamiselt, milliseid muudatusi tehti A/B värskenduste vastuvõtmiseks, kuid jao viimase 5 minuti jooksul rääkis hr Lemarchand "järgmisest suurest asjast", mille kallal tema meeskond töötas - SDCardFS.
Pean tunnistama, et sain SDCardFS-i olemasolust teada pärast seda podcasti kuulamist. Muidugi polnud ma ainuke, kes selle teema vastu huvi tundis, kuna a
hiljutine Redditi lõim on näidanud. Siiski ei olnud ma rahul podcastis pakutud põhiseletusega ja püüdsin hajutada mõningaid valeinformatsiooni levimisel tegin ise mõned uuringud ja vestlesin mõne asjakohaste teadmistega eksperdiga asja.Suur tänu tarkvaraarendaja Michal Kowalczykile selle artikli valmimisse oma teadmiste panuse ja minu küsimustele vastamiseks aega leidmise eest.
"Väline" on tõesti sisemine
Kohe kohe on kindlasti mõned väärarusaamad, mille peame välja selgitama – vastasel juhul on ülejäänud artikkel väga segane. Kasulik on arutada SD-kaartide ja Android-telefonide ajalugu.
Android-telefonide algusaegadel kasutasid peaaegu kõik seadmed talletamiseks oma microSD-kaarte. See oli tingitud asjaolust, et telefonid tarniti sel ajal väikese sisemise mälumahuga. Kuid rakenduste salvestamiseks kasutatavad SD-kaardid ei paku sageli suurepäraseid kasutuskogemusi, vähemalt võrreldes kiirusega, millega sisemine välkmälu suudab andmeid lugeda/kirjutada. Seetõttu oli SD-kaartide sagenev kasutamine väliseks andmesalvestuseks saamas Google'i kasutajakogemuse probleemiks.
SD-kaartide varajase leviku tõttu väliste salvestusseadmetena põhinesid Androidi salvestuse nimetamise kokkulepped asjaolul, et igal seadmel oli tegelik, füüsiline microSD-kaardi pesa. Kuid isegi seadmetes, mis ei sisaldanud SD-kaardi pesa, kasutati /sdcard silti tegelikule sisemälukiibile osutamiseks. Segadust tekitab asjaolu, et seadmed, mis kasutasid salvestamiseks nii füüsilist SD-kaarti kui ka suure mahutavusega salvestuskiipi, nimetasid oma partitsioonid sageli SD-kaardi alusel. Näiteks nendes seadmetes viitaks /sdcard kinnituspunkt tegelikule sisemälukiibile, samas kui midagi nagu /storage/sdcard1 viitaks füüsilisele välisele kaardile.
Seega, kuigi microSD-kaarti peetakse praktiliselt välismäluseadmeks, põhjustas nimede andmise tava „SDCard” kleepumise juba ammu pärast füüsilise kaardi tegelikku kasutamist. See segadus salvestusruumiga valmistas ka rakenduste arendajatele peavalu, kuna rakenduse andmed ja selle meedium olid kahe partitsiooni vahel eraldatud.
Varasemate sisemälukiipide vähese salvestusruumi tõttu said kasutajad pettumuslikult teada, et nad ei saa enam rakendusi installida (seoses /data partitsioonist on täis). Vahepeal jäeti nende suurema mahutavusega microSD-kaardid ainult meediumite (nt fotod, muusika ja filmid) hoidmisele. Kasutajad, kes omal ajal meie foorumeid sirvisid, võivad mäletada neid nimesid: Link2SD ja Apps2SD. Need olid (juur)lahendused, mis võimaldasid kasutajatel installida oma rakendused ja selle andmed füüsilisele SD-kaardile. Kuid need polnud kaugeltki täiuslikud lahendused, nii et Google pidi sekkuma.
Kuulsalt tõmbas Google SD-kaartide pistiku juba varakult lahti. Nexus One jääb ainsaks Nexuse seadmeks, millel on microSD-kaardi pesa (ja see jääb igaveseks, kuna Nexuse bränd on tegelikult surnud). Nexus S-ga oli nüüd ainult üks ühtne partitsioon kõigi rakenduste andmete ja meediumide salvestamiseks – partitsioon /data. See, mida kunagi nimetati /sdcard ühenduspunktiks, viitas nüüd lihtsalt virtuaalsele failisüsteemile (rakendatud FUSE protokoll, nagu allpool kirjeldatud), mis asub andmesektsioonis - /data/media/0.
Ühilduvuse säilitamiseks ja segaduse vähendamiseks kasutas Google meediumite hoidmiseks siiski seda nüüdseks muutunud virtuaalset sdcard partitsiooni. Kuid nüüd, kui see "sdcard" virtuaalne partitsioon asus tegelikult jaotises /data, läheb kõik sellesse salvestatud sisemälukiibi salvestusruumi hulka. Seega oli originaalseadmete tootjate ülesanne kaaluda, kui palju ruumi eraldada rakendustele (/data) versus meediumile (/data/media).
Google lootis, et tootjad järgivad nende eeskuju ja vabanevad SD-kaartidest. Õnneks suutsid telefonitootjad aja jooksul hankida need komponendid suurema võimsusega, jäädes samas kulutõhusaks, nii et vajadus SD-kaartide järele hakkas vähenema. Kuid nimetamisreeglid on püsinud, et vähendada pingutusi, mida arendajad ja originaalseadmete tootjad peavad kohanemiseks tegema. Praegu, kui me viitame "välisele salvestusruumile", peame silmas kas üks kahest asjast: tegelik eemaldatav microSD-kaart või virtuaalne "SDCardi" partitsioon, mis asub kaustas /data/media. Neist viimane praktiliselt öeldes on tegelikult sisemälu, kuid Google'i nimede andmise tava eristab seda asjaolu tõttu, et need andmed on kasutajale juurdepääsetavad (nt arvutiga ühendatud).
Praegu, kui me viitame "välisele salvestusruumile", peame silmas kas üks kahest asjast: tegelik eemaldatav microSD-kaart või virtuaalne "SDCardi" partitsioon, mis asub kaustas /data/media.
Androidi virtuaalsete failisüsteemide ajalugu
Nüüd, kui SD-kaarti käsitletakse virtuaalse failisüsteemina, tähendas see, et seda saab vormindada mis tahes failisüsteemina, mida Google soovib. Alates Nexus S-ist ja Android 2.3-st otsustas Google vormindada SD-kaardi VFAT-iks (virtuaalne FAT). See samm oli tol ajal mõistlik, kuna VFAT-i paigaldamine võimaldas peaaegu igal arvutil juurdepääsu teie telefoni salvestatud andmetele. Selle esialgse rakendamisega oli aga kaks peamist probleemi.
Esimene puudutab eelkõige lõppkasutajat (teid). Seadme arvutiga ühendamiseks peaksite andmete edastamiseks kasutama USB-massmälurežiimi. See aga nõudis Android-seadmelt virtuaalse partitsiooni lahtiühendamist, enne kui arvuti pääses andmetele juurde. Kui kasutaja soovib oma seadet kasutada, kui see on ühendatud, kuvatakse paljud asjad kättesaamatuks.
The meediaedastusprotokolli kasutuselevõtt (MTP) lahendas selle esimese probleemi. Kui see on ühendatud, näeb arvuti teie seadet "meediumisalvestusseadmena". See küsib teie telefonist failide loendit ja MTP tagastab failide loendi, mida arvuti saab seadmest alla laadida. Kui faili palutakse kustutada, saadab MTP käsu soovitud faili salvestusruumist eemaldamiseks. Erinevalt USB-massmälurežiimist, mis tegelikult ühendab SD-kaardi, võimaldab MTP kasutajal jätkata oma seadme kasutamist, kui see on ühendatud. Lisaks pole Android-telefonis olev failisüsteem enam oluline, et arvuti seadmes olevaid faile ära tunneks.
Teiseks oli tõsiasi, et VFAT ei pakkunud sellist tugevat lubade haldust, mida Google vajas. Varakult käsitlesid paljud rakenduste arendajad SD-kaarti oma rakenduse andmete prügimäena, ilma ühtse arusaamata, kuhu oma faile salvestada. Paljud rakendused loovad lihtsalt oma rakenduse nimega kausta ja salvestavad selle failid sinna.
Peaaegu iga toonane rakendus nõudis seda WRITE_EXTERNAL_STORAGE luba kirjutada oma rakendusfailid välismällu. Veelgi murettekitavam oli aga asjaolu, et peaaegu iga rakendus nõudis ka seda READ_EXTERNAL_STORAGE luba - lihtsalt oma andmefailide lugemiseks! See tähendas, et rakendustel oli lihtne juurdepääs andmetele, mis on salvestatud kõikjal välismälu, ja sellise loa andis sageli kasutaja, kuna see oli paljude rakenduste jaoks vajalik funktsiooni.
Google pidas seda selgelt problemaatiliseks. Kogu lubade haldamise idee seisneb eraldades, millele rakendused saavad juurdepääsu ja millele mitte. Kui peaaegu igale rakendusele antakse lugemisõigus potentsiaalselt tundlikele kasutajaandmetele, on luba mõttetu. Seega otsustas Google, et neil on vaja uut lähenemist. See on koht, kus FUSE tuleb sisse.
Failisüsteem kasutajaruumis (FUSE)
Alates Android 4.4-st otsustas Google enam virtuaalset "sdcard" partitsiooni VFAT-ina mitte ühendada. Selle asemel hakkas Google kasutama FUSE-d FAT32 emuleerimiseks sdcard virtuaalse partitsioonil. sdcard-programmiga helistades FUSE emuleerida FAT-on-sdcard stiilis kataloogi õigusi, võivad rakendused alustada juurdepääsu välisele salvestusruumile salvestatud andmetele ilma lubadeta. Tõepoolest, alates API tasemest 19 ei olnud READ_EXTERNAL_STORAGE enam vajalik, et pääseda juurde failidele, mis asuvad välismälus – eeldusel, et FUSE deemoni loodud andmekaust vastab rakenduse paketi nimele. FUSE saaks hakkama välismälu failide omaniku, rühma ja režiimide sünteesimine kui rakendus on installitud.
FUSE erineb tuumasisestest moodulitest, kuna see võimaldab mitteprivilegeeritud kasutajatel kirjutada virtuaalseid failisüsteeme. Põhjus, miks Google FUSE kasutusele võttis, on üsna lihtne – see tegi seda, mida nad tahtsid ja juba tegid hästi mõistetav ja dokumenteeritud Linuxi maailmas. Tsiteerides a Google'i arendaja selles küsimuses:
"Kuna FUSE on kena stabiilne API, ei vaja kerneli versioonide vahel liikumisel hooldustööd sisuliselt null. Kui me läheksime üle kernelisisesele lahendusele, oleksime registreerunud iga stabiilse kerneli versiooni jaoks plaastrite komplekti hooldamiseks." -Jeff Sharkey, Google'i tarkvarainsener
Siiski sai üsna selgeks, et FUSE üldkulud tekitasid muude probleemide hulgas jõudluses löögi. Arendaja, kellega sellel teemal rääkisin, Michal Kowalczyk, kirjutas suurepärase blogipostituse rohkem kui aasta tagasi, kirjeldades üksikasjalikult FUSE praegusi probleeme. Rohkem tehnilisi üksikasju saab lugeda tema blogist, kuid ma kirjeldan tema leide (tema loal) võhiklikumalt.
Probleem FUSE-ga
Androidis kasutab "sdcard" kasutajaruumi deemon FUSE-d, et ühendada /dev/fuse alglaadimisel emuleeritud välismälukataloogi. Pärast seda küsib sdcardi deemon FUSE-seadmelt kõiki kerneli ootelolevaid sõnumeid. Kui kuulasite taskuhäälingusaadet, oleksite võib-olla kuulnud, et hr Lemarchand viitas FUSE-le, mis lisab sisend- ja väljundoperatsioonide ajal üldkulusid – siin on sisuliselt see, mis juhtub.
Reaalses maailmas mõjutab see jõudlushitt ükskõik milline välismälu salvestatud fail.
Probleem nr 1 – I/O üldkulud
Oletame, et loome lihtsa tekstifaili nimega "test.txt" ja salvestame selle faili /sdcard/test.txt (mis, olgu tuletan teile meelde, et tegelikult on /data/media/0/test.txt, eeldades, et praegune kasutaja on põhikasutaja seade). Kui sooviksime seda faili lugeda (käsku anda), siis eeldame, et süsteem annab välja 3 käsku: ava, loe, siis sulge. Tõepoolest, nagu hr Kowalczyk kasutamist demonstreerib jälg, see juhtubki:
Kuid kuna fail asub välismälus, mida haldab sdcardi deemon, tuleb teha palju lisatoiminguid. Hr Kowalczyki sõnul on selleks vaja sisuliselt 8 täiendavat sammu igaüks neist 3 individuaalsest käsust:
- Userspace'i rakendus annab välja süsteemikutse, mida haldab tuumas olev FUSE draiver (näeme seda esimeses strace väljundis)
- Kerneli FUSE draiver teavitab kasutajaruumi deemonit (sdcard) uuest taotlusest
- Kasutajaruumi deemon loeb /dev/fuse
- Userspace deemon parsib käsku ja tuvastab failitoimingud (nt. avatud)
- Userspace deemon väljastab süsteemikutse tegelikule failisüsteemile (EXT4)
- Kernel haldab füüsilist juurdepääsu andmetele ja saadab andmed kasutajaruumi tagasi
- Userspace muudab (või mitte) andmeid ja edastab need läbi /dev/fuse uuesti kernelile
- Kernel lõpetab algse süsteemikutse ja teisaldab andmed tegelikku kasutajaruumi rakendusse (meie näites cat)
See tundub olevat palju üldkuludest vaid ühele käivitatavale I/O-käsule. Ja sul oleks õigus. Selle demonstreerimiseks proovis hr Kowalczyk kahte erinevat I/O testi: üks hõlmas suure faili kopeerimist ja teine paljude väikeste failide kopeerimist. Ta võrdles neid toiminguid haldava FUSE (virtuaalsel partitsioonil, mis on ühendatud FAT32-ga) kiirust kernel (andmesektsioonil, mis on vormindatud kui EXT4) ja ta leidis, et FUSE andis tõepoolest märkimisväärse panuse pea kohal.
Esimeses testis kopeeris ta mõlemas katsetingimustes 725 MB faili. Ta leidis, et FUSE rakendus edastas suuri faile 17% aeglasemalt.
Teises testis kopeeris ta 10 000 faili – igaüks neist 5 KB suurune. Selle stsenaariumi korral oli FUSE rakendamine lõppenud 40 sekundit aeglasem põhiliselt 50 MB väärtuses andmete kopeerimiseks.
Reaalses maailmas mõjutab see jõudlushitt ükskõik milline välismälu salvestatud fail. See tähendab selliseid rakendusi nagu Maps, mis salvestab suuri faile /sdcardile, muusikarakendusi, mis salvestavad palju muusikafaile, kaamerarakendusi ja fotosid jne. Kõik sisend-/väljundtoimingud, mis hõlmavad välist salvestusruumi, on mõjutatud FUSE-i üldkulud. Kuid I/O üldkulud pole FUSE'i ainus probleem.
Probleem nr 2 – topeltvahemällu salvestamine
Andmete vahemällu salvestamine on andmetele juurdepääsu parandamiseks oluline. Olulisi andmeid mällu salvestades suudab Linuxi kernel need andmed vajaduse korral kiiresti meelde tuletada. Kuid FUSE rakendamise viisi tõttu salvestab Android kahekordselt vajaliku vahemälu.
Nagu hr Kowalczyk näitab, salvestatakse 10 MB fail vahemällu täpselt 10 MB, kuid selle asemel suurendatakse vahemälu suurust umbes 20 MB võrra. See on problemaatiline seadmetes, millel on vähem RAM-i, kuna Linuxi kerneli poed kasutavad andmete salvestamiseks lehe vahemälu mälu. Hr Kowalczyk testis seda topeltvahemällu salvestamise probleemi, kasutades järgmist lähenemisviisi:
- Looge teadaoleva suurusega fail (testimiseks, 10 MB)
- Kopeerige see kausta /sdcard
- Tühjendage lehe vahemälu
- Tehke lehe vahemälu kasutamisest ülevaade
- Lugege testifaili
- Tehke veel üks hetktõmmis lehe vahemälu kasutamisest
Ta leidis, et enne testimist kasutas kernel lehe vahemälu jaoks 241 MB. Kui ta oma testfaili luges, eeldas ta, et lehe vahemälu jaoks kasutatakse 251 MB. Selle asemel leidis ta, et see kernel kasutas 263 MBs lehe vahemälu jaoks - umbes kaks korda oodatust. Selle põhjuseks on asjaolu, et andmed salvestab esmalt vahemällu kasutajarakendus, mis algselt I/O-kõne (FUSE) väljastas, ja teiseks sdcardi deemon (EXT4 FS).
Probleem nr 3 – FAT32 mittetäielik rakendamine
FAT32 emuleeriva FUSE kasutamisest tulenevad veel kaks probleemi, mis on Androidi kogukonnas vähem tuntud.
Esimene hõlmab valed ajatemplid. Kui olete kunagi faili (nt foto) edastanud ja märkasite, et ajatempel on vale, on põhjuseks FUSE rakendus Androidis. Sellel teemal on jaoks eksisteeris aastat. Täpsemalt hõlmab probleem järgmist utime() süsteemikutse, mis võimaldab teil muuta failile juurdepääsu ja muutmise aega. Kahjuks ei ole sdcardi deemonile kui tavakasutajale tehtud kõnedel selle süsteemikutse täitmiseks nõuetekohast luba. Selle jaoks on lahendusi, kuid need nõuavad teilt seda omama juurjuurdepääsu.
Kui olete kunagi faili (nt foto) edastanud ja märkasite, et ajatempel on vale, on põhjuseks FUSE rakendus Androidis.
Järgmine probleem on rohkem murettekitav ettevõtetele, kes kasutavad midagi sellist smartSD kaart. Enne FUSE-i said rakenduste tegijad seda jälgida O_DIRECT lipp et suhelda kaardi sisseehitatud mikrokontrolleriga. FUSE abil pääsevad arendajad juurde ainult faili vahemällu salvestatud versioonile ega näe mikrokontrolleri saadetud käske. See on problemaatiline mõnede ettevõtete/valitsuse/pangandusrakenduste puhul, mis suhtlevad lisandväärtusega microSD-kaartidega.
SDCardFS-i jaoks eemaldatakse FUSE
Mõned originaalseadmete tootjad mõistsid need probleemid varakult ja hakkasid otsima tuumasisest lahendust FUSE asendamiseks. Näiteks Samsung arendas SDCardFS mis põhineb WrapFS-il. See kernelisisene lahendus emuleerib FAT32 täpselt nagu FUSE, kuid loobub I/O üldkuludest, topeltvahemällu salvestamisest ja muudest ülalmainitud probleemidest. (Jah, lubage mul seda punkti korrata, see lahendus, mida Google praegu rakendab, põhineb Samsungi tööl).
Google ise on lõpuks tunnistanud FUSE-ga seotud puudusi, mistõttu on nad hakanud liikuma Samsungi väljatöötatud kernelisisese FAT32 emulatsioonikihi poole. Ettevõte, nagu on mainitud Androidi arendajad lava taga podcast, on töötanud selle nimel, et teha SDCardFS kättesaadavaks kõigi seadmete jaoks kerneli tulevases versioonis. Praegu näete nende edenemist töö AOSP-s.
Nagu Google'i arendaja selgitas varem, on kernelisisese lahenduse juurutamise suurim väljakutse paketi nime vastendamine rakenduse ID, mis on vajalik paketi jaoks, et pääseda juurde oma andmetele välises salvestusruumis, ilma et see seda nõuaks load. Kuid see avaldus tehti aasta tagasi ja oleme jõudnud punkti, kus meeskond nimetab SDCardFS-i oma "järgmiseks suureks asjaks". Nad on juba kinnitanud, et kardetud ajatempli viga on tänu FUSE-st lahkumisele parandatud, nii et võime oodata kõiki FUSE-st loobumisega kaasnevaid muudatusi.
Faktikontrolli väärarusaamad
Kui olete artikliga nii kaugele jõudnud, siis aitäh, et olete seni kõigega kursis olnud! Tahtsin selgitada mõningaid küsimusi, mis mul seda artiklit kirjutades tekkisid:
- SDCardFS on tegelike SD-kaartidega pole midagi pistmist. Seda nimetatakse lihtsalt selliseks, kuna see haldab / sdcardi sisend-/väljundpääsu. Ja nagu mäletate, on /sdcard aegunud silt, mis viitab teie seadme „välisele” salvestusruumile (kuhu rakendused oma meediume salvestavad).
- SDCardFS on mitte traditsiooniline failisüsteem nagu FAT32, EXT4 või F2FS. See on virnastatav ümbrisfailisüsteem, mis edastab käsud madalamatele, emuleeritud failisüsteemidele (antud juhul oleks see /sdcardil FAT32).
- MTP-ga seoses ei muutu midagi. Jätkate failide arvutisse/arvutist ülekandmiseks MTP-d (kuni Google otsustab parema protokolli). Aga vähemalt ajatempli viga parandatakse!
- Nagu varem mainitud, siis kui Google viitab välisele salvestusruumile, siis räägivad nad kas (kõikide kavatsuste ja sisemine / sdcard virtuaalne FAT32 partitsioon VÕI nad räägivad tegelikust füüsilisest eemaldatavast microSD-st kaardile. Terminoloogia on segane, kuid see on see, mis meid tabab.
Järeldus
FUSE-st eemaldudes ja tuumasisest FAT32 emulatsioonikihi (SDCardFS) juurutades vähendab Google märkimisväärne sisend-/väljundkulu, välistades topelt vahemällu salvestamise ja lahendades mõned ebaselged probleemid, mis on seotud selle FUSE emuleerimisega. FAT32.
Kuna need muudatused tehakse tuumas, saab need kasutusele võtta ilma Androidi uue suurema versioonita. Mõned kasutajad eeldavad, et need muudatused rakendatakse ametlikult Android 8-s, kuid see on võimalik mis tahes tulevase Pixeli seadme OTA jaoks, et tuua Linuxi kerneli versioon 4.1, mida Google on töötanud peal.
Mõne jaoks pole SDCardFS uus kontseptsioon. Tegelikult on Samsungi seadmed seda juba aastaid kasutanud (lõpuks olid nemad selle välja töötanud). Alates sellest, kui SDCardFS eelmisel aastal AOSP-s kasutusele võeti, on mõned kohandatud ROM-i ja kerneli arendajad otsustanud selle oma töösse juurutada. CyanogenMOD kaalus ühel hetkel selle rakendamist, kuid tühistas selle, kui kasutajatel tekkis fotodega probleeme. Kuid loodetavasti saavad Google'i selle projekti valitsemise ajal kõigi tulevaste seadmete Androidi kasutajad ära kasutada FUSE-i loobumisega kaasnevaid täiustusi.