android – NameLess, the Jedi Odbite echo myśli Wed, 06 Apr 2011 15:02:46 +0000 pl-PL hourly 1 https://wordpress.org/?v=6.2.4 Dezynsekcja w praktyce /nlj/dezynsekcja-w-praktyce/ /nlj/dezynsekcja-w-praktyce/#comments Wed, 06 Apr 2011 15:01:55 +0000 /?p=194 android

Od dobrych paru tygodni mam jakiś wstręt do androidowych wnętrzności. Po części to efekt presji rzeczywistości, po części – jakaś głupia blokada. Waham się czy przejść już na kolejną wersję Androida (Gingerbread czyli 2.3) czy pozostać z FroYo. Jednak odłóżmy rozterki 'młodego’ wyrobnika na bok i zajmijmy się tępieniem robali czyli dezynsekcją właśnie.

Chyba przedostatnia wersja Androidowego ROMu Laszlo opublikowana na forum XDA miała dość ciekawy błąd mianowicie nie widziała aplikacji zainstalowanych na partycji Ext.

Dorabiając z Fireratem natywną obsługę SdExt prawie w ogóle nie zwracaliśmy uwagi na to czy stosowna partycja karty w ogóle istnieje (o podmontowaniu jej we właściwym miejscu nawet nie wspomnę). Ubocznym efektem (i, do pewnego stopnia, powodem moich programistycznych wypocin) był fakt, że telefon potrafił wpadać w bootloop (czyli w kółko się restartował).

Pierwszym krokiem było zmodyfikowanie Volda (VOLume Daemon – usługa systemowa zarządzająca 'dyskami’), tak by montował odpowiednią partycję pod /sd-ext i sprzedał informację o sukcesie (lub porażce) reszcie systemu. Jak już umiał przekazać informację to trzeba było sprawić by framework wiedział co z tą informacją zrobić i tak powstała funkcja o nazwie getSdExtState(). Tak prosta, że nie sposób popełnić w niej błędu. Od razu też wykorzystałem ją do sprawdzania dostępności /sd-ext przed próbą skanowania zainstalowanych tam aplikacji przy starcie systemu. Kawałek kodu tak trywialny, że nawet nie przyszło mi do głowy jakieś większe testowanie.

if (Environment.getSdExtState().equals(Environment.MEDIA_MOUNTED)) {
   scanDirLI(mSdExtInstallDir, PackageParser.PARSE_ON_SDEXT, scanMode);
}

Jak podmontowane to skanuj, jak nie – to nie. Prawda, że proste? W samym frameworku jest parę newralgicznych miejsc (związanych z instalacją aplikacji) w których użyłem identycznego testu. Świat stał się lepszym miejscem :-) a ja mogłem się zająć dorabianiem informacji o SdExt w Ustawieniach czy czymś takim. Mniej więcej w tym momencie Laszlo zapewne zsynchronizował swoje źródła z moimi i wypuścił na świat kolejną wersję swojego ROMu. Chyba w sobotę Firerat dał mi znać na Twitterze, że ludzie mają kłopoty z Apps2SdExt na najnowszym FbL. Zerknąłem na forum i, na podstawie zamieszczonych tam postów, doszedłem do wniosku, że dochodzi do tzw race condition. Vold działa asynchronicznie względem reszty systemu i w czasie gdy jeszcze zajmuje się sprawdzaniem systemów plikowych uruchamiane są pozostałe komponenty systemu takie jak usługa PackageManagera. To ona właśnie przeprowadza początkowy skan katalogów z aplikacjami. Skoro nie widać aplikacji zainstalowanych na SdExt to (patrząc na powyższy kawałek kodu) getSdExtState zwraca coś innego niż MEDIA_MOUNTED i system nawet nie próbuje zajrzeć do /sd-ext/app. Wniosek z tego jest taki, że Vold jeszcze nie zdążył pozałatwiać swoich spraw z /sd-ext. Problem znany zatem teraz wystarczy znaleźć rozwiązanie. Na szybko Firerat przekompilował framework.jar z wywalonym sprawdzaniem getSdExtState(), wrzucił na XDA i 'rozwiązał’ problem (to był akurat weekend i, zdaje się, byłem po jakimś większym maratonie Singstara w towarzystwie sąsiadów i paru butelek Dark Whisky :-)).

