Ponořte se do SDCardFS: Jak výměna FUSE od společnosti Google sníží režii I/O

click fraud protection

Hloubkový průzkum SDCardFS, náhrady společnosti Google za FUSE, a toho, jak její implementace sníží režii I/O.

Před několika měsíci Google přidal něco s názvem „SDCardFS” do oficiálních větví AOSP pro linuxové jádro. V té době si tohoto kroku všiml pouze někteří vývojáři jádra, ale jinak letěl pod radarem většiny uživatelů. Není divu, když vezmeme v úvahu skutečnost, že většina uživatelů, včetně mě, vlastně neví, co se děje pod poklicí operačního systému Android a jeho jádra.

Nicméně, nejnovější epizoda Android Developers Backstage podcast obnovil zájem o toto téma. Podcast, který hostil Chet Haase (starší softwarový inženýr ve společnosti Google), prozkoumal nedávné a nadcházející změny v jádře. Na výstavě byl vývojář linuxového jádra pracující na týmu Android - Rom Lemarchand. Duo primárně diskutovalo o tom, jaké změny byly provedeny, aby vyhovovaly aktualizacím A/B, ale v posledních 5 minutách epizody pan Lemarchand hovořil o „další velké věci“, na které jeho tým pracoval – SDCardFS.

Musím přiznat, že o existenci SDCardFS jsem se dozvěděl až po poslechu tohoto podcastu. Samozřejmě jsem nebyl jediný, koho toto téma zajímalo, jako a

nedávné vlákno na Redditu ukázal. Nebyl jsem však spokojen se základním vysvětlením, které bylo v podcastu nabídnuto, a ve snaze rozptýlit některé z dezinformace se šíří kolem, udělal jsem si vlastní průzkum a promluvil jsem s několika odborníky s relevantními znalostmi o této problematice hmota.

Velké poděkování patří vývojáři softwaru Michalu Kowalczykovi za to, že přispěl svými znalostmi k tomuto článku a že si udělal čas na zodpovězení mých otázek.


"Externí" je skutečně vnitřní

Hned ze začátku se jistě vyskytnou nějaké mylné představy, které musíme vyjasnit – jinak bude zbytek článku velmi matoucí. Je užitečné diskutovat o historii SD karet a telefonů Android.

V počátcích telefonů s Androidem se téměř každé zařízení spoléhalo na to, že pro ukládání používá své microSD karty. To bylo způsobeno skutečností, že telefony v té době byly dodávány s minimem vnitřních úložných kapacit. SD karty používané pro ukládání aplikací však často neposkytují hvězdný uživatelský zážitek, alespoň ve srovnání s rychlostí, s jakou dokáže interní flash paměť číst/zapisovat data. Rostoucí používání karet SD pro externí ukládání dat se proto pro společnost Google stalo problémem uživatelského dojmu.

Vzhledem k brzkému rozšíření SD karet jako externích úložných zařízení byly konvence pojmenovávání úložišť systému Android založeny na skutečnosti, že každé zařízení mělo skutečný fyzický slot pro kartu microSD. Ale i na zařízeních, která neobsahovala slot pro SD kartu, byl štítek /sdcard stále používán k označení skutečného interního paměťového čipu. Více matoucí je skutečnost, že zařízení, která pro ukládání využívala jak fyzickou SD kartu, tak i vysokokapacitní paměťový čip, často pojmenovávala své oddíly podle SD karty. Například v těchto zařízeních by bod připojení /sdcard odkazoval na skutečný interní paměťový čip, zatímco něco jako /storage/sdcard1 by odkazovalo na fyzickou externí kartu.

I když je tedy karta microSD prakticky považována za externí úložiště, konvence pojmenování vedla k tomu, že „SDCard“ přetrvávalo dlouho po skutečném použití fyzické karty. Tento zmatek s úložištěm také způsobil určité bolesti hlavy vývojářům aplikací kvůli skutečnosti, že data aplikace a jejich média byla oddělena mezi dvěma oddíly.

Nízký úložný prostor dřívějších interních čipů vedl k tomu, že uživatelé frustrovaně zjistili, že již nemohou instalovat aplikace (kvůli plnému oddílu /data). Mezitím byly jejich karty microSD s větší kapacitou odkázány na uložení pouze médií (jako jsou fotografie, hudba a filmy). Uživatelé, kteří dříve procházeli naše fóra, si možná pamatují tato jména: Link2SD a Apps2SD. Jednalo se o (kořenová) řešení, která uživatelům umožňovala instalovat své aplikace a jejich data na fyzickou SD kartu. K dokonalým řešením to ale mělo daleko, a tak musel zakročit Google.