To, co zrobił Firerat było jednak tylko obejściem problemu a nie jego rozwiązaniem. Poczytałem jeszcze raz posty na forum, popsioczyłem, że nikt z pomstujących nie zdobył się na złapanie logów ze startu systemu i doszedłem do identycznego wniosku jak wcześniej: Race condition. Na swoim telefonie nie miałem problemu z brakiem aplikacji z SdExt ale też miałem wtedy zainstalowaną wersję bardzo rozwojową (czyt: powiązaną sznureczkiem i podpartą patyczkiem z każdej strony). Złapałem logi z restartu swojego telefonu i patrzyłem w nie jak sroka w gnat. No nijak nie było szans na race condition. Zgodnie z tym co widziałem w logach /sd-ext było już dawno podmontowane. Przecież nie da się zrobić błędu w 6 linijkach kodu z jakich składa się getSdExt():

    /**
     * Gets the current state of SD-Ext
     * Note: this call should be deprecated as it doesn't support
     * multiple volumes.
     */
   public static String getSdExtState() {
       try {
           if (mMntSvc == null) {
               mMntSvc = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
           }
           return mMntSvc.getVolumeState(getSdExtDirectory().toString());
       } catch (Exception rex) {
           return Environment.MEDIA_REMOVED;
       }
   }

Poza tym w innych miejscach kodu funkcja ta działa perfekcyjnie. Tak się zafiksowałem na tym race condition, że dobre dwa dni nad tym spędziłem. Albo raczej zmarnowałem. Zmarnowałem bo z całego logu (około 150+ KB tekstu) skoncentrowałem się wyłącznie na części związanej ze PackageManagerem i skanowaniem /sd-ext/app. W końcu mój umysł zaczął rejestrować inne linijki logu i wyłapał coś takiego:

I/sysproc (  147): System server: starting Android runtime.
I/sysproc (  147): System server: starting Android services.
I/SystemServer(  147): Entered the Android system server!
I/sysproc (  147): System server: entering thread pool.
I/SystemServer(  147): Entropy Service
I/SystemServer(  147): Power Manager
I/SystemServer(  147): Activity Manager
I/ActivityManager(  147): Memory class: 16
D/dalvikvm(  147): GC_FOR_MALLOC freed 641 objects / 80848 bytes in 138ms
D/dalvikvm(  147): GC_FOR_MALLOC freed 2131 objects / 317920 bytes in 159ms
I/SystemServer(  147): Telephony Registry
I/SystemServer(  147): Package Manager
D/dalvikvm(  147): GC_FOR_MALLOC freed 5971 objects / 222640 bytes in 181ms
I/dalvikvm(  147): DexOpt: source file mod time mismatch (3e4c9ef4 vs 3e618cf4)
D/installd(  101): DexInv: --- BEGIN '/system/framework/android.test.runner.jar' ---
D/dalvikvm(  163): DexOpt: load 111ms, verify 722ms, opt 13ms

Kilkanaście linijek niżej pojawia się:

I/PackageManager(  147): Pruning dalvik file: sd-ext@app@com.twitter.android-2.apk@classes.dex
I/PackageManager(  147): Pruning dalvik file: sd-ext@app@com.keramidas.TitaniumBackup-1.apk@classes.dex
D/PackageManager(  147): Scanning app dir /system/framework
D/PackageManager(  147): Scanning app dir /system/app
D/dalvikvm(  147): GC_FOR_MALLOC freed 4987 objects / 280408 bytes in 193ms
W/PackageParser(  147): No actions in intent filter at /system/app/Bluetooth.apk Binary XML file line #124
I/PackageManager(  147): /system/app/CMParts.apk changed; collecting certs

I jeszcze kilkadziesiąt linijek niżej:

D/dalvikvm(  147): GC_EXPLICIT freed 7597 objects / 563168 bytes in 221ms
I/SystemServer(  147): Account Manager
I/SystemServer(  147): Content Manager
I/SystemServer(  147): System Content Providers
I/SystemServer(  147): Battery Service
I/SystemServer(  147): Lights Service
I/SystemServer(  147): Vibrator Service
I/SystemServer(  147): Alarm Manager
D/AlarmManagerService(  147): Kernel timezone updated to -60 minutes west of GMT
I/SystemServer(  147): Init Watchdog
I/SystemServer(  147): Sensor Service
I/SystemServer(  147): Window Manager
I/SystemServer(  147): Bluetooth Service
I/SystemServer(  147): Device Policy
I/bluedroid(  147): Starting hciattach daemon
I/SystemServer(  147): Status Bar
I/SystemServer(  147): Clipboard Service
I/SystemServer(  147): Input Method Service
I/SystemServer(  147): NetStat Service
I/SystemServer(  147): NetworkManagement Service
I/SystemServer(  147): Connectivity Service
V/ConnectivityService(  147): ConnectivityService starting up
D/ConnectivityService(  147): getMobileDataEnabled returning true
V/ConnectivityService(  147): Starting Wifi Service.
I/WifiService(  147): WifiService starting up with Wi-Fi disabled
D/Tethering(  147): Tethering starting
D/NetworkManagmentService(  147): Registering observer
I/bluedroid(  147): Starting bluetoothd deamon
I/SystemServer(  147): Throttle Service
I/SystemServer(  147): Accessibility Manager
I/SystemServer(  147): Mount Service
I/SystemServer(  147): Notification Manager

Widać?
Nie widać?? Hmmm… A teraz?

I/SystemServer(  147): Entropy Service
I/SystemServer(  147): Power Manager
I/SystemServer(  147): Activity Manager
I/SystemServer(  147): Telephony Registry
I/SystemServer(  147): Package Manager
I/SystemServer(  147): Account Manager
I/SystemServer(  147): Content Manager
I/SystemServer(  147): System Content Providers
I/SystemServer(  147): Battery Service
I/SystemServer(  147): Lights Service
I/SystemServer(  147): Vibrator Service
I/SystemServer(  147): Alarm Manager
I/SystemServer(  147): Init Watchdog
I/SystemServer(  147): Sensor Service
I/SystemServer(  147): Window Manager
I/SystemServer(  147): Bluetooth Service
I/SystemServer(  147): Device Policy
I/SystemServer(  147): Status Bar
I/SystemServer(  147): Clipboard Service
I/SystemServer(  147): Input Method Service
I/SystemServer(  147): NetStat Service
I/SystemServer(  147): NetworkManagement Service
I/SystemServer(  147): Connectivity Service
I/SystemServer(  147): Throttle Service
I/SystemServer(  147): Accessibility Manager
I/SystemServer(  147): Mount Service

Jeszcze nie widać? No, dobra. Widzisz kiedy jest startowany Mount Service? A teraz zobacz gdzie jest Package Manager. Między jednym a drugim wpisem mija dobrych kilkanaście – kilkadziesiąt sekund.  W tym czasie skanowane są aplikacje systemowe (/system/app) i użytkownika (/data/app i ewentualnie /sd-ext/app). Poprawność działania getSdExtState() jest uzależniona od działania Mount Service a w chwili próby skanowania /sd-ext/app ta usługa jeszcze nie działa. I to właśnie było źródło problemu :-)