Je známé, že Google velmi brzy vytáhl SD karty. Nexus One zůstává jediným zařízením Nexus se slotem pro kartu microSD (a navždy bude, protože značka Nexus je fakticky mrtvá). U zařízení Nexus S byl nyní pouze jeden jednotný oddíl pro ukládání všech dat aplikací a médií – oddíl /data. To, co bylo kdysi známé jako přípojný bod /sdcard, nyní jednoduše odkazovalo na virtuální souborový systém (implementovaný pod POJISTKA protokol, jak je popsáno níže) umístěný v datovém oddílu - /data/media/0.

Aby byla zachována kompatibilita a snížil se zmatek, Google stále používal tento nyní virtuální oddíl „sdcard“ k ukládání médií. Ale nyní, když byl tento virtuální oddíl „sdcard“ skutečně umístěn v /data, vše, co je v něm uložené, se započítává do úložného prostoru interního úložného čipu. Bylo tedy na OEM, aby zvážili, kolik prostoru přidělit aplikacím (/data) oproti médiím (/data/média).

Dvě velmi odlišné "SD karty"

Google doufal, že výrobci budou následovat jejich příklad a zbaví se SD karet. Naštěstí byli výrobci telefonů v průběhu času schopni dodávat tyto komponenty s vyššími kapacitami a přitom zůstat nákladově efektivní, takže potřeba SD karet začínala ubývat. Ale konvence pojmenování přetrvaly, aby se snížilo množství úsilí, které by vývojáři a OEM museli vynaložit na přizpůsobení. V současné době, když mluvíme o „externím úložišti“, máme na mysli buď jedna ze dvou věcí: skutečná vyměnitelná karta microSD nebo virtuální oddíl „SDCard“ umístěný v /data/media. Poslední z nich, prakticky řečeno, je vlastně interní úložiště, ale konvence pojmenování společnosti Google je odlišuje díky skutečnosti, že tato data jsou přístupná uživateli (např. když je připojena k počítači).

V současné době, když mluvíme o „externím úložišti“, máme na mysli buď jedna ze dvou věcí: skutečná vyměnitelná karta microSD nebo virtuální oddíl „SDCard“ umístěný v /data/media.


Historie virtuálních souborových systémů Androidu

Nyní, když se s „sdcard“ zachází jako s virtuálním souborovým systémem, znamenalo to, že by mohla být naformátována jako jakýkoli souborový systém, který Google chtěl. Počínaje Nexus S a Androidem 2.3 se Google rozhodl formátovat „sdcard“ jako VFAT (virtuální FAT). Tento krok měl v té době smysl, protože instalace VFAT by umožnila téměř každému počítači přístup k datům uloženým ve vašem telefonu. Tato počáteční implementace však měla dva hlavní problémy.

První se týká především koncového uživatele (vás). Chcete-li připojit zařízení k počítači, budete k přenosu dat používat režim velkokapacitního úložiště USB. To však vyžadovalo, aby zařízení Android odpojilo virtuální oddíl, než mohl počítač získat přístup k datům. Pokud by uživatel chtěl používat své zařízení připojené k síti, mnoho věcí by se ukázalo jako nedostupných.

The zavedení protokolu pro přenos médií (MTP) vyřešil tento první problém. Když je počítač zapojen do sítě, vidí vaše zařízení jako zařízení pro ukládání médií. Vyžádá si seznam souborů z telefonu a MTP vrátí seznam souborů, které může počítač stáhnout ze zařízení. Když je požadováno odstranění souboru, MTP odešle příkaz k odstranění požadovaného souboru z úložiště. Na rozdíl od režimu velkokapacitního úložiště USB, který ve skutečnosti připojuje „sdcard“, MTP umožňuje uživateli pokračovat v používání zařízení, i když je připojeno. Navíc na systému souborů v telefonu Android již nezáleží, aby počítač rozpoznal soubory v zařízení.

Zadruhé tu byla skutečnost, že VFAT neposkytoval druh robustní správy oprávnění, kterou Google potřeboval. Zpočátku mnoho vývojářů aplikací považovalo „sdcard“ za skládku pro data své aplikace, aniž by měli jednotnou představu o tom, kam ukládat své soubory. Mnoho aplikací by jednoduše vytvořilo složku s názvem aplikace a uložilo do ní své soubory.

Téměř každá aplikace tam v té době vyžadovala WRITE_EXTERNAL_STORAGE oprávnění zapisovat soubory aplikací na externí úložiště. Co však bylo více znepokojující, byla skutečnost, že téměř každá aplikace také vyžadovala READ_EXTERNAL_STORAGE povolení - stačí číst své vlastní datové soubory! To znamenalo, že aplikace mohly mít snadný přístup k datům uloženým kdekoli na externím úložišti, a takové oprávnění bylo často uděleno uživatelem, protože to bylo vyžadováno pro mnoho aplikací funkce.

Google to jasně viděl jako problematické. Celá myšlenka správy oprávnění je oddělit, k čemu aplikace mohou a nemohou mít přístup. Pokud je téměř každé aplikaci udělen přístup pro čtení k potenciálně citlivým uživatelským datům, pak toto oprávnění postrádá smysl. Google se proto rozhodl, že potřebuje nový přístup. To je místo, kde přichází FUSE.


Souborový systém v uživatelském prostoru (FUSE)

Počínaje Androidem 4.4 se Google rozhodl již nepřipojovat virtuální oddíl „sdcard“ jako VFAT. Místo toho Google začal používat FUSE k emulaci FAT32 na virtuálním oddílu „sdcard“. S voláním programu sdcard FUSE k emulaci oprávnění adresáře ve stylu FAT-on-sdcard, mohly aplikace začít přistupovat k datům uloženým na externím úložišti bez nutnosti jakýchkoliv oprávnění. Počínaje úrovní API 19 již READ_EXTERNAL_STORAGE nebylo vyžadováno pro přístup k souborům umístěným na externím úložišti – za předpokladu, že datová složka vytvořená démonem FUSE odpovídá názvu balíčku aplikace. FUSE by to zvládla syntetizuje vlastníka, skupinu a režimy souborů na externím úložišti když je nainstalována aplikace.

FUSE se liší od modulů v jádře, protože umožňuje neprivilegovaným uživatelům psát virtuální souborové systémy. Důvod, proč Google implementoval FUSE, je poměrně jednoduchý - dělal to, co chtěli, a už to bylo dobře srozumitelné a zdokumentované ve světě Linuxu. Abych citoval a Vývojář Google v této věci:

„Protože FUSE je pěkné stabilní API, při přechodu mezi verzemi jádra není potřeba v podstatě žádná údržba. Pokud bychom migrovali na řešení v jádře, přihlásili bychom se k údržbě sady oprav pro každou stabilní verzi jádra." -Jeff Sharkey, softwarový inženýr ve společnosti Google

Začalo však být zcela jasné, že režie FUSE přinesla kromě jiných problémů i zásah do výkonu. Vývojář, se kterým jsem v této věci mluvil, Michal Kowalczyk, napsal skvělý blogový příspěvek před více než rokem podrobně popisující aktuální problémy s FUSE. Více technických podrobností se dočtete na jeho blogu, ale jeho zjištění (s jeho svolením) popíšu spíše laicky.


Problém s FUSE

V systému Android používá démon uživatelského prostoru „sdcard“ FUSE k připojení /dev/fuse do emulovaného adresáře externího úložiště při spouštění. Poté démon sdcard požádá zařízení FUSE o jakékoli nevyřízené zprávy z jádra. Pokud jste poslouchali podcast, možná jste slyšeli, jak pan Lemarchand odkazuje na FUSE zavádějící režii během I/O operací – zde je v podstatě to, co se stane.

V reálném světě tento zásah do výkonu ovlivňuje žádný soubor uložený na externím úložišti.

Problém č. 1 - I/O Overhead

Řekněme, že vytvoříme jednoduchý textový soubor nazvaný „test.txt“ a uložíme jej do /sdcard/test.txt (což připomínám, je to ve skutečnosti /data/media/0/test.txt za předpokladu, že aktuální uživatel je primární uživatel na přístroj). Pokud bychom chtěli číst (příkaz cat) tento soubor, očekávali bychom, že systém vydá 3 příkazy: otevřít, přečíst, pak zavřít. Vskutku, jak pan Kowalczyk dokazuje použití strace, to se stane:

Ale protože je soubor umístěn na externím úložišti spravovaném démonem sdcard, je potřeba provést mnoho dalších operací. Podle pana Kowalczyka je k tomu zapotřebí v podstatě 8 dalších kroků každý z těchto 3 samostatných příkazů:

  1. Aplikace v uživatelském prostoru vydává systémové volání, které bude zpracovávat ovladač FUSE v jádře (vidíme to v prvním strace výstupu)
  2. Ovladač FUSE v jádře upozorní démona uživatelského prostoru (sdcard) na nový požadavek
  3. Démon uživatelského prostoru čte /dev/fuse
  4. Démon uživatelského prostoru analyzuje příkaz a rozpoznává operace se soubory (např. OTEVŘENO)
  5. Démon uživatelského prostoru vydává systémové volání skutečného souborového systému (EXT4)
  6. Kernel se stará o fyzický přístup k datům a odesílá data zpět do uživatelského prostoru
  7. Uživatelský prostor upravuje (nebo ne) data a znovu je předává přes /dev/fuse do jádra
  8. Kernel dokončí původní systémové volání a přesune data do skutečné aplikace uživatelského prostoru (v našem příkladu cat)