W systemie Android część usług została zaliczona do usług krytycznych (w powyższym wyciągu z logów od Entropy Service do Bluetooth Service). Na moje nieszczęście Mount Service nie trafił do tej kategorii. Z punktu widzenia twórców Androida nie było takiej potrzeby. Usługa ta jest potrzebna tylko do dostępu do kart pamięci. Zmiana kategorii tej usługi nie jest za bardzo możliwa bez potężnej ingerencji w nią samą i szereg innych komponentów a to oznacza więcej potencjalnych bugów. Najprostszym rozwiązaniem było porozmawianie (prawie) bezpośrednio z Voldem. Ubocznym skutkiem jest potencjalne wydłużenie startu systemu o maksymalnie 20 sekund. W skrajnej sytuacji może się okazać, że i tak aplikacje zainstalowane na SdExt się nie pokażą (w przypadku kłopotów z filesystemem). Wygląda to mniej więcej tak. Zdaję sobie sprawę z braków tego rozwiązania. Właściwie jest to tylko nieco hakerskie obejście. Prawidłowym rozwiązaniem jest skanowanie aplikacji z SdExt już po starcie systemu, tak jak to jest robione z aplikacjami zainstalowanymi na partycji FAT karty. Mam już nawet mgliste pojęcie jak to zrobić :-) Jako bonus dostaniecie wtedy możliwość odmontowania i wyjęcia karty pamięci bez wyłączania telefonu :-) Cieszycie się?

 

]]>
/nlj/dezynsekcja-w-praktyce/feed/ 3
Learning Java using Google /nlj/learning-java-using-google/ /nlj/learning-java-using-google/#comments Fri, 21 Jan 2011 14:05:24 +0000 /?p=180 android

Tytuł wpisu wyjaśni się pewnie gdzieś niżej (bo jak zwykle zaczynam pisanie bez konkretnego planu, zaledwie z mglistym zarysem tego co ma się pojawić). Ogólnie rzecz ujmując będzie o Androidzie. Taki śmieszny system operacyjny stworzony przez Google dla urządzeń mobilnych. Chyba od samego początku Android kusił mnie swoją otwartością. Jakoś tak w połowie 2009 roku stałem się właścicielem aparatu Era G1 – znanego bardziej jako HTC Dream. Z Androidem 1.5.

Zdaje się, że z niezmodyfikowanym systemem wytrzymałem jakieś 2-3 miesiące. Proces rootowania/odblokowania Dreama był wówczas nieco skomplikowany i wymagał przygotowania specjalnej karty. Bodaj w sierpniu pokazała się malutka aplikacja, dzięki której można było jednym kliknięciem odblokować Dream. No i się zaczęło.

Zainstalowałem wtedy jakiegoś CyanogenMod-a 4-coś. Przez jakiś czas wystarczało mi instalowanie kolejnych aktualizacji CM4, potem  CM5 i wreszcie CM6. Jakoś w wakacje zwróciłem uwagę na inne ROMy pojawiające się na forum XDA-Developers. Początkowo traktowałem je identycznie jak CMy czyli wipe i flash.  Zainwestowałem nawet w Titanium Backup, żeby nie tracić danych. Raz mnie jednak podkusiło, że zajrzeć do środka zipa. Wydaje mi się, że to był jakiś SpeedTeam Froyo. Numerka nie pamiętam, za to głównym hmmm… „developerem” był (sympatyczny skąd inąd) Jacob Chu-Hing bardziej znany jako XxKOLOHExX.

Developement w wykonaniu SpeedTeam polegał na podmianie paru grafik i xml-i (tzw theming) i dorzuceniu (nieco na oślep) paru cudownych skryptów do /system/etc/init.d. Dodatki typu „apps2sdext-out-of-the-box!” robione były poprzez wywoływanie (przy każdym starcie telefonu) bardzo popularnego (i przy okazji bardzo dobrze napisanego) skryptu Firerata o nazwie All in One Patch. Ten właśnie fakt sprawił, że zacząłem się bawić w modyfikowanie ROMów. Pierwsze kroki robiłem w znanym sobie terenie skryptów shellowych i ogólnie w tej części Androida, która leży na samiusieńkim spodzie i jest po prostu, przyciętym na miarę, Linuxem.

Parę tygodni później miałem na dysku komplet źródeł CyanogenModa a na telefonie samodzielnie skompilowany ROM. Znowu parę tygodni minęło i delikatnie zacząłem gmerać w kodzie. Pierwszym zupełnie samodzielnym dziełkiem było dołożenie możliwości kontrolowania swapu do CyanogenMod Settings. Trywialna modyfikacja javowego kodu i jeden czy dwa skrypty w shellu. Nic skomplikowanego. Dołożenie obsługi CPUFreq było trochę bardziej pracochłonne (i nie obyło się bez pomocy Joëla Bourquarda – autora Titanium Backup) ale się udało :)

W międzyczasie SpeedTeam zawiesił działalność a XxKOLOHExX przeszedł do Biff Squad. Wersja 2.0 BiffModa była w całości oparta o moją kompilację i pewnie byłaby sukcesem ale RoyalKnight zdecydował się na inny kernel i trochę niefortunnie wkleił go w przygotowaną przeze mnie paczkę. Zdarza się a ja się czegoś nowego nauczyłem :) Potem był BiffMod 2.1 przygotowany przez Ezterry’ego, z jego kernelem i moimi dodatkami. Mogłem spocząć na laurach i grzecznie czekać na Gingerbreada.

I pewnie bym spoczął gdyby nie twitterowa rozmowa najpierw z Cyanogenem a potem Fireratem. Jakoś tak wyszło, że razem z Fireratem zajęliśmy się tzw natywnym apps2sdext. Do tej pory możliwość instalacji aplikacji na partycji Ext2/3/4 karty była realizowana przy pomocy skryptów shellowych i polegała na oszukiwaniu systemu co do faktycznej lokalizacji plików apk. Gdybym miał chociaż blade pojęcie jak skomplikowany to projekt pewnie bym sie nigdy nie odważył za to zabrać. Prace nad wbudowanym w system apps2sdext trwały dobrze ponad 2 miesiące. Choć rozwiązań kolejnych problemów poszukiwaliśmy wspólnie, to jednak gross rozwiązań znajdował Firerat. Wiele razy zdarzało się, że dłubaliśmy nad jakimś kawałkiem kodu i już miałem rozwiązanie problemu na końcu języka gdy Firerat zaćwierkał „Ok, I made it”. Nigdy go nie spytałem czy kiedyś przydarzyła mu się podobna sytuacja ale ze mną w roli głównej. Mam nadzieję, że tak :D jest w tym wszystkim ładnych parę linijek mojego autorstwa.

No dobra ale co to ma wspólnego z tytułem wpisu? Ermm… zdradzę pewną tajemnicę… Nie znam Javy. Serio! Nie znam Javy. Nigdy wcześniej nie używałem tego języka (jestem przecież adminem a nie programistą!). Tymczasem całe to apps2sdext wymagało grzebania w jednym z kluczowych komponentów (framework.jar) napisanym w całości w Javie. Dziesiątki razy oglądałem kawałek kodu, dopisywałem kawałek kodu i bez przerwy odpytywałem Google na okoliczność składni tego czy innego polecenia Javy. Sprawdzałem dostępne funkcje, metody i temu podobne sprawy. O, właśnie! Metody! Dodatkowym smaczkiem jest to, że nigdy wcześniej nie pisałem niczego w jakimkolwiek obiektowo zorientowanym języku programowania :) Największym zaskoczeniem dla mnie jest to, że #LearningJavaUsingGoogle działa! :P Nie wierzysz? To zerknij na

Miłego haczenia Androida!!

NameLess
the Jedi

]]>
/nlj/learning-java-using-google/feed/ 2