Tohle vypadá jako mnoho režii pouze na jeden I/O příkaz, který má být spuštěn. A měli byste pravdu. Aby to pan Kowalczyk demonstroval, pokusil se o dva různé I/O testy: jeden zahrnoval kopírování velkého souboru a druhý kopírování velkého množství malých souborů. Porovnal rychlost FUSE (na virtuálním oddílu připojeném jako FAT32) zpracovávajícího tyto operace s rychlostí kernel (na datovém oddílu naformátovaném jako EXT4) a zjistil, že FUSE skutečně významně přispívá nad hlavou.

V prvním testu zkopíroval soubor o velikosti 725 MB za obou testovacích podmínek. Zjistil, že implementace FUSE přenáší velké soubory o 17 % pomaleji.

Ve druhém testu zkopíroval 10 000 souborů – každý z nich o velikosti 5 kB. V tomto scénáři byla implementace FUSE u konce o 40 sekund pomaleji zkopírovat v podstatě 50 MB dat.

V reálném světě tento zásah do výkonu ovlivňuje žádný soubor uložený na externím úložišti. To znamená aplikace, jako jsou Mapy ukládající velké soubory na /sdcard, Hudební aplikace ukládající spoustu hudebních souborů, aplikace pro fotoaparát a fotografie atd. Jakákoli prováděná I/O operace, která zahrnuje externí úložiště, je ovlivněna režií FUSE. Ale režie I/O není jediným problémem FUSE.

Problém č. 2 - Dvojité ukládání do mezipaměti

Ukládání dat do mezipaměti je důležité pro zlepšení výkonu přístupu k datům. Uložením důležitých částí dat do paměti je linuxové jádro schopno tato data v případě potřeby rychle vyvolat. Ale kvůli způsobu implementace FUSE ukládá Android dvojnásobné množství mezipaměti, které je potřeba.

Jak ukazuje pan Kowalczyk, očekává se, že soubor o velikosti 10 MB bude uložen do mezipaměti přesně 10 MB, ale místo toho bude velikost mezipaměti přibližně o 20 MB. To je problematické na zařízeních s menší RAM, protože linuxové jádro používá k ukládání dat mezipaměť stránek Paměť. Pan Kowalczyk testoval tento problém s dvojitým ukládáním do mezipaměti pomocí tohoto přístupu:

  1. Vytvořte soubor se známou velikostí (pro testování 10 MB)
  2. Zkopírujte jej do /sdcard
  3. Zrušte mezipaměť stránky
  4. Pořiďte snímek použití mezipaměti stránky
  5. Přečtěte si testovací soubor
  6. Pořiďte další snímek použití mezipaměti stránky

Zjistil, že před jeho testem jádro využívalo 241 MB pro cache stránek. Jakmile si přečetl svůj testovací soubor, očekával, že uvidí 251 MB využitých pro mezipaměť stránky. Místo toho zjistil, že toto jádro používá 263 MB pro mezipaměť stránky - o dvojnásobek toho, co se očekávalo. Důvodem je to, že data jsou nejprve uložena do mezipaměti uživatelskou aplikací, která původně vydala I/O volání (FUSE), a poté démonem sdcard (EXT4 FS).

Problém č. 3 – Neúplná implementace FAT32

Existují dva další problémy vyplývající z použití FUSE emulující FAT32, které jsou v komunitě Android méně známé.

První zahrnuje nesprávná časová razítka. Pokud jste někdy přenesli soubor (například fotografii) a všimli jste si, že časové razítko je nesprávné, je to kvůli implementaci FUSE v systému Android. Tento problém má existoval pro let. Abych byl konkrétnější, problém se týká utime() systémové volání, které umožňuje změnit přístup a čas úpravy souboru. Bohužel volání démona sdcard jako standardní uživatel nemají správná oprávnění k provedení tohoto systémového volání. Existují pro to řešení, ale vyžadují, abyste to udělali mít root přístup.

Pokud jste někdy přenesli soubor (například fotografii) a všimli jste si, že časové razítko je nesprávné, je to kvůli implementaci FUSE v systému Android.

Další problém se týká spíše podniků používajících něco jako a karta smartSD. Před FUSE mohli tvůrci aplikací sledovat Příznak O_DIRECT za účelem komunikace s mikrokontrolérem zabudovaným v kartě. S FUSE mohou vývojáři přistupovat pouze k verzi souboru v mezipaměti a nejsou schopni vidět žádné příkazy odeslané mikrokontrolérem. To je problematické u některých podnikových/vládních/bankovních aplikací, které komunikují s kartami microSD s přidanou hodnotou.


Dumping FUSE pro SDCardFS

Někteří OEMS rozpoznali tyto problémy brzy a začali hledat řešení v jádře, které by FUSE nahradilo. Vyvíjel se například Samsung SDCardFS který je založen na WrapFS. Toto řešení v jádře emuluje FAT32 stejně jako FUSE, ale zbavuje se I/O režie, dvojitého ukládání do mezipaměti a dalších problémů, které jsem zmínil výše. (Ano, dovolte mi zopakovat tento bod, toto řešení, které Google nyní implementuje, je založeno na práci společnosti Samsung).

Sami Google konečně uznal nevýhody spojené s FUSE, a proto začal směřovat k emulační vrstvě FAT32 v jádře vyvinuté společností Samsung. Společnost, jak je uvedeno v Android Developers Backstage podcast, pracuje na zpřístupnění SDCardFS pro všechna zařízení v připravované verzi jádra. Aktuálně můžete vidět jejich průběh práce v AOSP.

Jako Vývojář Google vysvětlil dříve, největší výzvou při implementaci řešení v jádře je, jak namapovat název balíčku ID aplikace potřebné k tomu, aby balíček mohl přistupovat k vlastním datům v externím úložišti, aniž by je vyžadoval oprávnění. Ale toto prohlášení bylo učiněno před rokem a my jsme dosáhli bodu, kdy tým nazývá SDCardFS svou „další velkou věcí“. Již potvrdili, že obávaná chyba časového razítka byl opraven díky odklonu od FUSE, takže se můžeme těšit na všechny změny, které přineslo opuštění FUSE.


Mylné představy o ověřování faktů

Pokud jste se dostali až sem do článku, děkujeme, že jste zatím se vším drželi krok! Chtěl jsem objasnit několik otázek, které jsem měl při psaní tohoto článku:

  • SDCardFS má nic společného se skutečnými SD kartami. Je jen tak pojmenován, protože zpracovává I/O přístup pro /sdcard. A jak si možná vzpomínáte, /sdcard je zastaralý štítek odkazující na „externí“ úložiště vašeho zařízení (kam aplikace ukládají svá média).
  • SDCardFS je není tradiční souborový systém jako FAT32, EXT4 nebo F2FS. Je to stohovatelný obalový souborový systém, který předává příkazy nižším emulovaným souborovým systémům (v tomto případě by to byl FAT32 na /sdcard).
  • S ohledem na MTP se nic nezmění. K přenosu souborů do/z počítače budete nadále používat MTP (dokud se Google nerozhodne pro lepší protokol). Ale alespoň bude opravena chyba časového razítka!
  • Jak již bylo zmíněno dříve, když Google odkazuje na „externí úložiště“, mluví buď o (pro všechny záměry a vnitřní /sdcard virtuální oddíl FAT32 NEBO mluví o skutečné fyzické, vyměnitelné microSD Kartu. Terminologie je matoucí, ale právě to nás zaráží.

Závěr

Odchodem od FUSE a implementací emulační vrstvy FAT32 (SDCardFS) v jádře Google sníží značná I/O režie, eliminace dvojitého ukládání do mezipaměti a řešení některých nejasných problémů souvisejících s emulací FUSE FAT32.

Vzhledem k tomu, že tyto změny budou provedeny v jádře, lze je zavést bez velké nové verze Androidu. Někteří uživatelé očekávají, že tyto změny budou oficiálně implementovány v systému Android 8, ale je to možné pro jakékoli budoucí OTA na zařízení Pixel, které přinese linuxové jádro verze 4.1, na kterém Google pracuje na.

Pro některé z vás není SDCardFS nový koncept. Ve skutečnosti jej zařízení Samsung využívají již léta (koneckonců to byli oni, kdo jej vyvinul). Od té doby, co byl SDCardFS minulý rok představen v AOSP, se někteří vývojáři vlastní ROM a jádra rozhodli implementovat jej do své práce. CyanogenMOD v jednu chvíli uvažoval o jeho implementaci, ale vrátil jej zpět, když uživatelé narazili na problémy se svými fotografiemi. Ale doufejme, že když nad tímto projektem převezme vládu Google, uživatelé Androidu na všech budoucích zařízeních budou moci využít vylepšení zavedená zrušením FUSE.