Android, wiarygodnoÅłÄ⁄, programowa
Transkrypt
Android, wiarygodnoÅłÄ⁄, programowa
Politechnika Warszawska Wydział Elektroniki i Technik Informacyjnych Instytut Informatyki Rok akademicki 2012/2013 Praca dyplomowa magisterska Maciej Sułek Eksperymentalny system badania wiarygodności aplikacji w systemie Android Opiekun pracy: dr inż. Piotr Gawkowski Ocena . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ......................................... Podpis Przewodniczacego ˛ Komisji Egzaminu Dyplomowego Specjalność: Informatyka – Inżynieria Systemów Informatycznych Data urodzenia: 15 sierpnia 1989 r. Data rozpoczecia ˛ studiów: 20 luty 2012 r. Życiorys Nazywam sie˛ Maciej Sułek. Urodziłem sie˛ 15 sierpnia 1989 roku w Kozienicach. W roku 2008 ukończyłem VI Liceum Ogólnokształcace ˛ imienia Jana Kochanowskiego w Radomiu, gdzie realizowałem rozszerzony program edukacji z zakresu matematyki, fizyki oraz informatyki. W tym samym roku, rozpoczałem ˛ studia pierwszego stopnia na Wydziale Elektroniki i Technik Informacyjnych Politechniki Warszawskiej na kierunku Informatyka. Ukończyłem je w lutym 2012 roku, bezpośrednio rozpoczynajac ˛ studia drugiego stopnia na tym samym wydziale. ..................................... podpis studenta Egzamin dyplomowy Złożył egzamin dyplomowy w dn. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Z wynikiem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ogólny wynik studiów . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Dodatkowe wnioski i uwagi Komisji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .......................................................................................... Streszczenie Praca przedstawia system eksperymentalnego badania wiarygodności aplikacji dla systemu Android. Prezentuje architekture˛ samego systemu Android oraz istotne, z punktu widzenia programisty, biblioteki wraz z ich klasami oraz metodami. Omówiono koncepcje˛ zrealizowanego w ramach tej pracy systemu wymuszania sytuacji krytycznych nazwanego Android Fault Injection System - AFIS. Opisano sposób jego działania i implementacji wraz z możliwościami wykorzystania. Przeprowadzono eksperymentalne badania wiarygodności szeregu popularnych aplikacji, a wyniki oraz ich analize˛ zawarto w pracy. Wskazuja˛ one na wiele niedoskonałości badanych aplikacji oraz potwierdzaja˛ praktyczna˛ przydatność opracowanego systemu symulacyjnego. Słowa kluczowe: Android, wiarygodność, programowa symulacja błedów, ˛ testowanie oprogramowania Abstract Title: Experimental system for dependability analyses of Android applications This thesis presents an experimental system for dependability analyses of Android applications. The architecture overview of the Android operating system is given as well as some most significant classes and methods of libraries from the developers perspective. The concept of the developed system emulating critical situations, named Android Fault Injection System - AFIS - is described. Its implementation and use cases are also presented. Dependability analyses for a bunch of popular applications based on results from experiments carried out with the developed AFIS are given. They point out a variety of shortages of the analyzed applications and indicate the practicality of the implemented fault injection system. Key words: Android, dependability, software implemented fault injection, software testing Spis treści 1. Wstep ˛ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2. Przeglad ˛ literatury . . . . . . . . . . . . . . . . 2.1. Narzedzia ˛ do testów aplikacji dla systemu 2.1.1. Android Testing . . . . . . . . . . . 2.1.2. Robolectric . . . . . . . . . . . . . . 2.1.3. Android Mock . . . . . . . . . . . . 2.2. Symulacja błedów ˛ . . . . . . . . . . . . . . 2.3. Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . 4 4 4 5 6 7 9 3. Architektura systemu Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1. Opis bibliotek systemu Android . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 11 4. System AFIS . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1. Kompilacja systemu . . . . . . . . . . . . . . . . . . . . 4.2. Instalacja oprogramowania . . . . . . . . . . . . . . . 4.3. Użytkowanie systemu AFIS . . . . . . . . . . . . . . . 4.3.1. AFIS Desktop Manager . . . . . . . . . . . . . . 4.3.2. AFIS Desktop Analyzer . . . . . . . . . . . . . . 4.3.3. AFIS Android Manager . . . . . . . . . . . . . . 4.4. Przykłady użycia . . . . . . . . . . . . . . . . . . . . . . 4.4.1. Zaniechanie sprawdzenia rezultatu wykonania 4.4.2. Bład ˛ wielowatkowości ˛ . . . . . . . . . . . . . . . 4.4.3. Zmiana argumentów wywołania metody . . . . 4.4.4. Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . metody . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 22 25 25 26 28 31 33 33 35 36 37 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 40 41 43 44 53 54 56 58 77 77 80 81 83 84 85 85 87 87 90 90 6. Podsumowanie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 5. Badania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1. Connectbot . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.1. Rozpoznanie . . . . . . . . . . . . . . . . . . . . . . 5.1.2. Badania metod wywoływanych z jednego miejsca 5.1.3. Badania metoda wywoływanych z wielu miejsc . . 5.2. Endomondo . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.1. Rozpoznanie . . . . . . . . . . . . . . . . . . . . . . 5.2.2. Badania metod wywoływanych z jednego miejsca 5.2.3. Badania metod wywoływanych z wielu miejsc . . . 5.3. Play Music . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.1. Rozpoznanie . . . . . . . . . . . . . . . . . . . . . . 5.3.2. Badania metod wywoływanych z jednego miejsca 5.3.3. Badania metod wywoływanych z wielu miejsc . . . 5.4. VLC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.1. Rozpoznanie . . . . . . . . . . . . . . . . . . . . . . 5.4.2. Badania metod wywoływanych z jednego miejsca 5.4.3. Badania metod wywoływanych z wielu miejsc . . . 5.5. Android Browser . . . . . . . . . . . . . . . . . . . . . . . . 5.5.1. Rozpoznanie . . . . . . . . . . . . . . . . . . . . . . 5.5.2. Badania metod wywoływanych z jednego miejsca 5.5.3. Badania metod wywoływanych z wielu miejsc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Spis treści ii Bibliografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 A. Zawartość płyty CD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 1. Wstep ˛ System Android jest niezwykle dynamicznym i szybko rozwijajacym ˛ sie˛ projektem. Poczatkowo ˛ był tworem firmy Android Inc., która z czasem została wykupiona przez firme˛ Google. Obecnie to właśnie ona jest utożsamiana z tym projektem. Pierwszy powszechnie doste˛ pny telefon z tym systemem w wersji 1.0 został wprowadzony do sprzedaży 28 września 2008 roku [11]. Posiadał on już Android Market (obecnie Google Play), a wie˛ c sklep z aplikacjami, które mógł dostarczać każdy zarejestrowany deweloper. Warto zwrócić uwage, ˛ że na tle wcześniejszych systemów mobilnych, takich jak Windows Mobile czy też Symbian, była to spora innowacja. Użytkownik mógł za pomoca˛ kilku kliknieć ˛ pobrać i zainstalować wybrany program, a jeśli zaszła taka konieczność to od razu za niego zapłacić. Taki sposób dystrybucji oprogramowania spowodował, że aplikacje pobierane sa˛ w bardzo dużych ilościach (rysunek 1.1). Na dzień 26 września 2012 roku, pobrano je ponad 25 miliardów razy [7]. Na chwile˛ obecna, ˛ 13 września 2013 roku, w sklepie dostepnych ˛ jest 860815 aplikacji, z czego ponad 80% z nich jest darmowych [14]. Ostatnie statystyki wskazuja, ˛ że Android aktywowany jest 1,5 miliona raza na dzień [5], a urza˛ dzenia wyposażone w ten system stanowia˛ niemal 75% wszystkich smartfonów [13]. Z powodu szybkiego rozwoju system Android został dotkniety ˛ fragmentacja, ˛ czyli zbyt duża˛ liczba wersji funkcjonujacych ˛ na urzadzeniach. ˛ Sytuacja zaczyna si˛e jednak stabilizować i obecnie najpopularniejszymi z nich sa˛ te oznaczone numerami 4.1-4.3 - ponad 48% [14]. Rysunek 1.1. Liczba pobrań aplikacji ze sklepu Google Play [7] 1. Wstep ˛ 2 Wobec tak dużej popularności systemu Android, zachodzi obawa o wiarygodność dostarczanych aplikacji, która˛ rozumiemy jako zdolność do wyeliminowania bł˛edów, która sa˛ krytyczne oraz tych, które uniemożliwiaja˛ prace˛ z systemem dłużej niż jest to akceptowalne [19]. Oprogramowanie powinno wiec ˛ pracować w sposób ciagły ˛ i stabilny. W odniesieniu do systemów mobilnych, uruchamiane programy nie powinny nigdy kończyć sie˛ nieprawidłowa˛ operacja, ˛ a wiec ˛ wymuszonym zatrzymaniem. Nieakceptowalne jest również tracenie danych użytkownika badź ˛ ich niekontrolowane udoste˛ pnianie. Należy pamietać, ˛ że obecnie telefony służa˛ do coraz wie˛ kszej liczby zadań np.: do wykonywania płatności, sterowania systemami zdalnymi (kontrola inteligentnych domów, sprawdzanie stanu samochodu itp.) czy też do autoryzacji użytkownika w systemach zewnetrznych ˛ (dostep ˛ do firmy, logowanie w serwisach). Użytkownicy sa˛ wiec ˛ coraz bardziej narażeni na straty materialne. Dlatego ważnym jest aby zapewnić aplikacjom odpowiednia˛ jakość. W tym celu rozwijane sa˛ metody testowania, które musza˛ być uwzgledniane ˛ w procesie wytwarzania oprogramowania. Sa˛ one wspomagane przez odpowiednie narze˛ dzia, które mimo iż dla systemu Android istnieja, ˛ zdaja˛ sie˛ być niewystarczajace, ˛ ponieważ nie ułatwiaja˛ programiście czy też testerowi pokrycia testami fragmentów kodu odpowiedzialnych za obsługe˛ różnego rodzaju sytuacji krytycznych (niepowodzenie operacji podczas doste˛ pu do zasobu, brak możliwości określenia lokalizacji, brak zasobów itp. - patrz rozdział 2). W kontekście systemów mobilnych, dla których dedykowany jest Android, prawidłowa obsługa i adekwatność reakcji aplikacji i systemu jako takiego na tego typu zdarzenia staje sie˛ sprawa˛ kluczowa. ˛ Jedna˛ z ciekawszych możliwości rozwoju narzedzi ˛ testujacych ˛ i weryfikujacych ˛ jakość oprogramowania jest programowa symulacja błedów ˛ wykorzystujaca ˛ emulacj˛e sytuacji krytycznych oraz błednych ˛ w celu weryfikacji ich wpływu na stan systemu i aplikacji [16]. Celem niniejszej pracy było stworzenie kompletnego rozwiazania ˛ umożliwiajacego ˛ testowanie aplikacji programowych oraz ich odporności na sytuacje krytyczne poprzez ich emulowanie w systemie Android. Na jej potrzeby powstał Android Fault Injection System (w skrócie AFIS). Jest to zbiór programów oraz specjalnie przygotowana wersja systemu operacyjnego Android. Pozwalaja˛ one na symulowanie niepoprawnego działania systemu Android oraz ułatwiaja˛ zbieranie informacji jak i przeprowadzanie właściwych testów. Najważniejsza˛ cze˛ ścia˛ tworzenia AFIS była modyfikacja systemu Android. Został on spreparowany tak, aby umożliwiać dynamiczne wstrzykiwanie kodu do wybranych funkcji. Należy wspomnieć, że klasy oraz metody wyselekcjonowane zostały z doste˛ pnego API w wersji 8, a wiec ˛ dla Androida 2.2. Takie rozwiazanie ˛ zapewnia najwie˛ ksza˛ kompatybilność z innymi wersjami systemu. Do dyspozycji użytkownika oddano możliwość przecia˛żenia 125 funkcji. Lista ta jest łatwo rozszerzalna, źródła moga˛ być automatycznie modyfikowane za pomoca˛ dostarczanego skryptu. Powoduje to, że całość jest elastyczna i rozwojowa. Proces powstania koncepcji oraz implementacji został przedstawiony szczegółowo w pracy. W rozdziale 2 opisano dostepne ˛ dla systemu Android narzedzia, ˛ ogólne podejście do programowej symulacji błedów ˛ oraz koncepcje˛ utworzenia własnego rozwiaza˛ nia. Rozdział 3 zawiera opis architektury wspomnianego systemu oraz dostarczanych wraz z nim bibliotek. Architekture˛ własnego rozwiazania ˛ oraz sposób kompilacji, instalacji oraz jego wykorzystania zaprezentowano w rozdziale 4. Niezwykle istotnym elementem niniejszej pracy były badania. W ich ramach sprawdzono podatność 5 popularnych aplikacji na błedy. ˛ Sposób oraz metodologia testowania 1. Wstep ˛ 3 zostały opisane w rozdziale 5. W dodatku A umieszczono spis zawartości dołacza˛ nej do pracy płyty CD. Umieszczono na niej także dodatkowy plik plik w formacie pdf zawierajacy ˛ szczegółowe opisy poszczególnych testów wykonywanych w ramach badań. 2. Przeglad ˛ literatury Jakość wytwarzanego na system Android oprogramowania jest stosunkowo niska. Nie jest to jedynie subiektywna ocena autora jako użytkownika systemu, ale świadcza˛ o tym również systematyczne badania [1] [15]. Sam system oczywiście również nie jest pozbawiony błedów, ˛ jednak w znakomitej ilości przypadków, za problemy odpowiedzialne sa˛ aplikacje. W raporcie [1] przedstawiono najczestsze ˛ problemy wraz z odwołaniami do ich zgłoszeń w systemie śledzenia błedów. ˛ Wynika z niego, że problemy dotycza˛ kluczowych modułów oraz niekiedy uniemożliwiaja˛ poprawne funkcjonowanie urzadzenia. ˛ W [15] zawarto szczegółowo opracowane wyniki dotyczace ˛ najbardziej podatnych na błedy ˛ elementów systemu Android. Wynika z niego, że najwie˛ cej problemów sprawiaja˛ narzedzia ˛ dla deweloperów, przegladarka ˛ internetowa, aplikacje z pakietu Google oraz multimedia. Potwierdza to wi˛ec potrzebe˛ dostarczenia narzedzi ˛ umożliwiajacych ˛ testowanie aplikacji w różnych środowiskach, gdyż system Android działa na różnych urzadzeniach ˛ wielu producentów. 2.1. Narzedzia ˛ do testów aplikacji dla systemu Android W poszukiwaniu narze˛ dzi testujacych ˛ lub wspomagajacych ˛ testowanie, autor pracy zidentyfikował jedynie rozwiazania ˛ niekomercyjne. Przedstawiono najciekawsze z nich, których możliwości oraz podejście do problemu sa˛ różne. Mimo iż takich narze˛ dzi jest wie˛ cej to sa˛ one zbliżone funkcjonalnościa. ˛ Istnieja˛ również środowiska testujace ˛ dedykowane dla jezyka ˛ Java (np.: JUnit [8], Sureassert [10], FindBugs [6]) jednak nie umożliwiaja˛ one wymuszania sytuacji krytycznych celem zwi˛ekszania pokrycia kodu testami - aktywujac ˛ ścieżki obsługi sytuacji krytycznych. 2.1.1. Android Testing Android Testing to mechanizm testowania aplikacji dostarczany wraz z bibliotekami systemowymi. Jest on szczegółowo opisany na stronie dla deweloperów [4]. W bardziej przyste˛ pnej formie został on przedstawiony w artykule “Android application testing with the Android test framework” autorstwa Larsa Vogela [21]. Pokrótce, jest to wydzielona biblioteka dziedziczaca ˛ mechanizmy z dobrze znanego pakietu JUnit [8] służacego ˛ do tworzenia testów jednostkowych dla jezyka ˛ Java. W skład Android Testing wchodza˛ klasy umożliwiajace ˛ sprawdzanie poprawności tworzonych przez nas funkcji, klas oraz aktywności w systemie Android. Cały proces tworzenie oraz uruchamiania przygotowanych testów został maksymalnie uproszczony dzieki ˛ wtyczce dla środowiska Eclipse. Powoduje to, że można ja˛ wykorzystywać bez dodatkowego przygotowania, a czas ich generowania oraz przygotowania skrócono do minimum. Na wydruku 2.1 zaprezentowano przykład użycia mechanizmu Android Testing. Test ten polega na weryfikacji stanu 2.1. Narzedzia ˛ do testów aplikacji dla systemu Android 5 kolejnych obiektów wykorzystywanych w funkcji. W przypadku nieprawidłowości zakończy sie˛ on w miejscu sprawdzenia dostarczajac ˛ przygotowany komunikat o bł˛edzie. 1 5 @SmallTest public void testIntentTriggerViaOnClick ( ) { buttonId = com. v o g e l l a . android . t e s t . s i m p l e a c t i v i t y .R. id . button1 ; Button view = ( Button ) a c t i v i t y . findViewById ( buttonId ) ; assertNotNull ( " Button not allowed to be null " , view ) ; // You would c a l l the method d i r e c t l y via g e t A c t i v i t y ( ) . onClick ( view ) ; 10 // TouchUtils cannot be used , only allowed in // InstrumentationTestCase or ActivityInstrumentationTestCase2 // Check the i n t e n t which was started Intent t r i g g e r e d I n t e n t = g e t S t a r t e d A c t i v i t y I n t e n t ( ) ; assertNotNull ( " Intent was null " , t r i g g e r e d I n t e n t ) ; String data = t r i g g e r e d I n t e n t . getExtras ( ) . getString ( "URL" ) ; 15 assertEquals ( " I n c o r r e c t data passed via the intent " , " http ://www. v o g e l l a .com" , data ) ; 20 } Wydruk 2.1. Przykład użycia mechanizmów Android Testing. Źródło [21] Zwróćmy uwage˛ , że zadaniem programisty jest wskazanie i zbadanie potencjalnych miejsc błe˛ dów - np. sprawdzenie czy pobrany z widoku obiekt przycisku na pewno istnieje. Rozwiazanie ˛ to ma jednak zasadnicza˛ wade. ˛ Otóż nie daje możliwości wymuszenia by wspomniany obiekt faktycznie był pusty. Oczywiście nie takie jest przeznaczenie testów jednostkowych, jednak warto ten fakt zaznaczyć, szczególnie przy uwzgle˛ dnieniu opisywanej wcześniej metody testowania polegajacej ˛ na emulowaniu sytuacji krytycznych. 2.1.2. Robolectric Kolejnym niezależnym narzedziem ˛ do testów jednostkowych, które oprócz funkcji umożliwia również testowanie interfejsu użytkownika, jest Robolectric [9]. Mimo, iż jego przeznaczenie jest podobne do opisywanych mechanizmów dostarczanych wraz z Android Testing, wprowadza jednak sporo ułatwień i modyfikacji. Najważniejsza˛ z nich zdaje sie˛ być system adnotacji, który umożliwia sterowanie łatwa˛ modyfikacje˛ parametrów systemu. Przykład ich użycia zaprezentowano na wydruku 2.2. Umożliwiaja˛ wiec ˛ one zmiane˛ pliku manifestu1 aplikacji, jezyka ˛ systemowego, rozdzielczości ekranu czy nawet wersji API, w ramach której funkcja czy klasa powinna być wykonana. 1 Manifest to obowiazkowy ˛ dla każdej aplikacji plik konfiguracyjny. Za jego pomoca˛ określa sie˛ szereg parametrów, np.: minimalna, wymagana wersja systemu operacyjnego; uruchamiane aktywności; nazwa aplikacji; uprawnienia konieczne do jej uruchomienia; komponenty aplikacji. Wiecej ˛ informacji można znaleźć na stronie dla deweloperów [4] 6 2.1. Narzedzia ˛ do testów aplikacji dla systemu Android 1 5 10 @RunWith ( RobolectricTestRunner . class ) @Config ( manifest = " AlternateManifest . xml " ) // <== use a non−standard // manifest f i l e public class HomeActivityTest { @Config ( q u a l i f i e r s = " f r −land−hdpi " ) // <== use French resources on // a sideways high−res display @Test public void shouldHaveAButtonThatSaysPressMe ( ) throws Exception { // t e s t code here } } Wydruk 2.2. Przykład użycia adnotacji Config w bibliotece Robolectric Sama implementacja testów również została ułatwiona dzieki ˛ szeregom obiektów, które Robolectric potrafi preparować. Zaprezentowany na wydruku 2.3 przykład funkcji testujacej, ˛ pokazuje jak sprawdzić czy odpowiedź serwera jest poprawna. Należy zwrócić uwage, ˛ że nie trzeba konfigurować ani przygotowywać własnego serwera. Funkcja Robolectric.addPendingHttpResponse powoduje, że wykorzystujac ˛ klase˛ Http.Response zwrócona zostanie spreparowana informacja. Jest to niezwykle pomocny mechanizm oszczedzaj ˛ acy ˛ programiście wiele czasu. 1 @Test public void shouldReturnCorrectResponse ( ) throws Exception { Robolectric . addPendingHttpResponse (666 , " i t ’ s a l l cool " ) ; 5 Http . Response response = http . get ( "www. example .com" , new HashMap<String , String > ( ) , null , null ) ; assertThat ( fromStream ( response . getResponseBody ( ) ) , equalTo ( " i t ’ s a l l cool " ) ) ; assertThat ( response . getStatusCode ( ) , equalTo ( 6 6 6 ) ) ; 10 } Wydruk 2.3. Przykład funkcji testujacej ˛ odpowiedź Robolectric serwera w bibliotece 2.1.3. Android Mock Android Mock to biblioteka służaca ˛ do tworzenia obiektów imitujacych ˛ klasy oraz interfejsy dla wirtualnej maszyny Dalvik [2]. Mimo pewnych cześci ˛ wspólnych, jak np. możliwość modyfikacji parametrów systemu za pomoca˛ adnotacji, to prezentuje ona nieco inne podejście niż dotychczas prezentowane rozwiazania. ˛ Przykład użycia, przedstawiony na wydruku 2.4, pokazuje w jaki sposób można przygotować obiekt do testu. Poczatkowo ˛ odbywa sie˛ inicjalizacja 2.2. Symulacja błedów ˛ 7 obiektu imitujacego ˛ na podstawie testowanej klasy (wiersz 6). Nastepnie ˛ tworzony jest zestaw oczekiwanych rezultatów (wiersze od 9 do 13), a na końcu sa˛ one weryfikowane (wiersz 14). Warto zwrócić uwage, ˛ że warunki moga˛ być dostarczane w zależności od pewnej zmiennej - w tym przypadku od zmiennej sterujacej ˛ petl ˛ a. ˛ 1 5 10 15 public class MockingTest extends TestCase { @UsesMocks ( ClassToMock . class ) public void testMocks ( ) throws ClassNotFoundException { ClassToMock myMockObject = AndroidMock . createMock ( ClassToMock . class ) ; for ( int i = 0; i < 5; ++ i ) { AndroidMock . expect ( myMockObject . getString ( ) ) . andReturn ( "Woohoo" ) ; AndroidMock . expect ( myMockObject . getNextInt ( i ) ) . andReturn(42 + i ) ; AndroidMock . replay ( myMockObject ) ; assertEquals ( "Woohoo" , myMockObject . getString ( ) ) ; assertEquals (42 + i , myMockObject . getNextInt ( i ) ) ; AndroidMock . v e r i f y ( myMockObject ) ; AndroidMock . r e s e t ( myMockObject ) ; } } } Wydruk 2.4. Przykład użycia biblioteki Android Mock Zaprezentowane rozwiazanie, ˛ mimo dużej liczby zastosowań, nie jest wystarczajace ˛ by móc testować poprawność tych fragmentów kodu aplikacyjnego, które odpowiadaja˛ za obsługe˛ nieprawidłowych, rzadkich czy też krytycznych sytuacji. Sprowadza sie˛ to do problemu uzyskania lepszego pokrycia przypadkami testowymi. Niestety, pewne sytuacje nie sa˛ możliwe do zasymulowania bez ingerencji w kod źródłowy testowanej aplikacji. Pożadany ˛ efekt (emulacje˛ błedów) ˛ można uzyskać poprzez instrumentacje˛ kodu testowanej aplikacji. Konieczne jest wówczas wytworzenie dodatkowej ilości kodu, a całość generowana jest w czasie kompilacji. Instrumentacja jest również w wielu przypadkach niemożliwa z powodu ograniczeń licencyjnych i braku kodów źródłowych (np. biblioteki wykorzystywane przez testowana˛ aplikacje˛ ). Najlepszym rozwiazaniem ˛ byłoby narzedzie ˛ potrafiace ˛ emulować dynamicznie określone sytuacje w systemie, bez potrzeby dodatkowej instrumentacji i rekompilacji badanej aplikacji. Miedzy ˛ innymi tego typu badania umożliwia programowa symulacja błe˛ dów. 2.2. Symulacja błedów ˛ Ogólnie symulacja˛ błe˛ dów nazywamy zakłócanie działania analizowanego programu badź ˛ systemu oraz obserwowanie jego skutków [16]. Proces ten możemy podzielić na kilka etapów. Pierwszym z nich powinna być identyfikacja modułów czy bibliotek, z których aplikacja korzysta. Kolejny polega na przeprowadzaniu przebiegu wzorcowego (bez zakłóceń), który pozwala na określenie oczekiwanego zachowania programu. Trzeci etap, to wybór miejsc oraz momentów wstrzykiwania 2.2. Symulacja błedów ˛ 8 bł˛edów (adekwatnie do stawianego przed eksperymentem celu). Nastepnie ˛ przeprowadzane sa˛ faktyczne eksperymenty polegajace ˛ na wielokrotnym wykonaniu scenariusza testowego przez badana˛ aplikacje, ˛ podczas których dochodzi do wygenerowania określonego zakłócenia oraz obserwacja wpływu tego zakłócenia na system, wykonywane w tym czasie aplikacje i wyniki ich działania. Ostatnim krokiem jest analiza zebranych obserwacji (wyników). W pracy zajmowano sie˛ programowymi wstrzykiwaczami błe˛ dów (z ang. Software Implemented Fault Injector, w skrócie SWIFI). Narze˛ dzia umożliwiajace ˛ symulacje˛ błedów ˛ sa˛ stale rozwijane. Dla systemów z rodziny Windows oraz Linux, jednym z takich rozwiaza ˛ ń, jest opracowany w Instytucie Informatyki Politechniki Warszawskiej system DInjector oraz jego nastepca ˛ HInjector [16]. Cechuje je duża wydajność oraz możliwość pracy rozproszonej. Dopiero drugi z tych projektów umożliwiał łatwe zarzadzenie ˛ systemem z poziomu graficznego interfejsu użytkownika, co czyni go bardziej przystepnym. ˛ Systemy te (podobnie jak wie˛ kszość opisywana w literaturze naukowej) służa˛ badaniu wpływu przemijajacych ˛ błe˛ dów sprze˛ towych na systemy i aplikacje programowe. Odbiega to wi˛ec od celów stawianych przed autorem niniejszej pracy - tu emulowane błedy ˛ powinny odpowiadać sytuacjom realistycznym, które moga˛ faktycznie wystapić ˛ w systemie, choć prawdopodobieństwo ich wystapienia ˛ jest stosunkowo niskie. Innym projektem powstałym również we wspomnianym instytucie jest LRFI [18], który dedykowany jest urzadzeniom ˛ mobilnym. Działa on na poziomie jadra ˛ systemu Linux dla architektury ARM i umożliwia wstrzykiwanie błedów ˛ na tym poziomie. Daje wie˛ c, mie˛ dzy innymi, możliwość wpływania na połaczenia ˛ sieciowe, ograniczania zasobów, generowania bł˛edów odczytu i zapisu z pamieci. ˛ Realizuje on wie˛ c idee˛ emulowania sytuacji krytycznych dla testowanych aplikacji. W Instytucie Informatyki Politechniki Warszawskiej opracowano też narzedzia ˛ operujace ˛ na j˛ezykach wysokiego poziomu. Jednym z nich jest JInjector [17], który umożliwia symulacje˛ błe˛ dów w programach stworzonych w jezyku ˛ Java. Oparty on jest o koncepcje˛ programowania aspektowego (z ang. Aspect Oriented Programming, w skórcie AOP). Umożliwia on przecia˛żenie dowolnej funkcji w analizowanym programie (np. pominie˛ cie wywołania oryginalnej metody i emulacje˛ zwrotu przez nia˛ błe˛ du wykonania). Ponieważ operuje na kodzie maszynowym wirtualnej maszyny Java, to nie ma możliwości jego wykorzystania w środowisku uruchomieniowym systemu Android, ze wzgledu ˛ na niezależna˛ implementacje˛ maszyny wirtualnej Dalvik (dokładny opis w rozdziale 3). Nieco inne podejście zaprezentowano podczas opracowywania SWIFI dla platformy .NET [17]. Ze wzgledu ˛ na brak wsparcia dla dynamicznego wstrzykiwania kodu, przedefiniowano biblioteki środowiska Mono. Dało to możliwość wymuszania pewnych błedów ˛ (np.: błedy ˛ operacji na plikach, błe˛ dy podczas transmisji sieciowej, symulacja ograniczenia dost˛epnej pami˛eci). Zapewniono również mechanizm rekonfiguracji opracowanego systemu podczas działania maszyny wirtualnej .NET. Warto dodać, ze istnieja˛ narzedzia ˛ komercyjne - np. Holodeck czy AppVerifier, które realizuja˛ weryfikacje˛ zachowania aplikacji w krytycznych sytuacjach, jednak żadne z nich nie jest dedykowane systemowi Android oraz posiadaja˛ szereg ograniczeń [22]. 2.3. Podsumowanie 9 2.3. Podsumowanie Analizujac ˛ doste˛ pne rozwiazania ˛ należy stwierdzić, że nie ma obecnie dedykowanego symulatora błe˛ dów dla systemu Android. Nie istnieja˛ narzedzia, ˛ które umożliwiaja, ˛ w czasie rzeczywistym, na wymuszanie sytuacji krytycznych. Jest to motywacja˛ do opracowania własnego symulatora SWIFI. Należy zaznaczyć, że system Android jest dedykowany urzadzeniom ˛ mobilnym, dlatego możliwości wyste˛ powania błedów ˛ sa˛ bardziej prawdopodobne, a same błedy ˛ bardziej złożone. Co za tym idzie, możliwości testowania aplikacji sa˛ bardzo ograniczone (również ze wzgle˛ du na kompilacje˛ skrośna). ˛ Specyficzne sa˛ również tworzone aplikacje. Bardzo cze˛ sto korzystaja˛ one z dużej ilości dodatkowych modułów czy sensorów (np.: akcelerometr, żyroskop, moduł GPS itp.), co z pewnościa˛ różni je od tych tworzonych na komputery osobiste. Obsługa ta w znacznym stopniu spoczywa na bibliotekach systemowych (co szczegółowo opisano w rozdziale 3), dlatego symulator błe˛ dów powinien umożliwiać wymuszanie sytuacji krytycznych symulujac ˛ zmiane˛ stanu środowiska uruchomieniowego. Ingerowanie w system niesie ze soba˛ kilka dodatkowych wymagań. Należy zapewnić aby modyfikacje dotyczyły wyłacznie ˛ wybranej aplikacji, gdyż w przeciwnym przypadku mogłyby pojawiać sie˛ błedy ˛ spowodowane nieprawidłowym działaniem aplikacji systemowych lub problemami wymuszonymi przez inne programy. Narz˛edzie musi mieć wie˛ c możliwość wyboru oraz identyfikacji aplikacji w ramach, której be˛ dzie działać. Należy również opracować metode˛ powiadamiania programisty o uruchomieniu oraz działaniu symulatora. Musza˛ zostać dostarczone co najmniej informacje o wprowadzonych zmianach, czasie wykonania oraz rezultacie. Pozwoli to na identyfikacje˛ propagacji błedu ˛ oraz miejsc w testowanym programie odpowiedzialnych za jego obsługe. ˛ Wydaje sie, ˛ że sensownym rozwiaza˛ niem be˛ dzie użycie do tego celu systemowego dziennika zdarzeń. Warto również rozważyć możliwość stworzenia narzedzia ˛ ułatwiajacego ˛ kompletowanie informacji o bł˛edach oraz ich analizowania, tak by system był łatwy w obsłudze. Pomocna może być również aplikacja do zarzadzania ˛ systemem działajaca ˛ bezpośrednio na nim, co umożliwiłoby testerowi modyfikacje˛ parametrów działania bez konieczności wykorzystywania komputera osobistego. W oparciu o przedstawiona˛ koncepcje, ˛ stworzony został system realizujacy ˛ zaprezentowane założenia, o nazwie Android Fault Injection System (w skrócie AFIS) opisany w rozdziale 4. 3. Architektura systemu Android System Android oparty został o jadro ˛ systemu Linux, w skład którego wchodza˛ sterowniki oraz moduły np. zarzadzanie ˛ energia˛ - oznaczone kolorem niebieskim na rys. 3.1. Wyżej w hierarchii znajduja˛ sie˛ dostarczane z systemem biblioteki służace ˛ do obsługi operacji wymagajacych ˛ szybkości działania oraz responsywności (grupa LIBRARIES). Na równi z nimi, zaimplementowano środowisko uruchomieniowe systemu Android, w skład którego wchodza˛ główne biblioteki jezyka ˛ Java oraz wirtualna maszyna Dalvik (grupa ANDROID RUNTIME). Jest ona niezależna˛ implementacja˛ wirtualnej maszyny Javy z modyfikacjami wynikajacymi ˛ z nieco odmiennych zastosowań - została zoptymalizowana do działania na urzadzeniach ˛ mobilnych. Służy do uruchamiania aplikacji tworzonych z myśla˛ o systemie Android, które moga˛ korzystać z dostarczanych szkieletów oprogramowania (grupa APPLICATION FRAMEWORK). Głównym je˛ zykiem tworzenia aplikacji jest wiec ˛ Java, który mimo nieco odmiennego środowiska pracy, niczym sie˛ nie różni od wersji przeznaczonej na komputery osobiste. Należy nadmienić, że udostepniono ˛ również możliwość tworzenia pewnych fragmentów aplikacji w jezyku ˛ natywnym C/C++, dzieki ˛ czemu można wykonywać operacje bezpośrednio na systemie, z pominieciem ˛ maszyny Dalvik. Jest to metoda niezalecana i pomimo wrażenia szansy na zwiekszenie ˛ wydajności aplikacji, to w rzeczywistości ten sam efekt możemy osiagn ˛ ać ˛ tworzac ˛ je w je˛ zyku Java [12]. W trakcie działania systemu otrzymujemy możliwość instalowania aplikacji, jednak nie możemy domyślnie modyfikować żadnego z niższych poziomów. Rysunek 3.1. Architektura systemu Android. Źródło [4] 3.1. Opis bibliotek systemu Android 11 Taka struktura systemu powoduje, że najistotniejszym jej elementem, z punktu widzenia programisty, sa˛ dostarczane szkielety oprogramowania. Wykorzystane, mi˛edzy innymi, do naste˛ pujacych ˛ zadań w systemie: — odczytywanie informacji z sensorów urzadzenia ˛ (np.: akcelerometr, żyroskop, kompas, czujnik zbliżenia, czujnik światła itp.) - zapewnia to klasa SensorManager, — zarzadzanie ˛ połaczeniami ˛ (np.: wybieranie numerów, rejestrowanie połacze ˛ ń) ułatwia to klasa TelephonyManager, — zarzadzanie ˛ i obsługa widoków - umożliwiaja˛ to klasy SystemView oraz WindowManager, — obsługa dostarczycieli treści, które odpowiedzialne sa˛ za zarzadzanie ˛ wspólnymi zbiorami danych np.: kontaktami czy wiadomościami sms (umożliwia to ich wykorzystywanie przez wiele aplikacji bez konieczności stosowania dodatkowych mechanizmów synchronizacji czy współdzielenia) - zadanie klasy ContentProvider, — zarzadzanie ˛ systemowym obszarem powiadomień - zapewnia to klasa NotificationManager, — dostarczanie informacji o lokalizacji - umożliwia to klasa LocationManager. W zwiazku ˛ z tym aplikacje oraz system narażone sa˛ na błedy ˛ spowodowane nieprawidłowym wykorzystywaniem dostarczanych w ramach bibliotek metod oraz sytuacjami gdy wywołanie biblioteczne kończy sie˛ niepowodzeniem. AFIS umożliwia przecia˛żanie otwartoźródłowych bibliotek systemu Android emulujac ˛ określone sytuacje krytyczne, dzie˛ ki czemu uaktywniane sa˛ w aplikacji testowanej odpowiedzialne za ich obsługe˛ fragmenty kodu. Ich przetestowanie w konsekwencji prowadzi do wie˛ kszego uodpornienia programu na błedy. ˛ Niestety, system Android wykorzystuje również standardowe biblioteki jezyka ˛ Java których, ze wzgledu ˛ na ograniczenia wynikajace ˛ z licencji, nie ma możliwości modyfikacji. W opracowanym systemie zmianie podlegaja˛ wiec ˛ wyłacznie ˛ biblioteki dostarczane z systemem, których kod źródłowy jest dostepny ˛ na zasadach oprogramowania z otwartymi źródłami. W rozdziale 3.1 opisano najważniejsze z klas oraz metod, które moga˛ być modyfikowane przez AFIS. 3.1. Opis bibliotek systemu Android Biblioteki systemu Android komunikuja˛ sie˛ z programista˛ za pomoca˛ standardowych mechanizmów je˛ zyka Java. Wykorzystuja˛ wiec ˛ one mechanizm wyjatków ˛ oraz zwracaja˛ odpowiednie wartości. Każda klasa oraz jej metody szczegółowo zostały opisane w dokumentacji dla deweloperów [4]. System AFIS modyfikuje te najcze˛ ściej używane: pakiet android.bluetooth dostarcza funkcjonalność zwiazan ˛ a˛ z modułem Bluetooth. Umożliwia wyszukiwanie urzadze ˛ ń, ich dodawanie oraz zarzadzanie ˛ transferem danych. Przecia˛żono nastepuj ˛ ace ˛ klasy: BluetoothServerSocket umożliwia tworzenie oraz zarzadzanie ˛ gniazdami Bluetooth, które sa˛ zbliżone w obsłudze do tych dotyczacych ˛ protokołu TCP. Zmodyfikowano metody: accept(int) - zaakceptowanie przychodzacego ˛ połaczenia ˛ Bluetooth z określonym czasem oczekiwania, 3.1. Opis bibliotek systemu Android 12 accept() - zaakceptowanie przychodzacego ˛ połaczenia ˛ Bluetooth, close() - natychmiastowe zamkniecie ˛ gniazda. BluetoothSocket obiekt gniazda Bluetooth. Zmieniono metody: close() - natychmiastowe zamkniecie ˛ gniazda, connect() - próba połaczenia ˛ ze zdalnym urzadzeniem, ˛ getInputStream() - zwraca obiekt strumienia przychodzacego ˛ dla gniazda, getOutputStream() - zwraca obiekt strumienia wychodzacego ˛ dla gniazda. pakiet android.database.sqlite dostarcza funkcjonalność zwiazan ˛ a˛ z prywatna˛ baza˛ danych wykorzystywana˛ przez aplikacje. Zmodyfikowano nastepuj ˛ ace ˛ klasy: SQLiteOpenHelper ułatwia pobieranie bazy oraz zarzadzenie ˛ wersjami. Przecia˛żono metody: getReadableDatabase() - tworzy lub otwiera prywatna˛ baze˛ w trybie odczytu, getWritableDatabase() - tworzy lub otwiera prywatna˛ baze˛ w trybie odczytu i zapisu. pakiet android.hardware udostepnia ˛ klasy oraz funkcje ułatwiajace ˛ wykorzystanie sprze˛ tu np.: aparatu czy dostepnych ˛ sensorów. Zmodyfikowano klasy: Camera umożliwia wykorzystanie aparatu dostepnego ˛ w urzadzeniu. ˛ Przecia˛ żono metody: open() - tworzy nowy obiekt kamery, unlock() - odblokowuje kamere˛ umożliwiajac ˛ innym procesom jej wykorzystanie. SensorManager pozwala programiście na łatwy dostep ˛ do sensorów urzadze˛ nia. Zmieniono metody: getDefaultSensor(int) - zwraca domyślny sensor, którego typ określono za pomoca˛ przyjmowanego parametru wywołania, registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, android.os.Handler) - rejestruje obiekt dostarczajacy ˛ funkcjonalność podczas zmian wartości z sensora, registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int) - opis funkcjonalność jak w powyższej metodzie. pakiet android.location dostarcza obsługe˛ zwiazan ˛ a˛ z serwisami dotyczacymi ˛ lokalizacji oraz pokrewnymi. Przecia˛żono klasy: Address jest odpowiedzialna za reprezentacje˛ adresu. Zmieniono metody: getAddressLine(int) - zwraca linie˛ adresu określona˛ przez przyjmowany parametr, getLatitude() - zwraca szerokość geograficzna, ˛ getLongitude() - zwraca długość geograficzna, ˛ getPhone() - zwraca numer telefonu, setAddressLine(int, java.lang.String) - ustawia wskazana˛ linie˛ adresu. Geocoder umożliwia kodowanie oraz dekodowanie lokalizacji geograficznych. Zmodyfikowano naste˛ pujace ˛ metody: Geocoder(android.content.Context, java.util.Locale) - zwraca obiekt kodera/dekodera, getFromLocation(double, double, int) - zwraca liste˛ lokalizacji, które przypisane sa˛ do podanego adresu lub znajduja˛ sie˛ w jego okolicach, getFromLocationName(java.lang.String, int) - zwraca liste˛ lokalizacji w pobliżu podanego miejsca, 3.1. Opis bibliotek systemu Android 13 getFromLocationName(java.lang.String, int, double, double, double, double) - jak wyżej, można dodatkowo zdefiniować zakres poszukiwań. Location reprezentujaca ˛ lokalizacje. ˛ Przecia˛żono metody: convert(java.lang.String) - konwertuje położenie geograficzne opisane jako stopnie, minuty, sekundy na liczbe, ˛ convert(double,int) - konwertuje liczbe˛ na położenie geograficzne opisane jako stopnie, minuty, sekundy, distanceBetween(double,double,double,double,float[]) - oblicza przybliżona˛ odległość mie˛ dzy dwoma lokalizacjami. LocationManager daje programiście dostep ˛ systemowych serwisów zwiazanych ˛ z lokalizacja. ˛ Zmieniono metody: addGpsStatusListener(android.location.GpsStatus.Listener) - dodaje obiekt nasłuchujacy ˛ na zmiany stanu modułu GPS, addNmeaListener(android.location.GpsStatus.NmeaListener) - dodaje obiekt nasłuchujacy ˛ na wiadomości NMEA z moduług GPS, addProximityAlert(double, double, float, long, android.app.PendingIntent) - dodaje obiekt realizujacy ˛ zdarzenie na zbliżenie sie˛ lokalizacji, addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int) - umożliwia dodanie obiektu imitujacego ˛ dostarczyciela lokalizacji w systemie, clearTestProviderEnabled(java.lang.String) - usuwa aktywne, imitowane wartości dotyczace ˛ dostarczyciela lokalizacji, clearTestProviderLocation(java.lang.String) - usuwa imitowane wartości zwiazane ˛ z lokalizacja˛ dla dostarczyciela lokalizacji, clearTestProviderStatus(java.lang.String) - usuwa imitowane wartości zwiazane ˛ ze statusem dla dostarczyciela lokalizacji, getLastKnownLocation(java.lang.String) - zwraca ostatnia˛ znana˛ lokalizacje˛ zwiazan ˛ a˛ z dostarczycielem lokalizacji, getProvider(java.lang.String) - zwraca dostarczyciela lokalizacji, isProviderEnabled(java.lang.String) - informuje czy dostarczyciel lokalizacji jest właczony, ˛ removeTestProvider(java.lang.String) - usuwa obiekt imitujacy ˛ dostarczyciela lokalizacji, removeUpdates(android.app.PendingIntent) - usuwa wszystkie obiekty oczekujace ˛ aktualizacji lokalizacji, removeUpdates(android.location.LocationListener) - usuwa wszystkie obiekty nasłuchujace ˛ aktualizacji lokalizacji, requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener) - rejestruje obiekt nasłuchujacy ˛ zmian lokalizacji, requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener, android.os.Looper) - jak wyżej, requestLocationUpdates(java.lang.String, long, float, android.app.PendingIntent) - jak wyżej, setTestProviderEnabled(java.lang.String, boolean) - uaktywnia albo dezaktywuje wskazany obiekt imitujacy ˛ dostarczyciela lokalizacji, 3.1. Opis bibliotek systemu Android 14 setTestProviderLocation(java.lang.String, android.location.Location) - ustawia obiekt lokalizacji dla obiektu imitujacego ˛ dostarczyciela lokalizacji, setTestProviderStatus(java.lang.String, int, android.os.Bundle, long) ustawia status dla obiektu imitujacego ˛ dostarczyciela lokalizacji. pakiet android.media udostepnia ˛ programiście możliwość korzystania z multimediów (muzyka, filmy). Zmodyfikowano klasy: MediaPlayer służy do kontrolowania strumienia dźwiekowego ˛ albo filmowego. Zmieniono metody: create(android.content.Context, android.net.Uri, android.view.SurfaceHolder) - tworzy obiekt odtwarzacza, create(android.content.Context, int) - jak wyżej, create(android.content.Context, android.net.Uri) - jak wyżej, getVideoHeight() - zwraca wysokość klatki filmu, getVideoWidth() - zwraca szerokość klatki filmu, isLooping() - sprawdza czy obiekt odtwarzacza jest ustawiony w trybie odtwarzania w pe˛ tli, isPlaying() - sprawdza czy obiekt coś odtwarza, pause() - zatrzymuje odtwarzacz, prepare() - synchroniczne przygotowanie odtwarzacza do odtwarzania, prepareAsync() - asynchroniczne przygotowanie odtwarzacza do odtwarzania, seekTo(int) - przesuniecie ˛ treści do wskazanego miejsca, setDataSource(java.lang.String) - ustawienie źródła danych, setDataSource(java.io.FileDescriptor, long, long) - jak wyżej, setDataSource(java.io.FileDescriptor) - jak wyżej, start() - odtworzenie pliku, stop() - zastopowanie odtwarzacza. MediaRecorder umożliwia nagrywanie dźwieku ˛ oraz filmów. Przecia˛żono naste˛ pujace ˛ metody: getMaxAmplitude() - zwraca maksymalna˛ amplitude˛ w próbkowanym nagraniu od czasu ostatniego wywołania, prepare() - przygotowuje obiekt do nagrywania, setAudioEncoder(int) - ustawia koder dźwieku, ˛ setAudioSource(int) - ustawia źródło nagrywania dźwieku, ˛ setMaxDuration(int) - ustawia maksymalny czas nagrywania, setMaxFileSize(long) - ustawia maksymalny rozmiar nagrywanego pliku, setOutputFile(java.io.FileDescriptor) - ustawia miejsce zapisu nagrania, setOutputFile(java.lang.String) - jak wyżej, setOutputFormat(int) - ustawia format wyjściowy nagrania, setVideoEncoder(int) - ustawia koder wideo, setVideoFrameRate(int) - ustawia ilość klatek na sekunde˛ dla filmu, setVideoSize(int,int) - ustawia wymiary klatki filmu, setVideoSource(int) - ustawia źródło nagrywania wideo, start() - rozpoczyna nagrywanie, stop() - kończy nagrywanie. pakiet android.net ułatwiajacy ˛ wykorzystanie mechanizmów sieciowych. Przecia˛ żono klasy: 3.1. Opis bibliotek systemu Android 15 ConnectivityManager umożliwia pozyskiwanie informacji o połaczeniu ˛ sieciowym. Zmodyfikowano metody: requestRouteToHost(int, int) - sprawdza czy dana trasa sieciowa istnieje, startUsingNetworkFeature(int, java.lang.String) - zgłoszenie sieci checi ˛ wykorzystanie jej cechy, stopUsingNetworkFeature(int, java.lang.String) - zrezygnowanie z wykorzystania cechy danej sieci. LocalServerSocket daje możliwość tworzenia gniazd sieciowych. Zmieniono metody: accept() - zaakceptowanie połaczenia, ˛ close() - natychmiastowe zamkniecie ˛ gniazda, getFileDescriptor() - zwraca deskryptor gniazda. LocalSocket umożliwia tworzenie gniazd sieciowych, które moga˛ służyć wyłacz˛ nie do łaczenia ˛ (nie serwerowe). Zmodyfikowano metody: bind(android.net.LocalSocketAddress) - zwiazanie ˛ gniazda z adresem, close() - natychmiastowe zamkniecie ˛ gniazda, connect(android.net.LocalSocketAddress, int) - połaczenie ˛ z adresem, connect(android.net.LocalSocketAddress) - jak wyżej, getAncillaryFileDescriptors() - zwraca zbiór deskryptorów plików przez, które wysyłano pomocnicze wiadomości, getFileDescriptor() - zwraca deskryptor gniazda, getLocalSocketAddress() - zwraca adres lokalny, getPeerCredentials() - zwraca listy uwierzytelniajace, ˛ getReceiveBufferSize() - zwraca rozmiar bufora odbioru, getSendBufferSize() - zwraca rozmiar bufora wysyłania, getSoTimeout() - zwraca maksymalny czas oczekiwania na odczyt z gniazda, setReceiveBufferSize(int) - ustawia rozmiar bufora odbioru, setSendBufferSize(int) - ustawia rozmiar bufora wysyłania, setSoTimeout(int) - ustawia maksymalny czas oczekiwania na odczyt z gniazda, shutdownInput() - zamyka odczyt z wejścia gniazda, shutdownOutput() - zamyka odczyt z wyjścia gniazda. pakiet android.network.wifi zwiazany ˛ jest z funkcjonalnościa˛ modułu Wi-Fi. Przecia˛żono naste˛ pujace ˛ klasy: WifiManager dostarcza interfejsy zwiazane ˛ z zarzadzeniem ˛ połaczeniami ˛ Wi-Fi. Zmodyfikowano metody: addNetwork(android.net.wifi.WifiConfiguration) - dodaje konfiguracje˛ nowej sieci Wi-Fi, disableNetwork(int) - wyłacza ˛ dana˛ sieć, disconnect() - rozłacza ˛ z obecnie połaczonym ˛ punktem dostepu, ˛ enableNetwork(int, boolean) - zmienia wartość aktywności danej sieci, getConfiguredNetworks() - zwraca liste˛ skonfigurowanych sieci, isWifiEnabled() - zwraca informacje˛ czy moduł Wi-Fi jest właczony, ˛ reconnect() - powoduje próbe˛ ponownego połaczenia ˛ z aktywnym punktem doste˛ pu, startScan() - rozpoczyna wyszukiwanie punktów dostepowych, ˛ updateNetwork(android.net.wifi.WifiConfiguration) - aktualizuje konfiguracje˛ dla istniejacej ˛ już sieci. 3.1. Opis bibliotek systemu Android 16 pakiet android.os umożliwia wykonywanie podstawowych operacji na serwisach systemowych. Dostarcza również mechanizmy przesyłania wiadomości oraz komunikacji mie˛ dzy procesowej. Zmodyfikowano klasy: Environment ułatwia dostep ˛ do zmienny środowiskowych. Zmieniono metody: getExternalStorageState() - zwraca stan pamieci ˛ dostepnej ˛ do wykorzystania przez użytkownika. PowerManager daje możliwość kontrolowania stanu zasilania urzadzenia ˛ oraz rzeczy z nim zwiazanych. ˛ Zmodyfikowano metody: goToSleep(long) - wymuszenie uśpienia urzadzenia, ˛ isScreenOn() - stan właczenia ˛ ekranu, newWakeLock(int,java.lang.String) - utworzenie nowego obiektu do zarza˛ dzania działaniem systemu (np.: blokada gaszenia ekranu), reboot(java.lang.String) - ponowne uruchomienie systemu. pakiet android.telephony dostarcza interfejsy zwiazane ˛ z modułem telefonu. Przecia˛żono klasy: SmsManager ułatwia wysyłanie wiadomości tekstowych. Zmieniono metody: sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent) - wysłanie podstawowej wiadomości z danymi, sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent) - wysłanie podstawowej wiadomości tekstowej, sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app. PendingIntent>, java.util.ArrayList<android.app.PendingIntent>) wysłanie wielocze˛ ściowej wiadomości tekstowej. pakiet android.webkit dostarcza narzedzi ˛ do przegladania ˛ stron internetowych. Zmodyfikowano klasy: WebView umożliwia wyświetlanie stron WWW w formie widoku. Zmieniono metody: canGoBack() - sprawdzenie czy można wykonać operacje˛ wstecz, canGoBackOrForward(int) - sprawdzenie czy można wykonać operacje˛ wstecz albo wprzód, canGoForward() - sprawdzenie czy można wykonać operacje˛ wprzód, findAddress(java.lang.String) - zwraca podciag ˛ składajacy ˛ sie˛ z odnalezionej fizycznej lokalizacji, getCertificate() - zwraca certyfikat SSL dla strony, pageDown(boolean) - przesuwa widok strony w dół, pageUp(boolean) - przesuwa widok strony w góre, ˛ saveState(android.os.Bundle) - zapisuje stan widoku, zoomIn() - powie˛ ksza wyświetlana˛ strone, ˛ zoomOut() - pomniejsza wyświetlana˛ strone. ˛ Przedstawione klasy oraz metody zostały wybrane arbitralnie na podstawie własnych doświadczeń autora pracy i moga˛ być modyfikowane w trakcie działania systemu Android dzie˛ ki oprogramowaniu AFIS, co dokładniej zostało opisane w rozdziale 4. Stanowia˛ one pewien wycinek z całego API dla systemu Android. Dzieki ˛ 3.1. Opis bibliotek systemu Android 17 przyj˛etym w AFIS rozwiazaniom, ˛ można w zautomatyzowany sposób rozszerzyć pokrycie na kolejne interfejsy szkieletu oprogramowania. Mechanizm ten opisano w instrukcji kompilacji systemu AFIS zawartej w rozdziale 4.1. 4. System AFIS Na podstawie opisu koncepcyjnego (rozdział 2) oraz możliwości modyfikacji systemu Android (rozdział 3), opracowano oprogramowanie Android Fault Injection System (AFIS), w ramach którego dostarczane sa˛ nastepuj ˛ ace ˛ moduły oraz narze˛ dzia pomocnicze (schemat wykorzystania modułów przedstawia rys. 4.1): AFIS Core - najważniejszy element systemu; zawiera szereg modyfikacji źródeł systemu Android, które umożliwiaja˛ dynamiczne wstrzykiwanie kodu do metod z bibliotek; jest on kompilowany razem z systemem; poza dostarczaniem klas umożliwiajacych ˛ obsługe˛ systemu, w jego skład wchodzi również skrypt odpowiedzialny za modyfikacje˛ kodu metod istniejacych, ˛ AFIS Desktop Manager - moduł umożliwiajacy ˛ zarzadzanie ˛ systemem z poziomu komputera; umożliwia automatyczne generowanie kodu wybranej metody, konfiguracje˛ wstrzykiwania kodu, kompilacje˛ nowego kodu metody, modyfikacje˛ parametrów globalnych, przesyłanie oraz usuwanie plików z urzadzania/dysku ˛ lokalnego; z jego poziomu ustawia sie˛ konfiguracje˛ dla przeprowadzanego testu, AFIS Desktop Analyzer - moduł służacy ˛ do zbierania oraz zarzadzania ˛ poszczególnymi badaniami; zawiera również analizator logów systemu umożliwiajac, ˛ na ich podstawie, tworzenie grafów wywołań, wyznaczenie kolejności wykonywania metod, AFIS Android Manager - aplikacja dla systemu Android realizujaca ˛ wybrane funkcje umożliwiajace ˛ modyfikacje˛ ustawień systemu AFIS. Komputer osobisty Kompilacja źródeł Zarządca Android Kompilacja funkcji użytkownika Zmodyfikowany system Przygotowanie konfiguracji Analizator System logowania zdarzeń Urządzenie mobilne lub maszyna wirtualna Rysunek 4.1. Schemat wykorzystania modułów AFIS 4. System AFIS 19 Z punktu widzenia użytkownika systemu istotny jest sposób postepowania ˛ oraz wygoda użytkowania. Niezależnie od tego czy testowaniu bedzie ˛ podlegała aplikacja, do której źródeł mamy dostep ˛ czy też nie - użytkowanie oprogramowania AFIS jest analogiczne. Prace˛ z AFIS należy rozpoczać ˛ od pobrania źródeł systemu Android, ich modyfikacji oraz kompilacji. Cały proces opisano w rozdziale 4.1. Kolejnym krokiem jest instalacja odpowiednich pakietów oraz poszczególnych aplikacji dostarczanych z systemem AFIS, co przedstawiono w rodziale 4.2. Na poczatku ˛ zaleca sie˛ przeprowadzenie rozpoznania, celem wykrycia, z których metod z API korzysta program. Za pomoca˛ aplikacji AFIS Desktop Manager ustawiamy opcje˛ złotego przebiegu. Nastepnie ˛ korzystajac ˛ AFIS Desktop Analyzer zapisujemy log generowany podczas korzystania z analizowanej aplikacji, tworzymy graf wywołań oraz eliminujemy metody, których badanie nas nie interesuje (np. ich znaczenie jest marginalne). Kiedy wiemy już co chcemy testować, możemy przejść do przygotowywania testów. W module AFIS Desktop Manager wybieramy dana˛ metode˛ , ustalamy konfiguracje, ˛ generujemy, modyfikujemy oraz kompilujemy plik źródłowy (przedefiniowujac ˛ oryginalna˛ metode˛ na kod emulujacy ˛ określone zachowanie), a naste˛ pnie zapisujemy konfiguracje˛ i wysyłamy na urzadzenie ˛ wykorzystywane do badań aplikacji. Od tego momentu, dla zdefiniowanej procedury, symulator rozpocznie jej przecia˛żanie w zależności od ustawionych opcji. W tym momencie można przejść do wykonywania testów, rejestrujac ˛ je za pomoca˛ analizatora. Dalej sposób poste˛ powania może być różny w zależności od przyjetej ˛ metodologii testowania. W naste˛ pnym rozdziale przedstawiono przykłady użycia systemu, które pozwalaja˛ zlokalizować proste błedy. ˛ Schemat z rys. 4.2 przedstawia szczegółowo działanie systemu AFIS i jego sposób interpretacji dostarczanej konfiguracji. System w działaniu wykorzystuje specjalnie przygotowana˛ wersje˛ systemu, która dzie˛ ki modyfikacji źródeł bibliotek opisanych w rozdziale 3.1 umożliwia dynamiczna˛ zmiane˛ ich kodu. Na podstawie dostarczanych plików konfiguracyjnych podejmowana jest decyzja o charakterze wywołania metody. Tu rozróżnia sie˛ kilka możliwości: — wybrano opcje˛ złotego przebiegu, która powoduje, że użytkownik informowany jest o wykonaniu przechwytywanej metody, ale ich oryginalny kod nie jest przecia˛żany, — wybrano opcje˛ przecia˛żenia metody - zwracany jest wynik zmodyfikowanego kodu albo rzucany wyjatek, ˛ — wyjatek ˛ rzucany przez przecia˛żona˛ metode˛ jest klasy AFISFakeException, co powoduje, że podmieniane sa˛ parametry wywołania metody źródłowej i jest ona dalej wywoływana normalnie, — metoda nie jest przeznaczona do wywołania dla tej aplikacji. Informowanie użytkownika o wykonywanych zdarzeniach odbywa sie˛ za pomoca˛ logowania zdarzeń. W zależności od konfiguracji moga˛ one być dostepne ˛ z poziomu mechanizmu logów systemowych (logcat) lub do odczytania na karcie pamieci. ˛ Maja˛ one naste˛ pujac ˛ a˛ postać: [ s t a t e ] [ function ] ( [ pid ] [ call_from ] ) [ time ] description 20 4. System AFIS Rozpoczęcie wykonywania funkcji ze zrębów Opcja globalnego złotego przebiegu Tak Zalogowanie wyłowania Nie Wykonanie fukcji z przebiegiem normalnym Wczytanie konfiguracji funkcji 1 Skonfigurowany PID zgadza się z wywołaniem Nie Tak Opcja złotego przebiegu funkcji Tak Nie Spełniono warunek prawdopodobieństwa Nie Tak Załadowanie kodu funkcji Zalogowanie błędu 1 Błędy podczas ładowania Tak Zaloguj wyjątek Rzuć wyjątek Tak Nie Wyjątek dopuszczony przez funkcję Wykonanie przeciążonego kodu Nie Zaloguj informację Nie Funkcja rzuciła wyjątek Tak Wyjątek Symulatora Błędów Tak Podmień parametry wykonania Zaloguj wykonanie Wywołaj funkcję Nie Zaloguj wykonanie Zwróć wynik funkcji przeciążonej Rysunek 4.2. Schemat działania systemu AFIS 21 4. System AFIS Gdzie poszczególne pola maja˛ nastepuj ˛ ace ˛ znaczenie: — state - stan zdarzenia: RUN - wywołanie metody, CONFIG - komunikaty dotyczace ˛ konfiguracji, EXCEPTION - metoda rzuciła wyjatek, ˛ GRUN - opcja złotego przebiegu dla metody, — function - pełna nazwa metody, której dotyczy komunikat. Jeśli jej wartość to NONE - komunikat dotyczy systemu. W przeciwnym razie dostepne ˛ sa˛ pola pid oraz call_from, — pid - numer pid procesu (aplikacji), — call_from - funkcja, która wywołała przecia˛żona˛ metode. ˛ Jeśli to możliwe dostarczana jest informacja o klasie oraz numerze linii, z którego nastapiło ˛ wywołanie, — description - wiadomość komunikatu. Wpis poprzedzony jest poziomem logowania oraz znacznikiem aplikacji - w tym przypadku ciagiem ˛ znaków D/AFIS. Tak przyjeta ˛ struktura umożliwia łatwa, ˛ automatyczna˛ analize˛ komunikatów, która została zaimplementowana w ramach modułu analizatora. Przecia˛żane funkcje musza˛ być tworzone według ściśle określonych zasad. Użytkownik wykorzystujacy ˛ dostarczane oprogramowanie nie musi tworzyć nowych przecia˛żeń od podstaw - otrzymuje możliwość poprawnego generowania szablonów dla wybranych metod, niemniej jednak warto znać uwarunkowania systemu. Przy pomocy programu AFIS Desktop Manager użytkownik przeglada ˛ dost˛epne klasy z bibliotek systemu Android, które zostały przecia˛żone w ramach systemu AFIS oraz wskazuje na interesujace ˛ go metody, których działanie chce przedefiniować. Z jej poziomu automatycznie generuje plik źródłowy z szablonem przecia˛żanej metody. Utworzony w ten sposób plik zawiera klase˛ OverrideClass, która z kolei posiada metode˛ run. Owa metoda musi przyjmować argumenty oraz zwracać wartość tej samej klasy co metoda przecia˛żana. Wydruk 4.1 prezentuje wygenerowany plik klasy dla metody android.location.LocationManager.getLastKnownLocation(java.lang. String).java. Tak przygotowana klasa kompilowana jest przez kompilator javac, a naste˛ pnie (plik wynikowy) przez ten właściwy dla wirtualnej maszyny Dalvik - dx. Kolejno, zmieniana jest nazwa pliku na classes.dex i tworzony z nim plik jar. Na koniec należy zadbać o odpowiednia˛ nazwe, ˛ a mianowicie musi być ona określona dokładnie tak jak pełna nazwa metody (z pakietem i klasa) ˛ wraz z typami argumentów wywołania bez znaku spacji. Takie przygotowanie umożliwi poprawne wywołanie metody przez moduł AFIS Core. 1 5 import java . lang . IllegalArgumentException ; public class OverrideClass { public android . l o c a t i o n . Location run ( java . lang . String arg0 ) throws java . lang . IllegalArgumentException { // place yours code here return null ; } } Wydruk 4.1. Szablon przecia˛żanej metody 4.1. Kompilacja systemu 22 Wykorzystanie możliwości modyfikacji argumentów wywoływanej metody jest możliwe dzie˛ ki wykorzystaniu wyjatku ˛ AFISFakeException. W takim przypadku należy rzucić wyjatek ˛ tej klasy, w konstruktorze podajac ˛ liste˛ obiektów bed ˛ acych ˛ nowymi parametrami. Należy pamietać ˛ o odpowiedniej kolejności. Przykład użycia dla metody android.location.Location.distanceBetween(double,double, double,double,float[]) zaprezentowano na wydruku 4.2. 1 5 import android . a f i s c o r e . AFISFakeException ; public class OverrideClass { public void run ( double arg0 , double arg1 , double arg2 , double arg3 , f l o a t [ ] arg4 ) throws AFISFakeException { Object [ ] newArgs = { 0.0 , 0.1 , 0.2 , 0.3 , arg4 } ; throw new AFISFakeException ( newArgs ) ; } } Wydruk 4.2. Szablon przecia˛żanej metody ze zmiana˛ argumentów wywołania Funkcjonalność oraz sposób użytkowania dostarczanego w ramach AFIS oprogramowania zostały dokładnie opisane rozdziale 4.3. 4.1. Kompilacja systemu W ramach Android Fault Injection System dostarczany jest specjalnie przygotowany system Android. Jeśli jednak użytkownik chce dokonać własnych zmian lub usprawnień, może skompilować źródła sam. Pierwszym wymaganiem jest konieczność posiadania systemu Linux. Jeśli chcemy kompilować wersj˛e Androida od 2.2, potrzebna jest wersja 64 bitowa wybranej dystrybucji. Poniżej przedstawiono kroki poste˛ powania, na przykładzie systemu Ubuntu 13.04 64-bit oraz dla Androida 4.1.2. Na wste˛ pie należy zaznaczyć, że pakiety dystrybucji nie zostały zaktualizowane co pomaga uniknać ˛ problemu ze zbyt nowa˛ wersja˛ kompilatora gcc. Dla ustalenia uwagi, niniejsza kompilacja wykonywana jest w oparciu o gcc 4.7.3. Kroki post˛epowania przygotowano w oparciu o oficjalny poradnik [3]. W przedstawianym przypadku rozpoczynamy od instalacji odpowiedniej wersji środowiska Java. W tym celu dodajemy odpowiednie repozytorium oraz instalujemy pakiet oracle-java6-installer - zgodnie z wydrukiem 4.3. 1 sudo add−apt−r e p o s i t o r y ppa : webupd8team/java sudo apt−get update sudo apt−get i n s t a l l oracle−java6−i n s t a l l e r Wydruk 4.3. Dodanie repozytorium oraz instalacja odpowiedniej wersji środowiska Java Kolejny krokiem jest wyposażenie systemu w odpowiednie zależności - wydruk 4.4. 4.1. Kompilacja systemu 1 5 23 sudo apt−get i n s t a l l g i t gnupg f l e x bison gperf build−e s s e n t i a l \ zip curl libc6−dev libncurses5−dev : i386 x11proto−core−dev \ libx11−dev : i386 l i b r e a d l i n e 6 −dev : i386 l i b g l 1 −mesa−glx : i386 \ l i b g l 1 −mesa−dev g++−m u l t i l i b mingw32 tofrodos \ python−markdown libxml2−u t i l s xsltproc zlib1g−dev : i386 Wydruk 4.4. Instalacja zależności niezbednych ˛ do kompilacji systemu Android Kolejnym krokiem jest pobranie źródeł systemu. W tym celu tworzymy w katalogu domowym (lub innym) folder android-build, a w nim katalog bin, który dodajemy do zmiennej środowiskowej PATH. Naste˛ pnie pobieramy skrypt do obsługi repozytorium curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > /bin/repo i konfigurujemy pakiet git. W tym celu musimy podać nasze imi˛e i nazwisko oraz adres e-mail (wydruk 4.5). 1 g i t config −−global user .name " Imie Nazwisko " g i t config −−global user . email " adres@email . pl " Wydruk 4.5. Konfiguracja pakietu git Przechodzimy do utworzonego katalogu android-build i wykonujac ˛ polecenie repo init -u https://android.googlesource.com/platform/manifest -b android-4.1.2_r1 inicjalizujemy repozytorium1 . Komenda˛ repo sync rozpoczynamy pobieranie plików źródłowych - przed rozpoczeciem ˛ właściwej operacji może pojawić sie˛ pytanie odnoście kolorowania wypisywanych treści dla komend status oraz diif, wybieramy opcje˛ właściwa˛ dla swoich preferencji. Po pomyślnym zakończeniu pobrania źródeł, rozpoczynamy konfiguracje˛ opcji kompilacji. Służy do tego komenda source build/envsetup.sh, która˛ wykonujemy z katalogu głównego pobranych źródeł. Nastepnie ˛ poleceniem lunch wyświetlamy liste˛ doste˛ pnych możliwości. Domyślnie, system AFIS korzysta z emulatora, wie˛ c wybieramy full-eng czyli opcje˛ pierwsza. ˛ Istnieje możliwość kompilacji systemu Android wraz z oprogramowaniem AFIS na fizycznych urzadzeniach, ˛ jednak sposób poste˛ powania jest zależny od producenta urzadzenia. ˛ Pobrane źródła umożliwiaja˛ bezproblemowe przygotowanie takie wersji systemu na urzadzenia ˛ wspierane przez firme˛ Google, które ujeto ˛ w repozytorium (na obecna˛ chwile˛ sa˛ to mi˛edzy innymi: wszystkie urzadzenia ˛ z serii Nexus, HTC One, Samsung Galaxy S4 oraz Sony Xperia Z). Ostatnim krokiem jest zbudowanie systemu. W tym celu należy wykonać polecenie make -jX, gdzie X określa ilość watków, ˛ które chcemy przeznaczyć na kompilacje˛ . Jeśli poprawnie przygotowaliśmy system, wszystko powinno przebiec pomyślnie. Po poprawnej kompilacji, można uruchomić przygotowany system, poleceniem emulator. Zaleca sie˛ dodanie opcji -gpu on, która wymusza użycie akceleracji na karcie graficzne (zapewnia to płynniejsze działanie). Możliwe jest również dołaczenie ˛ 1 Nazwy gał˛ezi poszczególnych wersji systemu Android sa˛ dost˛epne na stronie projektu [3] 4.1. Kompilacja systemu 24 karty pamie˛ ci - -sdcard file_name.img. Można je wytworzyć za pomoca˛ narze˛ dzia mksdcard znajdujacego ˛ sie˛ w źródłach w katalogu /sdk/emulator. Wystarczy wykonać polecenie mksdcard -l sdcard_label size file_name.img. Teraz możemy przejść do modyfikacji źródeł, czyli wprowadzeniu zmian z modułu AFISCore. W tym celu wykonujemy kopie˛ zapasowa˛ folderu frameworks ze źródeł systemu Android, a nast˛epnie modyfikujemy zmienna˛ working_directory ze skryptu modify_android_source.py, który uruchamiamy. Należy wspomnieć, że lista funkcji do przecia˛żenia dostarczana jest z pliku csv, który z kolei generowany jest na podstawie arkusza kalkulacyjnego ods. Rozszerzanie systemu jest wie˛ c możliwe w bardzo prosty sposób, a mianowicie, wystarczy dodać nowa˛ metode˛ do tego pliku (wzorem poprzednich metod) oraz wyeksportować go do wspomnianego formatu. Po jego poprawnym zakończeniu otrzymujemy informacje, które z funkcji zostały odnalezione oraz które z nich oznaczone sa˛ jako natywne i wymagaja˛ re˛ cznej modyfikacji plików. Zmiany te zostana˛ opisane na przykładzie funkcji setDataSource(FileDescriptor, long, long) z klasy android.media.MediaPlayer. Wystarczy odnaleźć plik zawierajacy ˛ implementacj˛e szukanej klasy w je˛ zyku C++. W tym przypadku znajduje sie˛ on w katalogu frameworks/base/media/jni pod nazwa˛ MediaPlayer.cpp. Nastepnie ˛ odszukujemy liste˛ funkcji natywnych i modyfikujemy linie˛ z szukana˛ funkcja, ˛ dodajac ˛ do jej nazwy ’_n’. Jest to konieczny zabieg umożliwiajacy ˛ przecia˛żanie metod, które faktycznie stworzono w jezyku ˛ natywnym. System AFIS tworzy metod˛e o identycznej nazwie, dodajac ˛ jednocześnie do oryginalnej końcówke˛ ’_n’. Programista wywołuje wie˛ c zmieniona˛ metode˛ w jezyku ˛ Java, która z kolei odwołuje sie˛ do jej natywnej implementacji. Kolejnym krokiem jest przekopiowanie folderu pakietu afiscore do katalogu frameworks/base/core/java/android. Konieczna jest również modyfikacja wirtualnej maszyny Dalvik, tak aby możliwe było zapisywanie zoptymalizowanych plików w dowolnym katalogu. Zmiany wymaga plik libcore/dalvik/src/main/java/dalvik/system/DexFile.java, w którym linie od 97 do 106 (włacznie) ˛ zamieniamy na String parent = new File(outputName).getParent();. Chodzi o to aby uniknać ˛ sprawdzenia właściciela katalogu - modyfikacja ta nie jest konieczna we wszystkich wersjach systemu Android. Po przystosowaniu źródeł, możemy przejść do ponownej kompilacji systemu. Post˛epujemy analogicznie jak ostatnio, z ta˛ różnica, ˛ że przed samym budowaniem systemu wykonujemy polecenie make update-api -jX, które ma na celu aktualizacj˛e listy doste˛ pnych funkcji oraz pozwoli na wcześniejsze wykrycie ewentualnego bł˛edu w przypadku niepoprawnej modyfikacji źródeł. Po pomyślnym zakończeniu tej operacji, ponownie właczamy ˛ emulator oraz za pomoca˛ polecenia adb shell logujemy sie˛ na konsoli uruchomionego systemu. Nastepnie ˛ tworzymy odpowiednia˛ strukture˛ katalogów: — /data/data/pl.msulek.afiscore/files - zawiera plik konfiguracyjne, źródłowe oraz postać skompilowana˛ funkcji, — /data/data/pl.msulek.afiscore/log - zawiera konfiguracje˛ systemu oraz plik logu: — logcat - jeśli plik istnieje, informacje z systemu AFIS sa˛ logowane za pomoca˛ mechanizmów systemowych, — logsd - jeśli plik istnieje, informacje z systemu AFIS sa˛ logowane do pliku /data/data/afiscore/log/AFISLog.log, 4.2. Instalacja oprogramowania 25 — goldenrun - jeśli plik istnieje, opcja globalnego złotego przebiegu jest aktywna. — /data/data/pl.msulek.afiscore/dex - zawiera pliki optymalizacyjne dynamicznie ładowanego przecia˛żonego kodu. Sa˛ tworzone przez wykorzystywana˛ w module AFISCore klase˛ DexClassLoader. Należy zadbać aby każdy miał uprawnienia do zapisu i odczytu z opisanych katalogów. 4.2. Instalacja oprogramowania Poniżej przedstawiono sposób instalacji oraz uruchamiania aplikacji z systemu AFIS. Aplikacje komputerowe do poprawnego działania wymagaja˛ skonfigurowanego środowiska Software Development Kit (w skrócie SDK) dla systemu Android. Opis instalacji doste˛ pny jest na oficjalnej stronie https://developer.android. com/sdk/index.html. Ponieważ przecia˛żone metody oraz klasy opieraja˛ sie˛ o API w wersji 8, to właśnie je należy zainstalować z dostarczonego menedżera. Ważne jest aby aplikacja Android Debug Bridge (w skrócie adb) dodana była do zmiennej środowiskowej PATH. Dostarczone oprogramowanie, przeznaczone na komputery, do funkcjonowania wymaga zainstalowanego interpretera jezyka ˛ Python oraz biblioteki odpowiedzialnej za interfejs wxGlade wraz z dowiazaniami ˛ do wspomnianego jezyka ˛ programowania. W systemie Ubuntu 13.04, na którym były one testowane, należy zainstalować naste˛ pujace ˛ python2.7 oraz python-wxglade. Jeśli w aplikacji AFIS Desktop Analyzer chcemy mieć możliwość generowania grafów wywołań należy doinstalować biblioteke˛ python-pygraphviz. Po skonfigurowaniu systemu możemy przejść do uruchomienia aplikacji. We właściwych folderach wydajemy odpowiednie komendy - python AFISDesktopManager.py dla AFIS Desktop Manager oraz python AFISDesktopAnalyzer.py dla AFIS Desktop Analyzer. Należy również wspomnieć, że jeśli w drugiej z wymienionych aplikacji chcemy wykorzystać opcje˛ uruchomienia pierwszej ze specjalnymi parametrami, to powinniśmy zadbać o zachowanie oryginalnej struktury katalogów (opisanej w dodatku A, tak by możliwe było importowanie plików źródłowych. Instalacja AFIS Android Manager wymaga uruchomionego emulatora albo urzadzenia ˛ podłaczonego ˛ do komputera w trybie programisty. Nastepnie ˛ w katalogu zawierajacym ˛ plik AFISAndroidManager.apk uruchamiamy polecenie adb install AFISAndroidManager.apk, co spowoduje jej instalacje˛ na urzadzeniu ˛ docelowym. Pojawi sie˛ ona wówczas automatycznie na liście zainstalowanych aplikacji. 4.3. Użytkowanie systemu AFIS Poniższy rozdział zawiera szczegółowy opis funkcji programów dostarczanych w ramach systemu AFIS. 4.3. Użytkowanie systemu AFIS 26 4.3.1. AFIS Desktop Manager Program służacy ˛ do zarzadzania ˛ systemem z poziomu komputera. Okno główne (rys. 4.3) zawiera liste˛ wszystkich metod, które zostały przecia˛żone w systemie. Sa˛ one wczytywane z dostarczanego pliku w formacie xml, który tworzony jest na podstawie listy przecia˛żonych metod. Dostepne ˛ sa˛ cztery grupy opcji: dotyczace ˛ zaznaczonej metody, dotyczace ˛ wszystkich metod, ogólne opcje systemu oraz informacje oraz zamykanie aplikacji. W pierwszej z nich należy wyróżnić nastepuj ˛ ac ˛ a˛ funkcjonalność: — Override options - okno umożliwiajace ˛ konfiguracje˛ metody (opis poniżej), — Details - okno wyświetlajace ˛ szczegóły dotyczace ˛ metody (opis poniżej), — Generate source code file - generuje szablon pliku źródłowego dla metody (w katalogu src_dex), — Compile - kompiluje plik źródłowy przypisany do metody (plik o nazwie metody wraz z argumentami wywołania, w katalogu src_dex), — Send java and jar file - wysłanie pliku źródłowego oraz skompilowanego na urzadzenie/emulator, ˛ — Save configuration - zapisanie ustalonej konfiguracji, — Send configuration - wysłanie konfiguracji na urzadzenie/emulator, ˛ — Remove function’s local files - usuniecie ˛ plików powiazanych ˛ z funkcja˛ z komputera, — Remove function’s remote files - usuniecie ˛ plików powiazanych ˛ z funkcja˛ z urza˛ dzenia/emulatora. Druga grupa umożliwia zbliżone operacje na wszystkich funkcjach z listy: — Generate all source code files - wygenerowanie szablonów plików źródłowych dla wszystkich metod, — Compile all - skompilowanie wszystkich plików źródłowych, — Send java and jar files - wysłanie wszystkich istniejacych ˛ plików źródłowych oraz skompilowanych na urzadzenie/emulator, ˛ — Save configurations - zapisanie konfiguracji wszystkich funkcji, — Send configurations - wysłanie wszystkich istniejacych ˛ plików konfiguracji, — Remove all functions’ local files - usuniecie wszystkich plików dotyczacych ˛ funkcji z komputera, — Remove all functions’ remote files - usuniecie ˛ wszystkich plików dotyczacych ˛ funkcji z urzadzenia/emulatora. ˛ Ogólne opcje systemu: — System logging - jeśli zaznaczona to informacje z systemu bed ˛ a˛ logowane za pomoca˛ systemowego dziennika zdarzeń (logcat), — File logging - jeśli zaznaczona to informacje z systemu bed ˛ a˛ zapisywane do pliku, — Global golden run - jeśli zaznaczona to aktywna bedzie ˛ opcja globalnego złotego przebiegu, — Apply - zatwierdzenie powyższych opcji i rekonfiguracja systemu. Okno przedstawione na rys. 4.4 służy do konfiguracji przecia˛żenia funkcji w systemie. Zawiera naste˛ pujace ˛ opcje: — Set the probability of error - ustalenie wartości prawdopodobieństwa przecia˛żenia funkcji w systemie, 4.3. Użytkowanie systemu AFIS 27 — Golden run - ustawienie złotego przebiegu dla funkcji, — Select applications for override - wybór aplikacji, dla których funkcja bedzie ˛ przecia˛żana, — ostatnie pole umożliwia zdefiniowanie opcji przecia˛żania funkcji dla aplikacji o numerze procesu równym lub wiekszym ˛ podanemu. Rysunek 4.3. Okno główne aplikacji zarzadcy ˛ Rysunek 4.4. Okno konfiguracji przecia˛żanej metody 4.3. Użytkowanie systemu AFIS 28 Okno z rys. 4.5 wyświetla nastepuj ˛ ace ˛ informacje o funkcji (zaczerpniete ˛ z oficjalnej dokumentacji): — nazwa funkcji, — opis funkcji, — parametry wywołania, — adres do strony w dokumentacji, — typ zwracanego obiektu, — opis wartości zwracanej lub rzucanych wyjatków, ˛ — typy rzucanych wyjatków. ˛ Rysunek 4.5. Okno szczegółów przecia˛żanej metody 4.3.2. AFIS Desktop Analyzer Aplikacja służaca ˛ do zarzadzania ˛ testami oraz umożliwiajaca ˛ analize˛ logów. Główne okno programu (rys. 4.6) zawiera liste˛ analiz dostepnych ˛ w ramach wybranego katalogu pracy. Dostepne ˛ sa˛ nastepuj ˛ ace ˛ funkcje: — Select workspace - wybór katalogu roboczego, — Create new - tworzenie nowej analizy, — Show/edit analysis - wyświetlanie i edycja analizy, — Remove analysis - usuwanie analizy. Okno analizy, przedstawione na rys. 4.7, umożliwia wprowadzenie informacji o teście: nazwa, opis, plik logów oraz wnioski. Dodatkowo umożliwia wywołanie okna przechwytywania logów (rys. 4.8) oraz okna analizatora dziennika zdarzeń (rys. 4.9). Pierwsze z nich pozwala na wybranie ścieżki oraz zapis zdarzeń z systemu. Należy pamie˛ tać, że przycisk rozpoczynajacy ˛ zapis powoduje wyczyszczenie logów (obsługa dziennika zdarzeń systemu Android odbywa sie˛ za pomoca˛ narze˛ dzia adb dostarczanego w ramach SDK tego systemu). Opcja Next test automatycznie kończy przechwytywanie, zmienia nazwe˛ - rozszerzajac ˛ wybrana˛ o kolejny numer oraz rozpoczyna procedure˛ ponownie. Jest to pewne uproszczenie w przypadku tworzenia wielu zapisów dla jednej analizy. Najważniejsza˛ cześci ˛ a˛ aplikacji jest analizator logów. Główna lista domyślnie wyświetla liste˛ wykorzystywanych funkcji, które przecia˛żane sa˛ przez system. Każdy z elementów posiada liste˛ metod, 4.3. Użytkowanie systemu AFIS 29 Rysunek 4.6. Główne okno aplikacji analizatora które je wywoływały. Każda z nich opatrzona jest stosownymi wpisami potwierdzajacymi ˛ ten fakt, które zawieraja˛ dodatkowe informacje: kolejność, data i czas zapisania informacji, stan systemu, numer procesu oraz wiadomość. Dostarczono dodatkowe funkcje ułatwiajace ˛ analize: ˛ Rysunek 4.7. Okno modyfikacji lub tworzenia analizy 4.3. Użytkowanie systemu AFIS 30 — All calls - informacja o sumarycznej ilości wywołań, — Overrides - ilość przecia˛żeń (nie wliczaja˛ sie˛ w to wykonania z opcja˛ złotego przebiegu, — Show function’s calls number - wygenerowany graf bedzie ˛ zawierał ilość wywołań danej funkcji, — Show functions order - na wygenerowanym grafie, do każdej przecia˛żonej funkcji, zostanie dołaczona ˛ informacja o kolejności wykonania, — Remove usless pids - pozwala na usuniecie ˛ z logów informacji o aplikacjach zewne˛ trznych, które zostały zapisane przez system, — Execute Desktop Manager - uruchamia aplikacje˛ AFIS Desktop Manager filtrujac ˛ liste˛ wszystkich dostepnych ˛ funkcji tak aby wyświetlane były wyłacznie ˛ te odnalezione podczas analizy, — Callers tree - wyświetla funkcje wraz z miejscami wywołań, — Order tree - wyświetla funkcje wraz z kolejnościa˛ ich wywołania, — Generate graph - generuje graf wywołań, — Show graph - wyświetla graf, — Save graph as SVG - zapisuje graf w postaci pliku SVG, — Save graph as PNG - zapisuje graf w postaci pliku PNG, Rysunek 4.8. Okno przechwytywania logów Rysunek 4.9. Okno wyników analizy pliku logów 4.3. Użytkowanie systemu AFIS 31 4.3.3. AFIS Android Manager AFIS Android Manage tp aplikacja służaca ˛ do zarzadzania ˛ systemem AFIS bezpośrednio z systemu Android. Jej funkcjonalność jest ograniczona ze wzgledu ˛ na brak możliwości kompilacji kodów źródłowych przecia˛żonych funkcji. Dodatkowo brakuje opcji odpowiedzialnej za konfiguracje˛ wywołań modyfikowanych metod dla aplikacji z numerem procesu równym lub wiekszym ˛ niż podany. Zachodzi bowiem obawa, że jego przypadkowe ustawienie może doprowadzić do zaburzenia działania systemu, a w założeniu, zarzadca ˛ dla systemu Android ma funkcjonować na urza˛ dzeniach testerów, wie˛ c proces ten pozbawiony jest ścisłej kontroli. Główny widok aplikacji (rys. 4.10) prezentuje liste˛ przecia˛żonych funkcji. Dłuższe przytrzymanie powoduje wyświetlenie informacji o wybranej metodzie. Podano informacje analogiczne do tych w aplikacji dla komputera. Pojedyncze klikniecie ˛ przenosi do widoku opcji (rys. 4.11). Wybranie przycisków skutkuje nastepuj ˛ acymi ˛ zmianami: — Apply - zatwierdzenie zmian, — Reset settings - usunie˛ cie plików konfiguracyjnych oraz zmian w programie, — Reload configuration - ponowne wczytanie zmian, ignoruje zmiany w aplikacji. Dodatkowo wybranie systemowego przycisku menu powoduje wyświetlenie dwóch opcji: Settings oraz About. Pierwsza z nich przenosi do widoku przedstawionego na rys. 4.12 gdzie możemy dokonać zmian ogólnych systemu - analogicznie do opisu zarzadcy ˛ dla komputera. Druga z nich wyświetla informacje o programie. Rysunek 4.10. Widok główny aplikacji AFIS Android Manager Widok konfiguracji przecia˛żenia funkcji (rys. 4.11) umożliwia ustawienie wartości prawdopodobieństwa, wyboru opcji złotego przebiegu oraz wybór aplikacji. Dodatkowo za pomoca˛ opcji Clear unused pids możemy usnać ˛ numery procesów aplikacji, których nie ma na liście, a sa˛ w konfiguracji. Przycisk Show code umożliwia wyświetlenie zmodyfikowanego kodu powiazanego ˛ z funkcja˛ (rys. 4.13). 4.3. Użytkowanie systemu AFIS Rysunek 4.11. Widok opcji funkcji Rysunek 4.12. Widok ogólnych ustawień systemu 32 4.4. Przykłady użycia 33 Rysunek 4.13. Widok przecia˛żonego kodu funkcji 4.4. Przykłady użycia Dla lepszego zrozumienia działania systemu AFIS przygotowano klika przykładów jego użycia. W tym celu opracowano aplikacje testowe MediaPlayerCreate-Demo, MediaPlayerThreadsDemo, TestProviderDemo, w których zaszyto intencjonalnie różnego rodzaju bł˛edy (w oparciu o rzeczywiste przykłady zaczerpniete ˛ z [4]). 4.4.1. Zaniechanie sprawdzenia rezultatu wykonania metody Biblioteki systemu Android określaja˛ swój stan za pomoca˛ mechanizmu wyjat˛ ków albo zwracanej wartości. Czesto ˛ zdarza sie, ˛ że programista ignoruje rezultat zwracany przez metode˛ , co może powodować wiele nieprawidłowości. Przyjrzyjmy si˛e przykładowemu użyciu klasy MediaPlayer zaczerpnietemu ˛ z oficjalnej strony dla deweloperów systemu, zaprezentowanemu na wydruku 4.6. 1 MediaPlayer mediaPlayer = MediaPlayer . create ( context , R. raw . sound_file_1 ) ; mediaPlayer . s t a r t ( ) ; //no need t o c a l l prepare ( ) ; create ( ) does that f o r you Wydruk 4.6. Użycie klasy MediaPlayer. Źródło [4] Zgodnie z dokumentacja˛ 2 metoda create odpowiada za utworzenie oraz przygotowanie obiektu odtwarzacza. W przypadku niepowodzenia zwraca ona pusty obiekt null. Zaprezentowany kod ignoruje ten fakt, co w przypadku błedu ˛ bedzie ˛ powodowało krytyczne zakończenie programu. Załóżmy jednak, że nie mamy dostepu ˛ do kodu aplikacji. Za pomoca˛ opcji złotego przebiegu wyznaczamy używane metody. Poniższy fragment logu systemowego (wydruk 4.7; ze wzgle˛ du na czytelność cześć ˛ informacji zastapiono ˛ wielokropkiem), 2 Dokumentacja dla klasy media.MediaPlayer [4] 4.4. Przykłady użycia 34 jednoznacznie wskazuje na bezpośrednie użycie metod create (linia 1) oraz start (linia 11) przez program. Używane sa˛ również setDataSource oraz prepare, jednak one sa˛ wywoływane przez create (linie od 4 do 10), dlatego nie musza˛ podlegać testowaniu. 1 5 10 D/AFIS ( 692) : [GRUN] [ android . media . MediaPlayer . create ( android . content . Context , i n t ) ][692][...][2013 −04 −10 19:57:41.561] Golden run f o r function . ( global option ) D/AFIS ( 692) : [GRUN] [ android . media . MediaPlayer . setDataSource ( java . i o . FileDescriptor , long , long ) ] [ 6 9 2 ] [ android . media . MediaPlayer . create ( MediaPlayer . java :929)][2013−04−10 19:57:41.700] Golden run f o r function . ( global option ) D/AFIS ( 692) : [GRUN] [ android . media . MediaPlayer . prepare ( ) ] [ 6 9 2 ] [ android . media . MediaPlayer . create ( MediaPlayer . java :931) ] [ 2013−04−10 19:57:42.082] Golden run f o r function . ( global option ) D/AFIS ( 692) : [GRUN] [ android . media . MediaPlayer . s t a r t ( ) ] [ 6 9 2 ] [ ...][2013−04−10 19:57:42.184]Golden run f o r function . ( global option ) Wydruk 4.7. Fragment logu systemowego z rozpoznania analizowanej aplikacji Naste˛ pnie możemy przejść do badania zachowania aplikacji podczas wymuszania błe˛ dów w wyznaczonych metodach. Ponieważ zależy nam na zbadaniu konkretnego przypadku (metodzie create) to skupimy sie˛ wyłacznie ˛ na tym przypadku. Za pomoca˛ oprogramowania AFIS generujemy plik źródłowy dla przecia˛żanej metody i tworzymy kod odpowiadajacy ˛ temu z wydruku 4.8. 1 5 public class OverrideClass { public MediaPlayer run ( android . content . Context arg0 , int arg1 ) { return null ; } } Wydruk 4.8. Plik źródłowy przecia˛żanej metody create Dalej ustalamy konfiguracje˛ aby zmieniony kod wywoływał sie˛ dla naszej aplikacji. Na zakończenie sprawdzamy czy ogólne ustawienia systemu powoduja˛ wpisywanie zdarzeń do dziennika systemowego oraz czy nie jest właczona ˛ opcja złotego przebiegu, a naste˛ pnie transferujemy przygotowany plik z przecia˛żona˛ implementacja˛ oraz konfiguracje˛ na urzadzenie ˛ mobilne. Teraz możemy uruchomić analizowana˛ aplikacje˛ . Wyzwolenie opisywanego kodu spowoduje krytyczne zamkniecie ˛ aplikacji, co widać we fragmencie logu przedstawionego na wydruku 4.9. Dzie˛ ki systemowi AFIS udało sie˛ poprawnie wykryć prezentowana˛ sytuacje. ˛ Dzi˛eki informacjom z logu systemowego programista może jednoznacznie zidentyfikować źródło błe˛ du i zabezpieczyć aplikacje˛ na jego wystapienie. ˛ Bez wsparcia narz˛edzia AFIS użytkownik może doprowadzić do wymuszenia błedu ˛ przygotowujac ˛ specjalnie spreparowany, uszkodzony plik multimedialny, jednak zdaje sie˛ być to bardziej pracochłonne. 4.4. Przykłady użycia 1 5 10 35 [RUN] [ android . media . MediaPlayer . create ( android . content . Context , i n t ) ] [ 6 9 2 ] [ . . . ] [2013−04−10 23:15:41.370] ’Run’ function finished normally . D/AndroidRuntime ( 692): Shutting down VM W/dalvikvm ( 692): threadid =1: thread e x i t i n g with uncaught exception ( group=0x40a13300 ) E/AndroidRuntime ( 692): FATAL EXCEPTION: main E/AndroidRuntime ( 692): java . lang . NullPointerException E/AndroidRuntime ( 692): at pl . msulek . usagedemos . mediaplayercreatedemo . MediaPlayerCreateDemoActivity\$1 . onClick ( MediaPlayerCreateDemoActivity . java : 2 7 ) Wydruk 4.9. Wymuszenie zamkniecia ˛ badanej aplikacji - fragment dziennika systemowego 4.4.2. Bład ˛ wielowatkowości ˛ Tworzenie aplikacji wielowatkowych ˛ jest czesto ˛ dla programistów pewnym wyzwaniem. Powszechne zjawisko wyścigu i konieczność synchronizacji oraz komunikacji moga˛ powodować nieoczekiwane i niechciane efekty. Problem ten dotyka również programów tworzonych na platformy mobilne, szczególnie, że najnowsze modele tabletów czy telefonów maja˛ procesory wyposażone w 2, 4, a nawet 8 rdzeni. Wyobraźmy sobie sytuacje, ˛ w której mamy do odtworzenia zadana˛ przez użytkownika liste˛ plików multimedialnych z sieci społecznościowej. Dla każdego z nich musimy wykonać dodatkowa˛ prace˛ np.: pobrać napisy, zaktualizować komentarze użytkowników czy też pobrać inne treści. Naturalnym pomysłem bedzie ˛ wykonywanie jej w osobnym watku, ˛ tak aby treść była gotowa możliwe szybko po zakończeniu odtwarzania poprzednika. Schemat działania aplikacji MediaPlayerThreadsDemo jest naste˛ pujacy: ˛ — załadowanie pliku 1, — w pe˛ tli: — wywołanie watku, ˛ zlecenie przygotowania pliku, w nowym obiekcie MediaPlayer, — odtworzenie pliku, — zamiana obiektów MediaPlayer. Podczas użytkowania może zdarzyć sie, ˛ że jeden plik odtwarzany jest kilkukrotnie zanim zostanie załadowany nastepny. ˛ Wykorzystanie opcji złotego przebiegu oraz analiza komunikatów systemu AFIS (wydruk 4.10) pozwalaja˛ na identyfikacje˛ problemu. Okazuje sie˛ , że metoda start wywoływana jest 3-krotnie przed metoda˛ create, a wi˛ec w implementacji brakuje oczekiwania na zakończenie przygotowania - być może programista optymistycznie założył, że skończy sie˛ ono zawsze przed zakończeniem odtwarzania pliku. Aplikacja AFIS Desktop Analyzer umożliwia również wygenerowanie grafu wywołań wraz z kolejnościa˛ wykonywania metod, który ułatwia analize˛ logów - dla omawianej sytuacji jest to rysunek 4.14. Zawiera on funkcje wywołujace ˛ przecia˛żane metody (zaznaczone linia˛ przerywana), ˛ kolejność ich wywołania w ramach badania (sekcja order) oraz liczba wywołań w teście (sekcja 36 4.4. Przykłady użycia 1 5 10 D/AFIS ( 4105): [GRUN] [ android . media . MediaPlayer . create ( android . content . Context , i n t )}][4105][...][2013 −04 −11 15:18:47.355] Golden run f o r function . ( global option ) D/AFIS ( 4105): [GRUN] [ android . media . MediaPlayer . s t a r t ( ) } ] [ 4 1 0 5 ] [ ...][2013−04−11 15:18:47.666]Golden run f o r function . ( global option ) D/AFIS ( 4105): [GRUN] [ android . media . MediaPlayer . s t a r t ( ) } ] [ 4 1 0 5 ] [ ...][2013−04−11 15:18:51.426]Golden run f o r function . ( global option ) D/AFIS ( 4105): [GRUN] [ android . media . MediaPlayer . s t a r t ( ) } ] [ 4 1 0 5 ] [ ...)][2013 −04 −11 15:18:55.661]Golden run f o r function . ( global option ) D/AFIS ( 4105): [GRUN] [ android . media . MediaPlayer . create ( android . content . Context , i n t )}][4105][...][2013 −04 −11 15:18:58.934] Golden run f o r function . ( global option ) D/AFIS ( 4105): [GRUN] [ android . media . MediaPlayer . s t a r t ( ) } ] [ 4 1 0 5 ] [ ...][2013−04−11 15:18:59.931]Golden run f o r function . ( global option ) } Wydruk 4.10. Fragment logu z rozpoznania badanej aplikacji called) . Mimo iż zaprezentowany przykład jest dość trywialny, nie trudno wyobrazić sobie możliwości wykorzystania systemu AFIS w bardziej złożonych sytuacjach dotyczacych ˛ wielowatkowości. ˛ android.media.MediaPlayer.setDataSource [called 11 time(s)] [order: 2,5,11,15,19,22,27,31,35,39,42] android.media.MediaPlayer.create android.media.MediaPlayer.prepare [called 11 time(s)] [order: 3,6,12,16,20,23,28,32,36,40,43] android.media.MediaPlayer.start [called 10 time(s)] [order: 7,8,9,13,17,24,25,29,33,37] android.media.MediaPlayer.create [called 12 time(s)] [order: 1,4,10,14,18,21,26,30,34,38,41,44] pl.msulek.usagedemos.mediaplayerpreparethreaddemo. MediaPlayerPrepareThread.run pl.msulek.usagedemos.mediaplayerpreparethreaddemo. MediaPlayerPrepareThread$HelperThread.run Rysunek 4.14. Graf wywołań dla przykładowej aplikacji wielowatkowej ˛ wraz z liczba˛ oraz kolejnościa˛ wywołań metod 4.4.3. Zmiana argumentów wywołania metody System AFIS umożliwia użytkownikowi zmiane˛ parametrów wywoływanej przez analizowana˛ aplikacje˛ metody docelowej. Opcja ta może okazać sie˛ przydatna, jeśli programista chce ściśle kontrolować argumenty wywołania już na poziomie biblioteki i w razie pewnych problemów zmieniać je. Wyobraźmy sobie testowanie aplikacji dotyczacej ˛ usług opartych o lokalizacje. ˛ Członkowie zespołu programistycznego rozpoczynaja˛ niezależnie testy swoich modułów. Doskonale do tego zadania nadaje sie˛ możliwość tworzenia obiektów imitujacych ˛ dostarczycieli lokalizacji (z ang. mock location provider). Każdy z nich tworzy taki obiekt nadajac ˛ mu niesprecyzowana˛ nazwe. ˛ W momencie, w którym moduły zaczynaja˛ być dodawane do programu oraz rozpoczynane testy całościowe, pojawia sie˛ problem nazewnictwa. Wykorzystywany powinien być wyłacznie ˛ jeden z dostarczycieli lokalizacji wie˛ c konieczne sa˛ poprawki kodu. Innym podejściem może być przecia˛żenie metody odpowiedzialnej za rejestrowanie dostarczycieli lokalizacji w systemie, dzie˛ ki czemu be˛ dzie on w funkcjonował w aplikacji pod jedna˛ nazwa. ˛ 4.4. Przykłady użycia 37 Do realizacji tego zadania można wykorzystać system AFIS, przecia˛żajac ˛ funkcje˛ android.location.LocationManager.addTestProvider(java.lang.String, boolean,boolean,boolean,boolean,boolean,boolean,boolean,int,int). Jej przykładowa˛ modyfikacje˛ w systemie AFIS zaprezentowano na wydruku 4.11. Jak widać, podmieniany jest wyłacznie ˛ argument odpowiedzialny za ustawienie nazwy - jest on definiowany na stałe. 1 5 10 import android . a f i s c o r e . AFISFakeException ; public class OverrideClass { public void run ( java . lang . String arg0 , boolean arg1 , boolean arg2 , boolean arg3 , boolean arg4 , boolean arg5 , boolean arg6 , boolean arg7 , int arg8 , int arg9 ) throws AFISFakeException { Object [ ] newArgs = { " myprovider " , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 , arg9 } ; throw new AFISFakeException ( newArgs ) ; } } Wydruk 4.11. Zmiana argumentów wywołania metody addTestProvider Dzie˛ ki takiemu wykorzystaniu systemu, w całej aplikacji bedzie ˛ wykorzystywany ten sam dostarczyciel lokalizacji - niezależnie od kodu. AFIS zgłasza poprawna˛ zamiane˛ argumentów w logach systemowych (wydruk 4.12. 1 5 D/AFIS ( 933): [RUN] [ android . l o c a t i o n . LocationManager . addTestProvider ( java . lang . String , boolean , boolean , boolean , boolean , boolean , boolean , boolean , int , i n t ) ] [ 9 3 3 ] [ pl . msulek . usagedemos . testproviderdemo . TestProviderDemoActivity . onCreate ( TestProviderDemoActivity . java :21)][2013−08−31 14:20:25.304] ’Run’ function with changed parameters . Wydruk 4.12. Log systemowy informujacy ˛ o poprawnej zamianie argumentów wywołania dla badanej metody Warto również zaznaczyć, że wszelkie nieprawidłowości sa˛ sygnalizowane przez system AFIS. Załóżmy, że przygotowujac ˛ przecia˛żana˛ funkcje˛ programista zapomniał dostarczyć jeden z argumentów wywołania - zamiast 10, jest ich 9. Problem ten zostanie zidentyfikowany przez system AFIS, a użytkownik bedzie ˛ poinformowany o błe˛ dzie za pomoca˛ stosownego komunikatu, co prezentuje fragment logu (wydruk 4.13). 4.4.4. Podsumowanie W powyższych przykładach zaprezentowano niektóre z możliwych scenariuszy wykorzystania sytemu AFIS. Przechwycenie wywołań bibliotek szkieletowych pozwala na dynamiczne wstrzykniecie ˛ kodu testera, dajac ˛ mu możliwość manipulacji na oryginalnych danych przechwyconych metod, wykonanie własnych operacji lub wygenerowanie określonego błedu. ˛ Pozwala to na dużo szerszy zakres działań niż samo obserwowanie wywołań czy emulacja prostych zakłóceń. Możliwe 4.4. Przykłady użycia 1 5 38 D/AFIS ( 892): [CONFIG ] [ android . l o c a t i o n . LocationManager . addTestProvider ( java . lang . String , boolean , boolean , boolean , boolean , boolean , boolean , boolean , int , i n t ) ] [ 8 9 2 ] [ pl . msulek . usagedemos . testproviderdemo . TestProviderDemoActivity . onCreate ( TestProviderDemoActivity . java :21)][2013−08−31 14:18:53.909] Expecting 10 parameter ( s ) , but gave 9. Executing function normally . Wydruk 4.13. Log systemowy informujacy ˛ o niepoprawnym przecia˛żeniu badanej metody jest np. przeprowadzenie jednoczesnego zakłócania wielu aplikacji różnego rodzaju bł˛edami. Dzie˛ ki pozostawieniu definiowania samych zakłóceń w rekach ˛ eksperymentatora może on w dowolny sposób budować złożone scenariusze krytycznych sytuacji w pracy systemu. 5. Badania Rozważajac ˛ sposoby badania aplikacji na urzadzenia ˛ mobilne, należy zastanowić sie˛ nad metodologia, ˛ uwzgledniaj ˛ ac ˛ możliwości analizy tych danych oraz odpowiedniej ich korelacji. Jednym ze sposobów może być opracowanie globalnego dla danego programu scenariusza pracy z nia˛ i posługiwanie sie˛ nim niezależnie od testowanej funkcji. Takie podejście daje nam szanse˛ porównywania funkcji oraz ich zależności czasowych (błe˛ dy pojawiajace ˛ sie˛ w różnych iteracjach danej funkcji moga˛ mieć różny efekt dla użytkownika). Może okazać sie, ˛ że niektóre z wywołań, mimo iż wcześniej zostały obsłużone poprawnie, w pewnych konfiguracjach wywołań sprawiaja˛ problemy. Nie trudno wyobrazić sobie sytuacje, ˛ w której zmiana pewnych wartości za pomoca˛ zupełnie innych funkcji ma wpływ na wykonanie akurat testowanej. Niestety to rozwiazanie ˛ ma poważny mankament - scenariusz musi być niezwykle obszerny i w swoich krokach uwzgledniać ˛ pełna˛ funkcjonalność aplikacji (pokrycie testami powinno być możliwie jak najwyższe). Nie daje nam to jednak gwarancji pobudzenia funkcji z każdego miejsca jej wywołania w kodzie statycznym, a testowanie może sie˛ czasowo znaczaco ˛ wydłużyć. Innym podejściem jest opracowanie ukierunkowanych pod katem ˛ danej funkcji scenariuszy. Tu z kolei istnieje ryzyko pominiecia ˛ pewnych kombinacji wywołań. Problemem jest również odpowiedni dobór kroków scenariusza. Dobry rozwiaza˛ niem byłoby wie˛ c odnalezienie możliwie dużej ilości miejsc używania testowanej funkcji przez aplikacje˛ . Doskonale do tego nadaje sie˛ opcja złotego przebiegu (opisana w rozdziale 4). Dzie˛ ki niej jesteśmy w stanie obserwować, w których miejscach nast˛epuje wykorzystanie danej procedury dla określonego scenariusza i na tej podstawie możliwa jest jego optymalizacja. Tu nasuwa sie˛ z jeszcze jeden wniosek dotyczacy ˛ oprogramowania. Niezwykle pomocnym mogło by sie˛ okazać opracowanie metody inteligentnego wstrzykiwania kodu na podstawie dostarczonej listy miejsc, z których funkcja może być potencjalnie wywoływana. Pozwoliłoby to na 100% pokrycie testów pod warunkiem dobrze przeprowadzonego rozpoznania. Biorac ˛ pod uwage˛ doste˛ pne mechanizmy, badania w tej pracy zostana˛ przeprowadzone za pomoca˛ ukierunkowanych na dana˛ funkcje˛ scenariuszy, które maja˛ szanse˛ wyczerpać możliwości wystepowania ˛ błedów. ˛ Schemat postepowania ˛ był wi˛ec naste˛ pujacy: ˛ 1. rozpoznanie aplikacji, podczas którego za pomoca˛ opcji złotego przebiegu, badano funkcje (oraz miejsca ich użycia) wykorzystywane przez aplikacje, ˛ 2. badanie funkcji wywoływanych z jednego miejsca, przy prawdopodobieństwie zamiany kodu równym 1.0, 3. dla funkcji, które wywoływane były z wielu miejsc, opracowano scenariusze badań, a naste˛ pnie poddano testom z różnym prawdopodobieństwem wstrzyknie˛ cia kodu, 4. przedstawienie przebiegów wzorcowych, analiza wyników. 5.1. Connectbot 40 Generowane błe˛ dy obejmowały m.in. sytuacje wyjatkowe ˛ podczas: korzystania z plików multimedialnych, operacjach na bazie danych aplikacji, dostepu ˛ do karty pami˛eci oraz określania lokalizacji użytkownika. Każdy z testów został sklasyfikowany do jednej z kategorii określajacej ˛ jego istotność zaobserwowanych efektów zakłóceń (w tabelach z wynikami posługiwano sie˛ ich numerami): — 1 - wszystko przebiegło bez zauważalnego efektu, — 2 - wystapiły ˛ efekty uboczne, których skutek jest akceptowalny, — 3 - wystapiły ˛ efekty uboczne, jednak aplikacja to zasygnalizowała, — 4 - wystapiły ˛ efekty krytyczne i aplikacja o tym zasygnalizowała, — 5 - wystapiły ˛ efekty krytyczne, które nie zostały niesygnalizowane, — 6 - aplikacja sie˛ wyłaczyła, ˛ — 7 - nieprawidłowa operacja (niewymuszone przez symulator). W analizie badań, w zależności od rezultatów, zaprezentowano różne wykresy, tworzone w zależności od prezentowanych wniosków: — “Liczba testów w poszczególnych kategoriach efektu błedów ˛ w zależności od numeru iteracji zakłócanej metody X” - obrazuje liczbe˛ testów, które przydzielono do kategorii błe˛ du, w zależności od numeru iteracji metody badanej. Jako numer iteracji rozumie sie˛ tu numer kolejnego wywołania funkcji w danym badaniu, — “Liczba testów w poszczególnych kategoriach efektu błedów ˛ w zależności od miejsca wywołania zakłócanej metody X” - prezentuje liczbe˛ testów w danej kategorii błe˛ du w zależności od miejsca wywołania przecia˛żanej metody z kodu źródłowego badanej aplikacji, — “Kolejne iteracje wywołań zakłócanej metody X - zależność numeru wywołania od czasu” - ukazuje zależności czasowe miedzy ˛ kolejnymi numerami wywołań badanej metody, — “Liczba testów w poszczególnych kategoriach efektu błedów ˛ w zależności od prawdopodobieństwa wstrzykniecia ˛ błedu ˛ dla zakłócanej metody X” - prezentuje liczbe˛ testów z określona˛ kategoria˛ błedu ˛ w zależności od wartości prawdopodobieństwa z jaka˛ wstrzykiwano błedny ˛ kod, — “Średnia liczba wstrzyknietych ˛ błedów ˛ w zależności od wartości prawdopodobieństwa dla zakłócanej metody X” - obrazuje średnia˛ liczbe˛ wstrzyknieć ˛ błedu, ˛ które były niezbe˛ dne do otrzymania błedu ˛ danej kategorii. Wykres adekwatny do sytuacji, w której na jeden test przypadało zdecydowanie wiecej ˛ wywołań zmodyfikowanego kodu niż jedno, co uniemożliwiało wskazanie konkretnego miejsca powodujacego ˛ nieprawidłowości. Szczegółowe wyniki badań zostały zamieszczone w postaci raportu w dodatkowym pliku w formacie pdf na dołaczonej ˛ z praca˛ płycie CD. 5.1. Connectbot Connectbot to jedna z bardziej popularnych aplikacji dla systemu Android, tworzona na zasadach Otwartego Oprogramowania. Służy ona do łaczenia ˛ sie˛ ze zdalnymi serwerami za pomoca˛ protokołu ssh albo telnet, a z dodatkowych funkcjonalności, umożliwia przekierowywanie portów. Badaniu poddano aplikacje˛ 5.1. Connectbot 41 w wersji 1.7.1. 5.1.1. Rozpoznanie Graf wywołań dla aplikacji zaprezentowano na rysunku 5.1. W ramach rozpoznania stwierdzono, że aplikacja wykorzystuje nastepuj ˛ ace ˛ metody (podano ich pełne nazwy wraz z miejscami wywoływania): — android.media.MediaPlayer.setDataSource(java.io.FileDescriptor,long,long): — org.connectbot.service.TerminalManager .enableMediaPlayer(TerminalManager.java:556), — android.media.MediaPlayer.prepare(): — org.connectbot.service.TerminalManager .enableMediaPlayer(TerminalManager.java:560), — android.os.Environment.getExternalStorageState(): — org.connectbot.PubkeyListActivity .pickFileSimple(PubkeyListActivity.java:568), — android.database.sqlite.SQLiteOpenHelper.getReadableDatabase() (klasy pochodza˛ z paczki org.connectbot.util - chyba, że zaznaczono inaczej): — HostDatabase.getDefaultColorsForScheme(HostDatabase.java:718), — HostDatabase.findHostById(HostDatabase.java:485), — HostDatabase.getHosts(HostDatabase.java:343), — PubkeyDatabase.allValues(PubkeyDatabase.java:220), — HostDatabase.getPortForwardsForHost(HostDatabase.java:593), — HostDatabase.getKnownHosts(HostDatabase.java:527), — PubkeyDatabase.getPubkeys(PubkeyDatabase.java:131), — HostDatabase.findHost(HostDatabase.java:464), — HostDatabase.getColorsForScheme(HostDatabase.java:661), — org.connectbot.HostEditorActivity$CursorPreferenceHack .cacheValues(HostEditorActivity.java:71), — HostDatabase.saveKnownHost(HostDatabase.java:510), — android.database.sqlite.SQLiteOpenHelper.getWritableDatabase() (metody pochodza˛ z klasy org.connectbot.util.HostDatabase): — touchHost(HostDatabase.java:276), — <init>(HostDatabase.java:145), — updateFontSize(HostDatabase.java:311), — savePortForward(HostDatabase.java:628), — setColorForScheme(HostDatabase.java:686), — saveHost(HostDatabase.java:289), — android.net.LocalSocket.close(): — com.android.internal.os.ZygoteConnection .closeSocket(ZygoteConnection.java:271). — android.net.LocalServerSocket.close(): — com.android.internal.os.ZygoteInit.closeServerSocket(ZygoteInit.java:196), — android.os.PowerManager.isScreenOn(): — android.view.ViewRootImpl.<init>(ViewRootImpl.java:403), Badaniom nie zostana˛ poddane wszystkie metody, gdyż niektóre z nich maja˛ marginalne znaczenie. Metoda close() z klasy LocalSocket oraz LocalServerSocket jest wywoływana przy zamykaniu aplikacji i nie ma już org.connectbot.util. HostDatabase.findHostById org.connectbot.util. HostDatabase.getHosts org.connectbot.util. HostDatabase.saveKnownHost org.connectbot.HostEditorActivity$ CursorPreferenceHack.cacheValues org.connectbot.util. HostDatabase.getColorsForScheme org.connectbot.util. HostDatabase.findHost org.connectbot.util. PubkeyDatabase.getPubkeys org.connectbot.util. HostDatabase.getKnownHosts org.connectbot.util. HostDatabase.getDefaultColorsForScheme org.connectbot.util. HostDatabase.getPortForwardsForHost org.connectbot.util. PubkeyDatabase.allValues android.media.MediaPlayer. setDataSource android.os.Environment. getExternalStorageState org.connectbot.util. HostDatabase.setColorForScheme org.connectbot.util. HostDatabase.saveHost org.connectbot.util. HostDatabase.touchHost org.connectbot.util. HostDatabase.<init> org.connectbot.util. HostDatabase.updateFontSize org.connectbot.util. HostDatabase.savePortForward org.connectbot.service. TerminalManager.enableMediaPlayer android.media. MediaPlayer.prepare org.connectbot.PubkeyListActivity.pickFileSimple android.database.sqlite. SQLiteOpenHelper.getWritableDatabase android.database.sqlite. SQLiteOpenHelper.getReadableDatabase 5.1. Connectbot 42 Rysunek 5.1. Graf wywołań metod podczas rozpoznania dla aplikacji Connectbot 5.1. Connectbot 43 wpływu na jej działanie. Najważniejsze jednak, że sa˛ one wywoływane przez metody systemowe, co powoduje, że za ich obsługe˛ nie jest odpowiedzialny programista. Metoda isScreenOn() zwraca jedynie informacje˛ o stanie właczenia ˛ ekranu i jest ona wykorzystywana przez klase˛ widoku implementowana˛ w ramach systemu. 5.1.2. Badania metod wywoływanych z jednego miejsca android.media.MediaPlayer.setDataSource(FileDescriptor, long, long) Metoda ta jest wykonywana podczas próby ustawiania dźwieku ˛ powiadomień terminala. W ramach przecia˛żenia wymuszono aby metoda rzucała wyjatek ˛ IOException. Podczas wykonania zaobserwowano, że aplikacja loguje niemożliwość ustawienia dźwi˛eku, jednak nie informuje o tym fakcie użytkownika. Jest to jednak bład ˛ niekrytyczny o stosunkowo małym znaczeniu dla użytkownika - kategoria 2. Kolejnemu sprawdzeniu podlegała obsługa wyjatku ˛ IllegalArgumentException, który wywoływany jest gdy któryś z argumentów jest niepoprawny. Wyjatek ˛ ten nie jest obsługiwany i powoduje niewłaczenie ˛ sie˛ aplikacji. Jest to bład ˛ krytyczny - kategoria 6. android.media.MediaPlayer.prepare() Podobnie jak metoda setDataSource jest ona wywoływana w momencie ustawiania dźwie˛ ku powiadomień terminala. Zgodnie z dokumentacja˛ metoda może rzucać wyjatek ˛ IOException albo IllegalStateException. Pierwszy z nich jest błednie ˛ obsługiwany - dźwiek ˛ nie został ustawiony i nie poinformowano o tym fakcie użytkownika - kategoria 2. Natomiast drugi z wyjatków ˛ wymaga spreparowania testu, który spowoduje faktycznie bł˛edny stan obiektu MediaPlayer. Dlatego przygotowano badanie, w którym metoda setDataSource wprowadza obiekt MediaPlayer w stan nieustawiony (rzucajac ˛ wyjatek ˛ IOException), a nastepnie ˛ metoda prepare kończy sie˛ wyjatkiem ˛ IllegalStateException. Podczas testu okazuje sie, ˛ że po obsłudze wyjatku ˛ rzucanego przez metode˛ ustawiajac ˛ a˛ źródło dźwieku, ˛ nie jest już wywoływana metoda przygotowujaca, ˛ dlatego nie da sie˛ faktycznie sprawdzić reakcji na wyjatek ˛ błednego ˛ stanu obiektu. android.os.Environment.getExternalStorageState() Wywołanie tej metody nastepuje ˛ podczas próby importowania klucza publicznego z karty pamie˛ ci. System skonfigurowano tak aby metoda zawsze zwracała stan karty jako niezamontowany. Podczas próby wyświetlenia katalogów z karty pamieci, ˛ aplikacja informuje, że karta jest niedostepna. ˛ Jej zachowanie jest wiec ˛ poprawne. 44 5.1. Connectbot 5.1.3. Badania metoda wywoływanych z wielu miejsc android.database.sqlite.SQLiteOpenHelper.getReadableDatabase() W ramach badań wymuszano na testowanej metody rzucenie wyjatku ˛ android.database.sqlite.SQLiteException. Scenariusz Przygotowanie testu — Zainstalowano aplikacje˛ Connectbot, — system posiada aktywne połaczenie ˛ sieciowe, — w aplikacji Connectbot skonfigurowano jedno połaczenie ˛ lokalne. Numer Krok kroku Oczekiwany rezultat 1 Uruchomienie aplikacji Uruchomiona aplikacja z jednym skonfigurowanym połaczeniem ˛ 2 Dodanie połaczenia ˛ zdalnego SSH Połaczenie ˛ zostało dodane do listy skonfigurowanych połacze ˛ ń, nastapiła ˛ próba połaczenia ˛ 3 Zaakceptowanie klucza komputera Komputer zdalny został dodany do zdalnego listy znanych kluczy, wyświetlono zapytanie o hasło 4 Wprowadzenie poprawnego hasła 5 Wyświetlenie opcji przekierowania Lista przekierowań portów (może portów być pusta) 6 Dodanie portu 7 Usunie˛ cie konfiguracji portu Port został usuniety ˛ z listy 8 Rozłaczenie ˛ połaczenia ˛ Wyświetlony został ekran główny aplikacji z dodanym wcześniej połaczeniem ˛ 9 Wyświetlenie parametrów połacze˛ Wyświetlone zostały opcje połacze˛ nia nia 10 Edycja dowolnego parametru (np. Parametr został zmieniony (w przyzmiana koloru połaczenia) ˛ padku wybrania innego koloru, zmiana jest widoczna w liście skonfigurowanych połacze ˛ ń) 11 Usunie˛ cie połaczenia ˛ dowolnej Nastapiło ˛ połaczenie ˛ z komputerem zdalnym konfiguracji Port został dodany do listy Połaczenie ˛ zostało usuniete ˛ z listy 45 5.1. Connectbot 12 Wyświetlenie bazy kluczy publicz- Wyświetlona została lista kluczy nych publicznych (może być pusta) 13 Wygenerowanie nowego klucza Klucz wyświetla sie˛ na liście 14 Usunie˛ cie dodanego klucza Klucz został usuniety ˛ z listy 15 Powrót do okna głównego aplikacji Lista skonfigurowanych połacze ˛ ń - wyłacznie ˛ skonfigurowane poła˛ czenie lokalne Tablica 5.1: Scenariusz badań dla metody SQLiteOpenHelper.getReadableDatabase() Analiza wyników Dla analizowanej metody przeprowadzono 30 testów z różnymi wartościami prawdopodobieństwa błe˛ du (0,1; 0,25 oraz 0,5) co daje łacznie ˛ 90 testów. Tabela 5.1.3 prezentuje wzorcowy przebieg testowania metody dla opracowanego scenariusza. Zależności czasowe pomiedzy ˛ poszczególnymi wywołaniami zostały zaprezentowane na wykresie 5.2. Numer Czas[s] wywołania Miejsca wołania metody Wszystkie metody, klasy oraz pakiety pochodza˛ z paczki org.connectbot 1 0,0 util.PubkeyDatabase.getPubkeys(PubkeyDatabase.java:131) 2 0,39 util.HostDatabase.getHosts(HostDatabase.java:343) 3 5,421 util.HostDatabase.findHost(HostDatabase.java:464) 4 6,003 util.HostDatabase.findHost(HostDatabase.java:464) 5 6,123 util.HostDatabase .getDefaultColorsForScheme(HostDatabase.java:718) 6 6,172 util.HostDatabase .getColorsForScheme(HostDatabase.java:661) 7 6,185 util.HostDatabase .getPortForwardsForHost(HostDatabase.java:593) 8 6,734 util.HostDatabase.getKnownHosts(HostDatabase.java:527) 9 10,425 util.HostDatabase.saveKnownHost(HostDatabase.java:510) 46 5.1. Connectbot 10 16,381 util.HostDatabase .getDefaultColorsForScheme(HostDatabase.java:718) 11 16,473 util.HostDatabase .getColorsForScheme(HostDatabase.java:661) 12 22,588 13 22,622 util.HostDatabase.findHostById(HostDatabase.java:485) util.HostDatabase .getPortForwardsForHost(HostDatabase.java:593) 14 57,145 util.HostDatabase.getHosts(HostDatabase.java:343) 15 60,736 util.HostDatabase.findHostById(HostDatabase.java:485) 16 60,806 HostEditorActivity$CursorPreferenceHack .cacheValues(HostEditorActivity.java:71) 17 60,902 util.PubkeyDatabase.allValues(PubkeyDatabase.java:220) 18 60,961 util.PubkeyDatabase.allValues(PubkeyDatabase.java:220) 19 63,879 HostEditorActivity$CursorPreferenceHack .cacheValues(HostEditorActivity.java:71) 20 74,684 util.HostDatabase.getHosts(HostDatabase.java:343) 21 74,788 util.HostDatabase.getHosts(HostDatabase.java:343) 22 81,634 util.HostDatabase.getHosts(HostDatabase.java:343) 23 85,837 util.PubkeyDatabase.getPubkeys(PubkeyDatabase.java:131) 24 85,884 util.PubkeyDatabase.getPubkeys(PubkeyDatabase.java:131) 25 105,295 util.PubkeyDatabase.getPubkeys(PubkeyDatabase.java:131) 26 105,573 util.PubkeyDatabase.getPubkeys(PubkeyDatabase.java:131) 27 112,608 util.PubkeyDatabase.getPubkeys(PubkeyDatabase.java:131) 28 114,076 util.HostDatabase.getHosts(HostDatabase.java:343) Tablica 5.2: Zależności czasowe oraz miejsca wywołań testowanej metody SQLiteOpenHelper.getReadableDatabase() dla wykonania wzorcowego 5.1. Connectbot 47 Rysunek 5.2. Zależności czasowe poszczególnych wywołań metody SQLiteOpenHelper.getReadableDatabase() w wykonaniu wzorcowym Z wykonania wzorcowego wynika, że scenariusz pokrył wszystkie miejsca wywołań odnalezione podczas rozpoznania. Maksymalny numer iteracji wyznaczony z wykonania wzorcowego to 28. Łacznie, ˛ we wszystkich testach, metoda getReadableDatabase() została wywołana 460, z czego błe˛ dny kod wstrzyknieto ˛ 97 razy. Wszystkie wstrzykniecia ˛ zakończyły sie˛ błe˛ dem krytycznym. Zaobserwowano jednak, że w kilku przypadkach metoda musiała być przecia˛żona wielu miejscach - pierwsze nie powodowało krytycznego zachowania. Na wykresie z rys. 5.3 zaprezentowano liczbe˛ wywołań oraz ich wpływ na aplikacje˛ w zależności od numeru wywołania. Z analizy wywołań wynika, że wszystkie miejsca, z których wykonywana jest badana metoda znalazły pokrycie w testach. W znakomitej wiekszości ˛ przypadków, wstrzykniety ˛ bład ˛ powoduje wyłaczenie ˛ sie˛ aplikacji, w szczególności jeśli wystapił ˛ on w fazie uruchamiania aplikacji. Należy również zwrócić uwage, ˛ że metoda ta jest używana niezwykle cze˛ sto. Zgodnie z zaleceniami z dokumentacji powinna być uruchamiana w osobnym watku ˛ co z pewnościa˛ jest kosztowne czasowo 1 . Analizujac ˛ liczb˛e wywołań metody z konkretnych miejsc (wykres na rys. 5.4) można, we wskazanych miejscach, próbować optymalizować kod. Wykres z rys. 5.5 pokazuje, że wraz ze wzrostem prawdopodobieństwa wstrzykniecia ˛ błedu, ˛ rośnie liczbe˛ błedów ˛ kończa˛ cych sie˛ wyłaczeniem ˛ aplikacji. 1 Za strona˛ android.developers.com: “Like getWritableDatabase(), this method may take a long time to return, so you should not call it from the application main thread, including from ContentProvider.onCreate().” 5.1. Connectbot 48 Rysunek 5.3. Liczba testów w poszczególnych kategoriach w zależności od numeru iteracji zakłócanej metody SQLiteOpenHelper.getReadableDatabase() Rysunek 5.4. Liczba testów w poszczególnych kategoriach w zależności od miejsca wywołania zakłócanej metody SQLiteOpenHelper.getReadableDatabase() 49 5.1. Connectbot Rysunek leżności 5.5. Liczba testów w poszczególnych kategoriach od wartości prawdopodobieństwa dla zakłócanej SQLiteOpenHelper.getReadableDatabase() w zametody android.database.sqlite.SQLiteOpenHelper.getWritableDatabase() Przecia˛żony kod został tak przygotowany aby metoda rzucała wyjatek ˛ android.database.sqlite.SQLiteException. Scenariusz Numer Krok kroku Oczekiwany rezultat Przygotowania testu oraz kroki od 1-15 ze scenariusza dla metody android.database.sqlite.SQLiteOpenHelper.getReadableDatabase() 16 Wyświetlenie konfiguracji kolorów Wyświetlone zostały możliwe do konfiguracji kolory terminala 17 Zmiana koloru ’FG’ Kolor został ustawiony 18 Zresetowanie kolorów Kolory zostały przywrócone do domyślnych Tablica 5.3: Scenariusz badań dla metody SQLiteOpenHelper.getWritableDatabase() Analiza wyników 50 5.1. Connectbot Dla zakłócanej metody przeprowadzono 30 testów z różnymi wartościami prawdopodobieństwa błe˛ du (0,1; 0,25 oraz 0,5) co daje łacznie ˛ 90 testów. Tabela 5.4 oraz wykres 5.6 prezentuja˛ zależności czasowe pomiedzy ˛ poszczególnymi wywołaniami dla wykonania wzorcowego (bezbłednego). ˛ Numer Czas[s] wywołania Miejsca wołania metody Wszystkie metody oraz pakiety pochodza˛ z paczki org.connectbot 1 0,0 util.HostDatabase.<init>(HostDatabase.java:145) 2 0,083 util.HostDatabase.<init>(HostDatabase.java:145) 3 4,696 util.HostDatabase.saveHost(HostDatabase.java:289) 4 5,541 util.HostDatabase.updateFontSize(HostDatabase.java:311) 5 5,632 util.HostDatabase.touchHost(HostDatabase.java:276) 6 15,917 util.HostDatabase.updateFontSize(HostDatabase.java:311) 7 27,667 util.HostDatabase.<init>(HostDatabase.java:145) 8 42,426 util.HostDatabase.savePortForward(HostDatabase.java:628) 9 46,6 util.HostDatabase.deletePortForward(HostDatabase.java:652) 10 50,116 util.HostDatabase.<init>(HostDatabase.java:145) 11 53,636 util.HostDatabase.<init>(HostDatabase.java:145) 12 56,096 HostEditorActivity$CursorPreferenceHack$Editor .commit(HostEditorActivity.java:119) 13 57,206 util.HostDatabase.<init>(HostDatabase.java:145) 14 60,939 util.HostDatabase.deleteHost(HostDatabase.java:329) 15 82,467 util.PubkeyDatabase.savePubkey(PubkeyDatabase.java:309) 16 82,639 util.HostDatabase.<init>(HostDatabase.java:145) 17 87,086 util.HostDatabase.<init>(HostDatabase.java:145) 18 87,167 util.HostDatabase.stopUsingPubkey(HostDatabase.java:572) 19 87,216 util.PubkeyDatabase.deletePubkey(PubkeyDatabase.java:105) 20 88,695 util.HostDatabase.<init>(HostDatabase.java:145) 21 91,422 util.HostDatabase.<init>(HostDatabase.java:145) 51 5.1. Connectbot 22 93,639 util.HostDatabase .setDefaultColorsForScheme(HostDatabase.java:755) 23 95,682 util.HostDatabase .setDefaultColorsForScheme(HostDatabase.java:755) 24 95,844 util.HostDatabase .setDefaultColorsForScheme(HostDatabase.java:755) 25 97,09 util.HostDatabase.<init>(HostDatabase.java:145) 26 97,167 util.HostDatabase.<init>(HostDatabase.java:145) Tablica 5.4: Zależności czasowe oraz miejsca wywołań testowanej metody SQLiteOpenHelper.getWritableDatabase() dla wykonania wzorcowego Rysunek 5.6. Zależności czasowe poszczególnych wywołań metody SQLiteOpenHelper.getWritableDatabase() w wykonaniu wzorcowym Badania pokryły wszystkie miejsca wywołań odnalezione podczas rozpoznania. Zaobserwowano, że metoda wywoływana jest maksymalnie 26 razy w trakcie pojedynczego testu. Metoda getWritableDatabase() została, w ramach testów, wywołana 578 razy. W ramach wszystkich wywołań, sytuacje˛ błedn ˛ a˛ wymuszono 101 razy, a aplikacja została wyłaczona ˛ 76 razy. Podobnie jak w badaniach poprzedniej metody, niektóre przebiegi wymagały wielokrotnego jej przecia˛żenia. Na wykresie z rys. 5.7 5.1. Connectbot 52 zaprezentowano liczbe˛ wywołań oraz ich wpływ na aplikacje˛ w zależności od numeru wywołania. Z analizy szczegółowych badań wynika, że testowana metoda nie została wywołana ani razu przez metode˛ org.connectbot.util.HostDatabase .setColorForScheme(HostDatabase.java:686), wiec ˛ osiagni ˛ eto ˛ pokrycie testami na poziomie 84%. Podobnie jak w przypadku poprzedniej metody, wiekszość ˛ sytuacji błe˛ dnych kończy sie˛ wyłaczeniem ˛ aplikacji. Zalecenia skierowane w dokumentacji do programisty sa˛ zbliżone do poprzednich2 , dlatego warto w oparciu o wykres z rys. 5.8 dokonać próby optymalizacji i zminimalizować liczbe˛ jej wywołań w kodzie. Na wykresie widocznym na rys. 5.9 możemy zaobserwować, że wraz ze wzrostem prawdopodobieństwa rośnie liczba błedów ˛ powodujacych ˛ wyłaczenie ˛ aplikacji. Rysunek 5.7. Liczba testów w poszczególnych kategoriach w zależności od numeru iteracji zakłócanej metody SQLiteOpenHelper.getWritableDatabase() 2 Za developers.android.com: “Database upgrade may take a long time, you should not call this method from the application main thread, including from ContentProvider.onCreate().” 5.2. Endomondo 53 Rysunek 5.8. Liczba testów w poszczególnych kategoriach w zależności od miejsca wywołania zakłócanej metody SQLiteOpenHelper.getWritableDatabase() Rysunek 5.9. Liczba testów w poszczególnych kategoriach w zależności od prawdopodobieństwa dla zakłócanej metody SQLiteOpenHelper.getWritableDatabase() 5.2. Endomondo Endomondo to popularna aplikacja wspomagajaca ˛ różnego rodzaju treningi sportowe. Oprócz zwykłego zarzadzania ˛ treningami, umożliwia ona np.: rejestrowanie tras, głosowe informowanie użytkownika o przebiegu trasy, dzielenie sie˛ 5.2. Endomondo 54 wynikami ze znajomymi za pomoca˛ sieci społecznościowych. Badaniom poddano aplikacje˛ w wersji 8.8.1. 5.2.1. Rozpoznanie Wywoływane przez aplikacje˛ metody systemowe zaprezentowano na grafie z rys. 5.10 Analizujac ˛ rozpoznanie wybrano nastepuj ˛ ace ˛ metody bibliotek systemu (podano wraz z miejscami wywołań) do badań: — android.location.Geocoder.Geocoder(android.content.Context,java.util.Locale): — android.location.Geocoder.<init>(Geocoder.java:135), — android.location.Geocoder.getFromLocation(double,double,int): — com.endomondo.android.common.AdConfManager$CheckForNewCountry .doInBackground(AdConfManager.java:204), — android.location.LocationManager.getProvider(java.lang.String) (klasy pochodza˛ z paczki com.endomondo.android.common): — TrackManager$TrackListLoader.fetchLocation(TrackManager.java:582), — TrackManager$TrackListLoader.fetchLocation(TrackManager.java:577), — AdConfManager.fetchLastLocation(AdConfManager.java:239), — GPSInterface.requestLocUpdates(GPSInterface.java:95), — android.location.LocationManager.isProviderEnabled(java.lang.String): — com.endomondo.android.common.GPSInterface .requestLocUpdates(GPSInterface.java:103), — android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(): — com.endomondo.android.common.EndomondoDatabase .updateAndCleanUpChallenges(EndomondoDatabase.java:4128), — com.endomondo.android.common.EndomondoDatabase .execSingleSqlStatement(EndomondoDatabase.java:651), — com.endomondo.android.common.EndomondoDatabase .replaceNotifications(EndomondoDatabase.java:4965), — com.endomondo.android.common.purchase .PurchaseDatabase.<init>(PurchaseDatabase.java:76), — com.google.android.apps.analytics.PersistentHitStore .putEvent(Unknown Source), — com.google.android.apps.analytics.PersistentHitStore .deleteHit(Unknown Source), — com.google.android.apps.analytics.PersistentHitStore .loadExistingSession(Unknown Source), — com.google.android.apps.analytics.PersistentHitStore .storeUpdatedSession(Unknown Source), — android.location.LocationManager.requestLocationUpdates( java.lang.String,long,float,android.location.LocationListener): — com.endomondo.android.common.GPSInterface .requestLocUpdates(GPSInterface.java:117), — android.database.sqlite.SQLiteOpenHelper.getReadableDatabase() (metody pochodza˛ z klasy com.endomondo.android.common.EndomondoDatabase chyba, że zaznaczono inaczej): — getChallenges(java:4340), com.endomondo.android.common. EndomondoDatabase.getPremiumDataCursor com.endomondo.android.common. EndomondoDatabase.getWorkoutCursor com.endomondo.android.common. EndomondoDatabase.getAllNotifications com.endomondo.android.common. EndomondoDatabase.getTrackPointCursor com.endomondo.android.common. EndomondoDatabase.getChallenges com.endomondo.android.common. EndomondoDatabase.<init> com.endomondo.android.common. EndomondoDatabase.getMostUsedSportsCursor com.google.android.apps.analytics. PersistentHitStore.peekHits com.endomondo.android.common. EndomondoDatabase.getAdConfCursor com.endomondo.android.common. EndomondoDatabase.getWorkoutExtras com.endomondo.android.common. EndomondoDatabase.getZonesCursor com.google.android.apps.analytics. PersistentHitStore.getVisitorVarBuffer com.endomondo.android.common.dao. WorkoutDao.getWorkoutIdsWithPendingExtras com.endomondo.android.common. EndomondoDatabase.getIntervalProgramCursor com.endomondo.android.common. EndomondoDatabase.getMusicCursor com.google.android.apps.analytics. PersistentHitStore.getNumStoredHitsFromDb com.endomondo.android.common. EndomondoDatabase.execSingleSqlStatement android.location.LocationManager. isProviderEnabled android.location.LocationManager. requestLocationUpdates com.endomondo.android.common. GPSInterface.requestLocUpdates android.location. LocationManager.getProvider com.endomondo.android.common. TrackManager$TrackListLoader.fetchLocation android.location.LocationManager. getLastKnownLocation com.endomondo.android.common. AdConfManager.fetchLastLocation android.location.Geocoder. getFromLocation com.google.android.apps.analytics. PersistentHitStore.loadExistingSession com.endomondo.android.common. EndomondoDatabase.updateAndCleanUpChallenges com.endomondo.android.common. EndomondoDatabase.replaceNotifications com.google.android.apps.analytics. PersistentHitStore.deleteHit com.endomondo.android.common. purchase.PurchaseDatabase.<init> com.google.android.apps. analytics.PersistentHitStore.putEvent com.google.android.apps.analytics. PersistentHitStore.storeUpdatedSession android.location.LocationManager. addGpsStatusListener android.database.sqlite. SQLiteOpenHelper.getWritableDatabase com.endomondo.android.common. AdConfManager$CheckForNewCountry.doInBackground android.database.sqlite. SQLiteOpenHelper.getReadableDatabase 5.2. Endomondo 55 Rysunek 5.10. Graf wywołań metod podczas rozpoznania dla aplikacji Endomondo 5.2. Endomondo 56 — — — — — — — — — — — — — <init>(java:141), getAdConfCursor(java:3546), getMostUsedSportsCursor(java:1434), getWorkoutCursor(java:995), getMusicCursor(java:1801), getIntervalProgramCursor(java:2271), dao.WorkoutDao.getWorkoutIdsWithPendingExtras(WorkoutDao.java:107), getZonesCursor(java:3860), getPremiumDataCursor(java:4741), getWorkoutExtras(java:4786), getAllNotifications(java:5008), getTrackPointCursor(java:1600), com.google.android.apps.analytics.PersistentHitStore .getNumStoredHitsFromDb(Unknown Source), — com.google.android.apps.analytics.PersistentHitStore .getVisitorVarBuffer(Unknown Source), — com.google.android.apps.analytics.PersistentHitStore .peekHits(Unknown Source), — android.os.PowerManager.newWakeLock(int,java.lang.String): — com.endomondo.android.common.WorkoutService .acquireWakeLock(WorkoutService.java:2568), — android.location.LocationManager.addGpsStatusListener( android.location.GpsStatus.Listener): — com.endomondo.android.common.GPSInterface .requestLocUpdates(GPSInterface.java:119), — android.location.LocationManager.getLastKnownLocation(java.lang.String): — com.endomondo.android.common.TrackManager$TrackListLoader .fetchLocation(TrackManager.java:578), — com.endomondo.android.common.AdConfManager .fetchLastLocation(AdConfManager.java:241), — android.net.LocalServerSocket.close(): — com.android.internal.os.ZygoteInit.closeServerSocket(ZygoteInit.java:196), — android.os.PowerManager.isScreenOn(): — android.view.ViewRootImpl.<init>(ViewRootImpl.java:403), — android.net.LocalSocket.close(): — com.android.internal.os.ZygoteConnection .closeSocket(ZygoteConnection.java:271), Analizujac ˛ używane metody należy stwierdzić, że badaniu podlegać bed ˛ a˛ wszystkie z nich, za wyjatkiem ˛ ostatnich trzech - o braku zasadności ich testowania wspomniano przy omawianiu aplikacji Connectbot. 5.2.2. Badania metod wywoływanych z jednego miejsca android.location.Geocoder.getFromLocation(double,double,int) Metoda wywoływana podczas próby uzyskania adresów miejsc znajdujacych ˛ si˛e w pobliżu zadanej pozycji. Z jej rezultatu korzysta moduł odpowiedzialny za wyświetlanie reklam. 5.2. Endomondo 57 W ramach pierwszego i drugiego testu przecia˛żono kod metody aby wywołanie kończyło sie˛ wyjatkiem ˛ java.io.IOException oraz wymuszono zwracanie pustej listy adresów. Każdy z przypadków nie jest obsługiwany - aplikacja nie informuje użytkownika o błe˛ dzie, jednak jej działanie nie jest zburzone. Bład ˛ kategorii 1. Trzeci test wymuszał rzucenie wyjatku ˛ java.lang.IllegalArgumentException, którego brak obsługi kończył niewłaczeniem ˛ sie˛ aplikacji, a wiec ˛ jest to bład ˛ kategorii 6. android.location.LocationManager.requestLocationUpdates( java.lang.String,long,float,android.location.LocationListener) Metoda wywoływana podczas próby konfiguracji modułu GPS przez aplikacje. ˛ W ramach kolejnych testów, konfigurowano system aby wykonanie meotyd kończyło sie˛ wyjatkiem: ˛ java.lang.IllegalArgumentException, java.lang.RuntimeException oraz java.lang.SecurityException. W każdym przypadku aplikacja nie obsługuje błedu ˛ oraz nie informuje użytkownika o tym zdarzeniu. Cały czas wyświetlana jest informacja o próbie uzyskania lokalizacji, jednak nigdy to nie nastapi. ˛ Jest to bład ˛ z kategorii 5. android.location.LocationManager.isProviderEnabled(java.lang.String) Metoda wywoływana podczas próby konfiguracji modułu GPS przez aplikacje. ˛ Wykonano dwa badania, w których wymuszono aby wykonanie metody kończyło sie˛ wyjatkami. ˛ W pierwszym z nich rzucano wyjatek ˛ java.lang.SecurityException, co kończyło sie˛ niewłaczeniem ˛ aplikacji - kategoria 6. Natomiast w drugim, metoda zwracała wyjatek ˛ java.lang.IllegalArgumentException, który spowodował, że program nie potrafił uzyskać lokalizacji, nie informujac ˛ o tym użytkownika. Jest to bład ˛ kategorii 5. android.location.LocationManager .addGpsStatusListener(android.location.GpsStatus.Listener) Metoda wykonywana podczas próby pobrania pozycji za pomoca˛ modułu GPS. W ramach pierwszego badania system został skonfigurowany tak aby zwracać wartość False. W kolejnym podejściu, ustawiono symulator aby metoda rzucała wyjatek ˛ java.lang.SecurityException. W każdym przypadku aplikacja nie informuje użytkownika o problemie. Błedy ˛ te powoduja, ˛ że program nie może uzyskać lokalizacji, wyświetlajac ˛ jednocześnie informacje, że próbuje on pozycje˛ uzyskać, a to nie jest możliwe. Kategoria błedu ˛ 5. android.os.PowerManager.newWakeLock(int,java.lang.String) Zgodnie z dokumentacja, ˛ metoda ta nie może zakończyć sie˛ wyjatkiem, ˛ jednak z analizy kodu wynika iż sa˛ sytuacje, w których zwracany jest NullPointerException. Ze wzgledu ˛ na to, że system zabezpiecza sie, ˛ aby przecia˛żany kod zwracał wyłaczenie ˛ wyjatki ˛ zgodne z dokumentacja, ˛ nie ma możliwości sprawdzenia takiego scenariusza. Test ten byłby niezasadny, gdyż programista nie może przygotować obsługi wyjatku, ˛ który teoretycznie nie może wystepować. ˛ W kolejnych badaniach metoda ta bedzie ˛ pomijana. 58 5.2. Endomondo 5.2.3. Badania metod wywoływanych z wielu miejsc android.location.LocationManager.getLastKnownLocation(java.lang.String) Zgodnie z dokumentacja˛ metoda ta może kończyć sie˛ jednym z dwóch wyjat˛ ków: java.lang.SecurityException, java.lang.IllegalArgumentException albo zwrócić pusty obiekt null. Pierwszy z nich może wystepować ˛ jeśli aplikacja nie ma uprawnień do używania modułu GPS, dlatego jej gł˛ebsze badanie nie ma sensu - bład ˛ ten wystapi ˛ już przy pierwszym uruchomieniu i wymaga jedynie modyfikacji manifestu aplikacji. Natomiast drugi, może być spowodowany jeśli podany jako argument dostawca danych lokalizacyjnych, nie istnieje albo obiekt jest pusty. Obiekt null jest zwracany gdy nie ma ostatniej znanej lokalizacji lub dostawca jest wyłaczony. ˛ Przeprowadzono wiec ˛ testy danej metody, przecia˛żajac ˛ jej kod tak aby kończył sie˛ on wyjatkiem ˛ java.lang.IllegalArgumentException, a nast˛epnie aby zwracała obiekt pusty. Scenariusz Przygotowanie testu — Zainstalowano aplikacje˛ Endomondo. Numer Krok kroku Oczekiwany rezultat 1 Uruchomienie aplikacji Ekran główny aplikacji 2 Z zakładek aplikacji, wybranie do- Ulubione trasy lub informacja o ste˛ pnych tras braku połaczenia ˛ Tablica 5.5: Scenariusz badań dla metody LocationManager.getLastKnownLocation(java.lang.String) Analiza wyników W ramach testów przeprowadzono po 30 testów z różnymi wartościami prawdopodobieństwa błe˛ du (0,1; 0,25 oraz 0,5) dla każdej wybranej modyfikacji kodu co daje łacznie ˛ 180 badań. Tabela 5.6 oraz wykres z rys. 5.11 prezentuja˛ zależności czasowe pomie˛ dzy poszczególnymi wywołaniami metody dla wykonania wzorcowego (bezbłe˛ dnego). Wynika z niego, że wszystkie wywołania metody z rozpoznania zostały pokryte przez scenariusz. 59 5.2. Endomondo Numer Czas[s] wywołania Miejsca wołania metody Metody, klasy oraz pakiety com.endomondo.android.common pochodza˛ z paczki 1 0,0 AdConfManager.fetchLastLocation(AdConfManager.java:241) 2 14,726 AdConfManager.fetchLastLocation(AdConfManager.java:241) 3 39,624 AdConfManager.fetchLastLocation(AdConfManager.java:241) 4 39,684 TrackManager$TrackListLoader .fetchLocation(TrackManager.java:578) Tablica 5.6: Zależności czasowe oraz miejsca wywołań testowanej metody LocationManager.getLastKnownLocation(java.lang.String) dla wykonania wzorcowego Rysunek 5.11. Zależności czasowe poszczególnych wywołań metody LocationManager.getLastKnownLocation(java.lang.String) w wykonaniu wzorcowym 5.2. Endomondo 60 Testowana metoda, w ramach badań, została wywołana 662 razy z czego przecia˛żony kod wstrzyknie˛ to 169 razy. Wymuszenie sytuacji błednej ˛ w 73 przypadkach spowodowało wyłaczenie ˛ aplikacji. Błedy ˛ były powodowane wyłacz˛ nie przez wyjatek ˛ IllegalArgumentException, dlatego analizie poddano wyłacznie ˛ dane dotyczace ˛ tych testów. Wykres przedstawiony na rys. 5.12 prezentuje kategorie błe˛ du w zależności od numeru iteracji metody w danym teście. Natomiast wykres z rys. 5.13 pokazuje zależność miedzy ˛ miejscem wywołania, a kategoria˛ danego błedu. ˛ Z ich analizy jasno wynika, że metoda AdConfManager.fetchLastLocation(AdConfManager.java:241) jest wywoływana dużo cze˛ ściej, a nieobsłużenie wyjatku ˛ IllegalArgumentException, którym kończy sie˛ metoda badana, objawia sie˛ wyłaczeniem ˛ aplikacji. Nie powinno mieć to miejsca, szczególnie, że moduł ten służy wyłacznie ˛ do konfigurowania wyświetlanych reklam, a nie odpowiada za realizacje˛ funkcjonalności dla użytkownika. Druga z nich, która wykorzystuje badana˛ metode, ˛ również nie obsługuje poprawnie przygotowanej sytuacji, jednak nie powoduje to całkowitego wyłaczenia ˛ aplikacji, a jedynie powrót do ekranu głównego - bez żadnego komunikatu. Warto zwrócić tu uwage˛ na zależności czasowe. Na poczatku, ˛ dla danego scenariusza, wywoływana jest metoda z klasy AdConfManager, która wykonuje sie˛ w watku. ˛ Wymuszenie w nim sytuacji krytycznej objawia sie˛ wiec ˛ zawieszeniem interfejsu użytkownika i oczekiwaniem na jego zakończenie, a nastepnie ˛ powoduje wyłacze˛ nie aplikacji. Czasem zdarza sie, ˛ że metoda z klasy TrackManager wykonuje sie˛ przed ostatnim wywołaniem funkcji z modułu zarzadzania ˛ reklam, co ma swoje uzasadnienie ze wzgle˛ du na wywoływanie tej procedury w watku. ˛ Przekłada sie˛ to bezpośrednio na fakt, że dla wywołania numer 3 obserwuje sie˛ również kategorie˛ bł˛edu 5, która faktycznie powodowana jest przez inna˛ funkcje. ˛ Należy również zauważyć, że w wielu przypadkach, dla pojedynczego testu, bład ˛ wstrzykiwano wiecej ˛ niż w jednej iteracji metody. Prawdopodobnie było to powodowane przez wywoływanie kodu programu w watkach, ˛ które pomimo zawieszenia aplikacji dalej działały. ˛ podczas badań, dlatego Wszystkie miejsca wywołań testowanej metody wystapiły można stwierdzić iż pokryły one wykonania w 100%. 5.2. Endomondo 61 Rysunek 5.12. Liczba testów w poszczególnych kategoriach w zależności od numeru iteracji zakłócanej metody LocationManager.getLastKnownLocation(java.lang.String) Rysunek 5.13. Liczba testów w poszczególnych kategoriach w zależności od miejsca wywołania zakłócanej metody LocationManager.getLastKnownLocation(java.lang.String) LocationManager.getProvider(java.lang.String) Zgodnie z dokumentacja˛ systemu, metoda ta w przypadku niepowodzenia, może zwracać pusty obiekt albo kończyć sie˛ jednym z dwóch wyjatków ˛ 62 5.2. Endomondo Rysunek 5.14. Liczba testów w poszczególnych kategoriach w zależności od wartości prawdopodobieństwa dla zakłócanej metody LocationManager.getLastKnownLocation(java.lang.String) IllegalArgumentException oraz SecurityException. Pierwszy z nich może wystapić, ˛ jeśli podany argument jest obiektem null, co z uwagi na to iż zazwyczaj nie jest to generowany, a statyczny tekst, jego badanie może nie mieć celu. Podobnie jest z drugim wyjatkiem. ˛ Wystepuje ˛ on jeśli aplikacja nie ma uprawnień do wykorzystywania mechanizmów służacych ˛ do pobierania lokalizacji. Bład ˛ zgłaszany jest przy wywołaniu tej metody (jego wykrycie jest ułatwione), a naprawa wymaga jedynie dodania uprawień w manifeście aplikacji. Stad, ˛ zdecydowano sie˛ na jej przecia˛żenie tak aby zwracała pusty obiekt - null. Scenariusz Przygotowanie testu — Zainstalowano aplikacje˛ Endomondo, — określono lokalizacje˛ GPS dla systemu. Numer Krok kroku Oczekiwany rezultat 1 Ekran główny aplikacji (należy poczekać do momentu, w którym aplikacja sygnalizuje brak sygnału GPS, oczekiwanie na pozycje˛ albo określenie lokalizacji Uruchomienie aplikacji 63 5.2. Endomondo 2 Z zakładek aplikacji, wybranie do- Ulubione trasy lub informacja o ste˛ pnych tras braku połaczenia ˛ Tablica 5.7: Scenariusz badań dla metody LocationManager.getProvider(java.lang.String) Analiza wyników Metode˛ przebadano dla różnych wartości prawdopodobieństw (0,1; 0,25; 0,5) wykonujac ˛ po 30 badań dla każdej z nich. Analiza tabeli 5.8, która prezentuje jej miejsca wywołania wraz z zależnościami czasowymi, pozwala stwierdzić, że scenariusz w 100% pokrywa użycie metody przez aplikacje. ˛ Wykres na rys. 5.15 zawiera wizualizacje˛ tych danych. Numer Czas[s] wywołania Miejsca wołania metody Wszystkie metody, klasy oraz com.endomondo.android.common pakiety pochodza˛ z paczki 1 0,0 AdConfManager.fetchLastLocation(AdConfManager.java:239) 2 0,036 AdConfManager.fetchLastLocation(AdConfManager.java:248) 3 1,711 GPSInterface.requestLocUpdates(GPSInterface.java:95) 4 9,771 AdConfManager.fetchLastLocation(AdConfManager.java:239) 5 9,799 AdConfManager.fetchLastLocation(AdConfManager.java:248) 6 39,539 AdConfManager.fetchLastLocation(AdConfManager.java:239) 7 39,568 AdConfManager.fetchLastLocation(AdConfManager.java:248) 8 39,633 TrackManager$TrackListLoader .fetchLocation(TrackManager.java:577) 9 39,672 TrackManager$TrackListLoader .fetchLocation(TrackManager.java:582) Tablica 5.8: Zależności czasowe oraz miejsca wywołań testowanej metody LocationManager.getProvider(java.lang.String) dla wykonania wzorcowego W ramach testów, metode˛ wywołano 609 razy z czego sytuacje˛ błedn ˛ a˛ wymuszono 170 razy. Aplikacja poprawnie ja˛ obsługuje i nie zaobserwowano błedów ˛ 5.2. Endomondo 64 Rysunek 5.15. Zależności czasowe poszczególnych wywołań metody LocationManager.getProvider(java.lang.String) w wykonaniu wzorcowym krytycznych. Analizujac ˛ szczegółowe badania należy stwierdzić, że do ich analizy należy podjeść nieco odmiennie niż w poprzednich przypadkach. Jest to spowodowane faktem, że w wielu testach bład ˛ wstrzykiwany był wielokrotnie i nie można precyzyjnie określić, które wywołanie faktycznie spowodowało dany bład. ˛ Sporzadzony ˛ wykres widoczny na rys. 5.16, w którym pierwsze miejsce wyste˛ pujace ˛ w teście było łaczone ˛ z kategoria˛ błedu, ˛ pozwala stwierdzić, że metoda GPSInterface.requestLocUpdates z klasy GPSInterface zawsze powoduje problemy. Mamy wie˛ c pewna˛ podstawe˛ aby twierdzić, że to wyłacznie ˛ ona jest przyczyna˛ błe˛ dów. Celem uargumentowania tej tezy, stworzono wykres z rys. 5.17, który obrazuje kategorie˛ błe˛ du w zależności od miejsca, z ta˛ różnica, ˛ że jeśli w teście wystapiło ˛ wywołanie ze wspomnianej metody to badanie było ignorowane. Wynika z niego jednoznacznie, że bład ˛ wstrzykniety ˛ w innej metodzie nie powoduje wystapienia ˛ sytuacji krytycznej. Można stwierdzić, że za faktyczne ustalenie lokalizacji odpowiada GPSInterface.requestLocUpdates. Dla niej, jak już wspomniano, obserwujemy wyłacznie ˛ jedna˛ kategorie˛ błe˛ du, a w szczegółowych badaniach niepoprawnej sytuacji odpowiada reakcja - aplikacja sygnalizuje brak sygnału GPS. Jest wiec ˛ ona poprawnie obsługiwana. Wykres z rys. 5.18 ukazuje, że wraz ze wzrostem wartości prawdopodobieństwa rośnie liczba wstrzyknietych ˛ błedów ˛ oraz tych skategoryzowanych jako krytyczne. 5.2. Endomondo Rysunek riach w 5.16. Liczba testów w poszczególnych zależności od miejsca wywołania zakłócanej LocationManager.getProvider(java.lang.String) 65 kategometody Rysunek 5.17. Liczba testów w poszczególnych kategoriach w zależności od miejsca wywołania zakłócanej metody LocationManager.getProvider(java.lang.String) z modyfikacjami android.database.sqlite.SQLiteOpenHelper.getReadableDatabase() Przecia˛żony kod został tak przygotowany aby metoda rzucała wyjatek ˛ android.database.sqlite.SQLiteException. 66 5.2. Endomondo Rysunek 5.18. Liczba testów w poszczególnych kategoriach w zależności od prawdopodobieństwa dla zakłócanej metody LocationManager.getProvider(java.lang.String) Scenariusz Przygotowanie testu — Zainstalowano aplikacje˛ Endomondo. Uwaga: Podczas wykonywania testu, może zdarzyć sie, ˛ że po zakończeniu treningu, a przed zakończeniem ostatniego kroku, aplikacja wyświetla opcje˛ współdzielenia odbytego ćwiczenia z innymi użytkownikami. W takim przypadku należy przejść za pomoca˛ przycisku powrotu do głównego ekranu. Dodatkowo zaleca sie˛ naprzemienny wybór jezyków ˛ co znacznie ułatwia weryfikacje˛ czy nastapiła ˛ faktyczna ich zmiana. Numer Krok kroku Oczekiwany rezultat 1 Uruchomienie aplikacji Ekran główny aplikacji 2 Zmiana sportu na dowolny inny Wybrano inny sport 3 Z zakładek aplikacji, wybrać usta- Wybrana dowolny jezyk, ˛ wyświetlił wienia, naste˛ pnie opcje dźwieku, ˛ sie˛ ekran główny aplikacji opcje je˛ zyków oraz głosu, syntezator systemu Android, wybrać dowolny je˛ zyk, a nastepnie ˛ potwierdzić wybór i za pomoca˛ przycisku powrotu, wrócić do ekranu głównego 67 5.2. Endomondo 4 Właczyć ˛ dowolny trening, zatrzy- Na ekranie głównym powinny zomać, a naste˛ pnie go zastopować stać wyświetlone dane z treningu 5 Z zakładek aplikacji wybrać opcje˛ Wyświetla˛ sie˛ wyzwania, pusta liwyzwań sta lub informacja o braku poła˛ czenia sieciowego Tablica 5.9: Scenariusz badań dla metody SQLiteOpenHelper.getReadableDatabase() Analiza wyników Dla badanej metody wykonano 90 testów, dla różnych wartości prawdopodobieństwa wstrzyknie˛ cia błe˛ du. Tabela 5.10 oraz wykres z rys. 5.19 prezentuja˛ zależności czasowe dla wykonania wzorcowego. Z analizy miejsc wywołań wynika, że scenariusz pokrywa powyżej 80% wywołań wyznaczonych w rozpoznaniu. Warto również zwrócić uwage˛ , że jeśli metoda testowana jest wywoływana, to zawsze, wielokrotnie w krótkich odste˛ pach czasu. Numer Czas[s] wywołania Miejsca wołania metody Metody oraz pakiety pochodza˛ z paczki com.endomondo.android.common (chyba, że zaznaczono inaczej) 1 0,0 2 0,058 EndomondoDatabase.<init>(EndomondoDatabase.java:141) dao.WorkoutDao .getWorkoutIdsWithPendingExtras(WorkoutDao.java:107) 3-7 EndomondoDatabase 0,627 .getAdConfCursor(EndomondoDatabase.java:3546) 0,736 8 0,78 EndomondoDatabase .getAdConfCursor(EndomondoDatabase.java:3546) 9 1,739 EndomondoDatabase .getZonesCursor(EndomondoDatabase.java:3860) 10 13 14 EndomondoDatabase - 3,038 .getWorkoutCursor(EndomondoDatabase.java:995) 3,624 3,754 com.google.android.apps.analytics.PersistentHitStore .getVisitorVarBuffer(Unknown Source) 68 5.2. Endomondo 15 3,81 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 16 3,813 com.google.android.apps.analytics.PersistentHitStore .getNumStoredHitsFromDb(Unknown Source) 17 4,125 EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 18 9,003 EndomondoDatabase .getMostUsedSportsCursor(EndomondoDatabase.java:1434) 19 10,962 EndomondoDatabase .getZonesCursor(EndomondoDatabase.java:3860) 20 29,282 com.google.android.apps.analytics.PersistentHitStore .peekHits(Unknown Source) 21 37,154 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 22 42,19 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 23 42,314 EndomondoDatabase .getPremiumDataCursor(EndomondoDatabase.java:4741) 24 42,33 EndomondoDatabase .getWorkoutExtras(EndomondoDatabase.java:4786) 25 42,385 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 26 42,451 EndomondoDatabase .getPremiumDataCursor(EndomondoDatabase.java:4741) 27 42,515 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 28 42,603 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 29 42,74 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 69 5.2. Endomondo 30 42,796 EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 31 42,823 EndomondoDatabase .getPremiumDataCursor(EndomondoDatabase.java:4741) 32 42,859 EndomondoDatabase .getWorkoutExtras(EndomondoDatabase.java:4786) 33 43,215 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 34 43,279 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 35 43,372 EndomondoDatabase .getPremiumDataCursor(EndomondoDatabase.java:4741) 36 43,408 EndomondoDatabase .getWorkoutExtras(EndomondoDatabase.java:4786) 37 39 - 43,731 43,922 40 44,139 EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 41 44,177 EndomondoDatabase .getPremiumDataCursor(EndomondoDatabase.java:4741) 42 44,19 EndomondoDatabase .getWorkoutExtras(EndomondoDatabase.java:4786) 43 44,351 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 44 44,432 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 45 44,693 dao.WorkoutDao .getWorkoutIdsWithPendingExtras(WorkoutDao.java:107) 46 49,52 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 70 5.2. Endomondo 47 49,555 EndomondoDatabase .getPremiumDataCursor(EndomondoDatabase.java:4741) 48 49,569 EndomondoDatabase .getWorkoutExtras(EndomondoDatabase.java:4786) 49 49,606 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 50 49,654 EndomondoDatabase .getPremiumDataCursor(EndomondoDatabase.java:4741) 51 49,672 EndomondoDatabase .getWorkoutExtras(EndomondoDatabase.java:4786) 52 55 - 52,292 83,088 56 83,165 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 57 83,278 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 58 83,308 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 59 83,395 EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 60 62 - 83,474 83,642 63 83,705 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 64 66 - 83,814 83,951 67 84,028 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 71 5.2. Endomondo 68 70 - 84,123 84,269 71 84,337 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 72 84,536 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 73 84,616 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 74 84,746 EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 75 84,835 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 76 84,889 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 77 84,98 EndomondoDatabase .getWorkoutCursor(EndomondoDatabase.java:995) 78 85,046 EndomondoDatabase .getTrackPointCursor(EndomondoDatabase.java:1600) 79 98,153 EndomondoDatabase .getChallenges(EndomondoDatabase.java:4340) 80 98,262 EndomondoDatabase .getChallenges(EndomondoDatabase.java:4340) Tablica 5.10: Zależności czasowe oraz miejsca wywołań testowanej metody SQLiteOpenHelper.getReadableDatabase() dla wykonania wzorcowego W ramach badań metoda SQLiteOpenHelper.getReadableDatabase() została wywołana 2197 z czego 388 z nich zakończyło sie˛ wymuszeniem sytuacji bł˛ednej. W 247 przypadkach, przecia˛żony kod spowodował wyłaczenie ˛ aplikacji. Z analizy czasowej wynika, że aplikacja jest najbardziej podatna na bład ˛ podczas uruchamiania, gdyż już na samym poczatku ˛ testowana metoda jest wielokrotnie wykorzystywana. Podczas testów zaobserwowano, że przed wyłaczeniem, ˛ w znakomitej wie˛ kszości przypadków, interfejs aplikacji przestawał odpowiadać na reakcje 5.2. Endomondo 72 Rysunek 5.19. Zależności czasowe poszczególnych wywołań zakłócanej metody SQLiteOpenHelper.getReadableDatabase() w wykonaniu wzorcowym użytkownika, co może być spowodowane faktem iż zgodnie z zaleceniami badana metoda wywoływana była w osobnym watku, ˛ stad ˛ interfejs oczekiwał na jego zakończenie. Miejsca wywołań testowanej metody zostały pokryte w 100% wzgl˛edem miejsc wyznaczonych w scenariuszu. Ze wzgledu ˛ na fakt, że w znakomitej wiekszo˛ ści przypadków, dla pojedynczego testu metoda przecia˛żana była wielokrotnie, to nie można jednoznacznie utożsamiać kategorii błedu ˛ z konkretnym numerem wywołania czy też miejscem. Interesujacy ˛ jest jednak wykres widoczny na rys. 5.20, z którego wynika, że wraz ze wzrostem prawdopodobieństwa potrzeba mniejszej liczby wstrzyknie˛ ć błe˛ dnego kodu aby doprowadzić do sytuacji krytycznej. Analizujac ˛ równocześnie szczegółowa˛ tabele˛ badań, możemy stwierdzić, że jeśli bład ˛ wystapi ˛ podczas uruchamiania aplikacji Endomondo to może sie˛ ona nie właczyć. ˛ 73 5.2. Endomondo Rysunek 5.20. Średnia liczba wstrzyknietych ˛ błedów ˛ w zależności od prawdopodobieństwa dla zakłócanej metody SQLiteOpenHelper.getReadableDatabase() android.database.sqlite.SQLiteOpenHelper.getWritableDatabase() Badana metoda została przygotowana tak, android.database.sqlite.SQLiteException. aby kończyła sie˛ wyjatkiem ˛ Scenariusz Przygotowanie testu — Zainstalowano aplikacje˛ Endomondo. Uwaga: Podczas wykonywania testu, może zdarzyć sie, ˛ że po zakończeniu treningu, a przed zakończeniem ostatniego kroku, aplikacja wyświetla opcje˛ współdzielenia odbytego ćwiczenia z innymi użytkownikami. W takim przypadku należy przejść za pomoca˛ przycisku powrotu do głównego ekranu. Dodatkowo zaleca sie˛ naprzemienny wybór sportu co znacznie ułatwia weryfikacje˛ czy nastapiło ˛ ich usuniecie ˛ z historii (pomimo, że nie ma kroku zmiany sportu, jest on dozwolony ponieważ nie korzysta z badanej metody). Numer Krok kroku Oczekiwany rezultat 1 Uruchomienie aplikacji Ekran główny aplikacji 2 Zmień sport na inny niż jest usta- W głównym widoku aplikacji został wiony wybrany inny sport 3 Właczyć ˛ dowolny trening, zatrzy- Na ekranie głównym powinny zomać, a naste˛ pnie go zastopować stać wyświetlone dane z treningu 74 5.2. Endomondo 4 Po zakończonym treningu pocze- Widok z możliwościa˛ podsumowakać na okno zakończenia treningu nia treningu 5 Dodać opis dla danego treningu Dodano dodatkowe informacje, (pole informacji może pozostać pu- nastapił ˛ powrót do ekranu podsuste, należy je zatwierdzić za po- mowania treningu moca˛ przycisku na górnej belce 6 Usunać ˛ dany trening za pomoca˛ Trening został usuniety ˛ (nie ma go przycisku kosza na górnej belce i na liście) przejść do historii treningów 7 Z zakładek aplikacji wybrać opcje˛ Wyświetliła sie˛ lista przyjaciół (może być pusta) 8 Za pomoca˛ przycisków powrotu, Aplikacja została zamknieta, ˛ wyzakończyć działanie aplikacji świetlony został ekran startowy systemu przyjaciół Tablica 5.11: Scenariusz badań dla metody SQLiteOpenHelper.getWritableDatabase() Analiza wyników Dla metody przeprowadzono łacznie ˛ 90 testów - 30 dla różnych wartości prawdopodobieństwa. Tabela 5.12 prezentuje miejsca wywołań testowania metody z kodu aplikacji wraz z orientacyjnymi zależnościami czasowymi dla każdej iteracji. Wykres 5.21 zawiera dokładne zależności czasowe pomiedzy ˛ kolejnymi wywołaniami metody. Numer Czas[s] wywołania Miejsca wołania metody Metody oraz pakiety pochodza˛ z paczki com.endomondo.android.common (chyba, że zaznaczono inaczej) 1 0,0 purchase.PurchaseDatabase .<init>(PurchaseDatabase.java:76) 2 0,236 purchase.PurchaseDatabase .<init>(PurchaseDatabase.java:76) 3 3,741 EndomondoDatabase .deleteWorkouts(EndomondoDatabase.java:2590) 4 4,125 EndomondoDatabase .execSingleSqlStatement(EndomondoDatabase.java:651) 75 5.2. Endomondo 5 4,346 com.google.android.apps.analytics .PersistentHitStore.loadExistingSession(Unknown Source) 6 4,462 EndomondoDatabase .execSingleSqlStatement(EndomondoDatabase.java:651) 7 4,616 com.google.android.apps.analytics .PersistentHitStore.putEvent(Unknown Source) 8 4,632 com.google.android.apps.analytics .PersistentHitStore.storeUpdatedSession(Unknown Source) 9 14,23 purchase.PurchaseDatabase .<init>(PurchaseDatabase.java:76) 10 66 - 16,341 62,894 67 66,861 EndomondoDatabase .execSingleSqlStatement(EndomondoDatabase.java:651) dao.WorkoutDao .setWorkoutExtras(WorkoutDao.java:33) 68 71,231 EndomondoDatabase .deleteWorkouts(EndomondoDatabase.java:2590) 69 71,357 purchase.PurchaseDatabase .<init>(PurchaseDatabase.java:76) 70 96 97 EndomondoDatabase - 71,574 .execSingleSqlStatement(EndomondoDatabase.java:651) 105,054 117,51 EndomondoDatabase .updateUsers(EndomondoDatabase.java:4058) 98 120,152 purchase.PurchaseDatabase .<init>(PurchaseDatabase.java:76) 99 121,98 EndomondoDatabase .cleanComments(EndomondoDatabase.java:4449) 100 122,016 EndomondoDatabase .cleanUsers(EndomondoDatabase.java:4500) 101 122,105 EndomondoDatabase .deleteWorkouts(EndomondoDatabase.java:2590) 5.2. Endomondo 76 Tablica 5.12: Zależności czasowe oraz miejsca wywołań testowanej metody SQLiteOpenHelper.getWritableDatabase() dla wykonania wzorcowego Rysunek 5.21. Zależności czasowe poszczególnych wywołań metody SQLiteOpenHelper.getWritableDatabase() w wykonaniu wzorcowym W ramach badań metoda SQLiteOpenHelper.getWritableDatabase() została wywołana 3582. Przecia˛żony kod wstrzyknieto ˛ 544 razy, co w 260 przypadkach doprowadziło do wyłaczenia ˛ aplikacji. W kilku badaniach, zamkniecie ˛ aplikacji było spowodowane wykonaniem nieprawidłowej operacji, ale nie były to sytuacje wymuszone przez symulator. Scenariusz zapewniał pokrycie wywołań na poziomie 77%. Ponieważ metoda, w ramach testów, została wywołana ze wszystkich miejsc w nim zawartych, to procent pokrycia testów jest równy podanemu. Podobnie jak przy badaniach poprzedniej metody, liczba przecia˛żonych wywołań przypadajaca ˛ na jeden test jest zbyt duża aby jednoznacznie móc powiazać ˛ kategori˛e z numerem wykonania czy też miejscem. Tu również obserwujemy, że wraz ze zmniejszajac ˛ a˛ sie˛ wartościa˛ prawdopodobieństwa, łatwiej o krytyczne zachowanie aplikacji. Wnioski sa˛ wie˛ c także zbliżone, a mianowicie, sekwencja uruchamiania programu Endomondo jest dużo bardziej newralgiczna i podatna na błedy, ˛ co w konsekwencji może prowadzić to braku możliwości jej właczenia. ˛ 5.3. Play Music 77 Rysunek 5.22. Średnia liczba wstrzyknieć ˛ błedów ˛ w zależności od prawdopodobieństwa dla zakłócanej metody SQLiteOpenHelper.getWritableDatabase() 5.3. Play Music Play Music to standardowa aplikacja systemu Android (od wersji 4.1) służaca ˛ do zarzadzania ˛ oraz odtwarzania muzyki. Analizie poddano wersje˛ o numerze 5.0.1041J.689753. 5.3.1. Rozpoznanie Graf z rys. 5.23 prezentuje zależności pomiedzy ˛ funkcjami aplikacji, a metodami bibliotek systemu Android. Analizuja˛ plik logu pochodzacy ˛ z rozpoznania wskazuje, że testowana aplikacja korzysta z naste˛ pujacych ˛ metod, wykonujac ˛ je z podanych miejsc: — android.media.MediaPlayer.setDataSource(java.io.FileDescriptor,long,long): — android.media.MediaPlayer.setDataSource(MediaPlayer.java:1151), — android.media.MediaPlayer.setDataSource(java.io.FileDescriptor): — android.media.MediaPlayer.setDataSource(MediaPlayer.java:986), — android.media.MediaPlayer.prepare(): — com.google.android.music.playback .AsyncMediaPlayer.setDataSourceImpl(AsyncMediaPlayer.java:485), — android.media.MediaPlayer.start(): — android.media .MediaPlayer.postEventFromNative(MediaPlayer.java:2510), — com.google.android.music.playback .AsyncMediaPlayer.handleMessageImp(AsyncMediaPlayer.java:215), — android.media.MediaPlayer.pause(): — com.google.android.music.playback .AsyncMediaPlayer.handleMessageImp(AsyncMediaPlayer.java:222), android.media.MediaPlayer postEventFromNative com.google.android.music.playback. AsyncMediaPlayer.seekImpl com.android.providers.media. MediaProvider.query android.media.MediaPlayer.start com.google.android.music.download. cache.CacheUtils.isExternalStorageMounted android.media.MediaPlayer.seekTo android.database.sqlite. SQLiteOpenHelper.getReadableDatabase com.google.android.music.playback. AsyncMediaPlayer.handleMessageImp android.os.Environment.getExternalStorageState android.media.MediaPlayer.pause com.google.android.music. store.Store.getDatabase android.media.MediaPlayer.prepare android.database.sqlite. SQLiteOpenHelper.getWritableDatabase com.google.android.music.playback. AsyncMediaPlayer.setDataSourceImpl com.android.providers.media. MediaProvider$DatabaseHelper.getWritableDatabase com.google.android.music.store.ConfigStore.getDatabase 5.3. Play Music 78 Rysunek 5.23. Graf wywołań metod podczas rozpoznania dla aplikacji Play Music 5.3. Play Music 79 — android.media.MediaPlayer.seekTo(int): — com.google.android.music.playback .AsyncMediaPlayer.seekImpl(AsyncMediaPlayer.java:670), — android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(): — com.google.android.music.store .Store.getDatabase(Store.java:214), — com.google.android.music.store .ConfigStore.getDatabase(ConfigStore.java:69), — com.android.providers.media .MediaProvider$DatabaseHelper.getWritableDatabase(MediaProvider.java:377), — android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(): — com.android.providers.media .MediaProvider.query(MediaProvider.java:2062), — android.os.Environment.getExternalStorageState(): — com.google.android.music.download .cache.CacheUtils.isExternalStorageMounted(CacheUtils.java:47), — android.os.PowerManager.newWakeLock(int,java.lang.String): — android.media.MediaPlayer.setWakeMode(MediaPlayer.java:1432), — com.google.android.music.playback .AsyncMediaPlayer.<init>(AsyncMediaPlayer.java:142), — android.net.LocalServerSocket.close(): — com.android.internal.os .ZygoteInit.closeServerSocket(ZygoteInit.java:196), — android.os.PowerManager.isScreenOn(): — android.view.ViewRootImpl .<init>(ViewRootImpl.java:403), — android.net.LocalSocket.close(): — com.android.internal.os .ZygoteConnection.closeSocket(ZygoteConnection.java:271), — android.net.LocalSocket.getAncillaryFileDescriptors(): — com.android.internal.os .ZygoteConnection.runOnce(ZygoteConnection.java:182). Biorac ˛ pod uwage˛ znaczenie tych metod oraz możliwości testowania nie wszystkie z nich zostana˛ zbadane. Metody MediaPlayer.setDataSource(java.io.FileDescriptor) oraz MediaPlayer.setDataSource(java.io.FileDescriptor,long,long) sa˛ wywoływane z klasy android.media.MediaPlayer - nie udało sie˛ znaleźć dokładnego miejsca wywołań, jednak sa˛ to pierwsze metody odwołujace ˛ sie˛ do tej biblioteki. Dlatego zdecydowano sie˛ na sprawdzenie ich obsługi. Z kolei metoda PowerManager.newWakeLock(int,java.lang.String nie bedzie ˛ badana ze wzgle˛ dów na ograniczenia systemu, o czym wspomniano przy testowaniu aplikacji Endomondo (5.2). Ostatnie cztery metody nie bed ˛ a˛ testowane ze wzgl˛edu na ich małe znaczenie dla aplikacji oraz z uwagi na fakt, że sa˛ one zazwyczaj wywoływane na zakończenie aplikacji i nie maja˛ już wpływu na dane czy też interfejs użytkownika. Należy również zwrócić uwage, ˛ że metoda MediaPlayer.start() wywoływana jest z dwóch miejsc, z czego jedno to kod biblioteki. Z punktu widzenia aplikacji istotne jest jedno miejsce, dlatego bedzie ˛ ona testowana wyłacznie ˛ z prawdopodobieństwem 1,0. 5.3. Play Music 80 5.3.2. Badania metod wywoływanych z jednego miejsca android.media.MediaPlayer.setDataSource(java.io.FileDescriptor) oraz android.media.MediaPlayer.setDataSource(java.io.FileDescriptor,long,long) Metody te zwracaja˛ takie same wyjatki ˛ oraz ich reakcja jest zbliżona, dlatego opisano je razem. Przetestowano te metody dla nastepuj ˛ acych ˛ wyjatków ˛ oraz zaobserwowano reakcje: — java.lang.IllegalStateException - aplikacja sie˛ wyłacza, ˛ — java.io.IOException - bład ˛ jest ignorowany, nie zauważono negatywnego wpływu, — java.lang.IllegalArgumentException - aplikacja wyświetla komunikat o braku możliwości obsłużenia utworu. Obserwuje sie˛ problem dotyczacy ˛ testowania obiektu klasy MediaPlayer, gdyż nie ma możliwości wymuszenia faktycznie złego stanu, a temu mogłyby zapobiegać mechanizmy poprzedzajace ˛ wywołanie metody, stad ˛ samo wywołanie java.lang.IllegalStateException jest niewystarczajace. ˛ Pomimo to, metoda ta, jak i inne ze wspomnianej klasy, zostały przetestowane pod katem ˛ tego wyjatku ˛ i w przypadku błe˛ dnej obsługi powinien być to sygnał, że należy sprawdzić czy faktycznie kontrolowany jest stan obiektu. Dokładniej, stan obiektu klasy android.media.MediaPlayer został opisany w dokumentacji systemu Android3 . android.media.MediaPlayer.prepare() Dla tej metody przygotowano dwa warianty wymuszenia błednej ˛ sytuacji. W pierwszym przypadku, przecia˛żony kod powodował rzucenie wyjatku ˛ java.lang.IllegalStateException, co spowodowało zamkniecie ˛ aplikacji. Druga sytuacja powodowała zakończenie sie˛ jej wyjatkiem ˛ java.io.IOException. Jest ona poprawnie obsługiwana - aplikacja informuje użytkownika, za pomoca˛ komunikatu, o niemożliwości odtworzenia utworu. android.media.MediaPlayer.start() Kod metody bibliotecznej został spreparowany aby jej wykonanie kończyło sie˛ wyjatkiem ˛ java.lang.IllegalStateException. Podczas uruchamiania muzyki, aplikacja wyłacza ˛ sie˛ . android.media.MediaPlayer.pause() Metode˛ przecia˛żono aby kończyła sie˛ wyjatkiem ˛ java.lang .IllegalStateException. Podczas zatrzymywania muzyki, aplikacja sie˛ wyłacza. ˛ android.media.MediaPlayer.seekTo(int) Kod metody zmodyfikowano aby rzucała wyjatek ˛ java.lang .IllegalStateException. Bład ˛ wystapił ˛ w trakcie przewijania utworu i spowodował wyłaczenie ˛ aplikacji. android.os.Environment.getExternalStorageState() Metoda została przygotowana aby zwracać stan pamieci ˛ zewnetrznej ˛ jako usuni˛ety (ang. removed). Nie obserwuje sie˛ negatywnego wpływu na aplikacje. ˛ 3 Stan obiektu MediaPlayer - http://developer.android.com/reference/android/media/ MediaPlayer.html#StateDiagram 81 5.3. Play Music android.database.sqlite.SQLiteOpenHelper.getReadableDatabase() Domyślna˛ implementacje˛ metody przecia˛żono aby zawsze kończyła sie˛ wyjat˛ kiem android.database.sqlite.SQLiteException. Jest ona wywoływana m.in. podczas próby odtwarzania utworu. Wymuszona sytuacja krytyczna kończy sie˛ wyłaczeniem ˛ aplikacji. 5.3.3. Badania metod wywoływanych z wielu miejsc android.database.sqlite.SQLiteOpenHelper.getWritableDatabase() Metoda została przecia˛żona aby android.database.sqlite.SQLiteException. kończyła sie˛ wyjatkiem ˛ Scenariusz Przygotowanie testu — Zainstalowano aplikacje˛ Play Music, — w bibliotece muzyki znajduje sie˛ co najmniej jeden utwór. Numer Krok kroku Oczekiwany rezultat 1 Ekran główny aplikacji Uruchomić aplikacje˛ Play Music Tablica 5.13: Scenariusz badań dla metody SQLiteOpenHelper.getWritableDatabase() Analiza wyników Tabela 5.14 zawiera kolejność wywołań metody wraz z miejscem oraz czasem wywołania. Wykres z rys. 5.24 prezentuje dokładne zależności czasowe miedzy ˛ jej kolejnymi wywołaniami. Scenariusz zapewnia pokrycie 2 z 3 wywołań, ponieważ nie udało sie˛ odtworzyć sytuacji, w której udałoby sie˛ w powtarzalny sposób wymusić brakujace ˛ wykonanie. Numer Czas[s] wywołania Miejsca wołania metody Wszystkie metody oraz pakiety com.google.android.music.store pochodza˛ 1 0.0 2-4 0,008 - ConfigStore.getDatabase(ConfigStore.java:69) 0,446 Store.getDatabase(Store.java:214) z paczki 5.3. Play Music 5 - 47 82 2,142 - Store.getDatabase(Store.java:214) 9,5 Tablica 5.14: Zależności czasowe oraz miejsca wywołań testowanej metody SQLiteOpenHelper.getWritableDatabase() dla wykonania wzorcowego Rysunek 5.24. Zależności czasowe poszczególnych wywołań zakłócanej metody SQLiteOpenHelper.getWritableDatabase() w wykonaniu wzorcowym W ramach testów, badana metoda została wywołana 904 razy z czego przecia˛ żony kod wstrzyknie˛ to 200 razy. Maksymalny, zaobserwowany numer iteracji podczas badań to 26. Każde wymuszenie błednej ˛ sytuacji kończyło sie˛ wyłaczeniem ˛ aplikacji, co widać na wykresie z rys. 5.25. Mimo iż wykres z rys. 5.26 wskazuje, że metoda wywoływana była mniej wiecej ˛ w takiej samej liczbie, to jednak uwzglednia˛ jac ˛ fakt, że prezentuje on wyłacznie ˛ pierwsze wywołania w ramach każdego testu oraz analizujac ˛ dokładniej wszystkie wykonania metody, możemy stwierdzić, że zdecydowanie cze˛ ściej wywoływana jest metoda getDatabase z klasy Store. 5.4. VLC 83 Rysunek 5.25. Liczba testów w poszczególnych kategoriach w zależności od numeru iteracji zakłócanej metody SQLiteOpenHelper.getWritableDatabase() Rysunek 5.26. Liczba testów w poszczególnych kategoriach w zależności od miejsca wywołania zakłócanej metody SQLiteOpenHelper.getWritableDatabase() 5.4. VLC VLC to bardzo popularna aplikacja do odtwarzania oraz strumieniowania multimediów na komputery osobiste. Od niedawna dostepna ˛ jest również, w wersji beta, 84 5.4. VLC org.videolan.vlc.betav7neon.MediaDatabase.<init> org.videolan.vlc.betav7neon.Util.hasExternalStorage android.database.sqlite.SQLiteOpenHelper.getWritableDatabase org.videolan.vlc.betav7neon.MediaLibrary$GetMediaItemsRunnable.run android.os.Environment.getExternalStorageState Rysunek 5.27. Graf wywołań metod podczas rozpoznania dla aplikacji VLC dla systemu Android. Badaniom poddano wersje˛ o numerze 9837e1e wydana˛ w dniu 23.05.2013. 5.4.1. Rozpoznanie Metody oraz miejsca ich wywołań zaprezentowano na grafie z rys. 5.27. Rozpoznanie pozwoliło wykryć wykorzystywane metody systemowe oraz określić miejsce ich wywołania: — android.net.LocalServerSocket.close(): — com.android.internal.os.ZygoteInit.closeServerSocket(ZygoteInit.java:196), — android.os.PowerManager.isScreenOn(): — android.view.ViewRootImpl.<init>(ViewRootImpl.java:403), — android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(): — org.videolan.vlc.betav7neon.MediaDatabase.<init>(MediaDatabase.java:98), — android.os.Environment.getExternalStorageState(): — org.videolan.vlc.betav7neon .MediaLibrary$GetMediaItemsRunnable.run(MediaLibrary.java:329), — org.videolan.vlc.betav7neon.Util.hasExternalStorage(Util.java:280), — android.os.PowerManager.newWakeLock(int,java.lang.String): — org.videolan.vlc.betav7neon.AudioService.onCreate(AudioService.java:152), — android.net.LocalSocket.close(): — com.android.internal.os.ZygoteConnection .closeSocket(ZygoteConnection.java:271), Analizujac ˛ wykorzystywane przez aplikacje˛ metody należy stwierdzić, że należy przepadać wyłacznie ˛ dwie z nich: SQLiteOpenHelper.getWritableDatabase() oraz Environment.getExternalStorageState(). Pozostałe maja˛ marginalne znaczenie albo nie można ich przetestować - o czym wspominano przy wcześniej opisanych badaniach innych aplikacji. 85 5.4. VLC 5.4.2. Badania metod wywoływanych z jednego miejsca android.database.sqlite.SQLiteOpenHelper.getWritableDatabase() System zmodyfikowano aby metoda kończyła sie˛ wyjatkiem ˛ SQLiteException. Wymuszona sytuacja krytyczna nie jest obsługiwana i powoduje wyłaczenie ˛ sie˛ aplikacji podczas jej właczania. ˛ 5.4.3. Badania metod wywoływanych z wielu miejsc android.os.Environment.getExternalStorageState() W ramach badań testowana metoda zwracała informacje˛ o tym, że karta pami˛eci nie jest zamontowana (ang. removed). Scenariusz Przygotowanie testu — Zainstalowano aplikacje˛ VLC, — pamie˛ ć zewne˛ trzna dodana jako biblioteka multimediów w programie, — na karcie pamie˛ ci znajduje sie˛ przynajmniej jeden film w formacie mp4. Numer Krok kroku Oczekiwany rezultat 1 Uruchomienie aplikacji VLC Ekran główny aplikacji 2 Przejście do zakładki folderów Wyświetlone zostały dostepne ˛ katalogi wraz z liczba˛ plików (co najmniej 1) 3 Przejście do zakładki filmów Wyświetlone zostały filmy (co najmniej 1) dostepne ˛ Tablica 5.15: Scenariusz badań dla metody Environment.getExternalStorageState() Analiza wyników Dla analizowanej metody przeprowadzono 30 testów z różnymi wartościami prawdopodobieństwa błe˛ du (0,1; 0,25 oraz 0,5) - łacznie ˛ 90 testów. W tabeli 5.4.3 zaprezentowano zależności czasowe poszczególnych wywołań dla wykonania wzorcowego. Wykres z rys. 5.28 dokładniej wizualizuje te dane. 86 5.4. VLC Numer Czas[s] wywołania Miejsca wołania metody Wszystkie metody, klasy oraz org.videolan.vlc.betav7neon 1 0,0 pakiety pochodza˛ z paczki MediaLibrary$GetMediaItemsRunnable .run(MediaLibrary.java:329) 2 - 11 5,196 - Util.hasExternalStorage(Util.java:280) 5,727 Tablica 5.16: Zależności czasowe oraz miejsca wywołań testowanej metody Environment.getExternalStorageState() dla wykonania wzorcowego Rysunek 5.28. Zależności czasowe poszczególnych wywołań zakłócanej metody Environment.getExternalStorageState() w wykonaniu wzorcowym Analizujac ˛ miejsca wywołań z wykonania wzorcowego, można stwierdzić, że pokrywa ono scenariusz w 100%. Badana metoda została wywołana 1037 razy. Przecia˛żony kod wstrzyknieto ˛ 317 z czego 316 przypadkach wystapił ˛ bład ˛ krytyczny, a maksymalnym zaobserwowanym numerem iteracji był 12. Przy testowaniu tej metody wystapił ˛ poważny problem określenia kiedy faktycznie mamy do czynienia z błedem. ˛ Podczas samego 5.5. Android Browser 87 badania, użytkownik nie wie czy przecia˛żono dana˛ metode˛ czy też nie. W tym przypadku, jeśli ja˛ wstrzyknie˛ to, aplikacja powinna uznać, że karta pamieci ˛ jest niedost˛epna, a tak nie było (poza jednym przypadkiem). Z punktu widzenia testujacego ˛ można było przegladać ˛ pliki i program działał poprawnie - stad ˛ w szczegółowym opisie badań, adnotacja “brak błedów”. ˛ Jednak należy uznać, że jeśli wstrzykni˛eto spreparowany kod, to aplikacja powinna zauważyć, że nie ma karty pamieci ˛ i wyświetlić stosowny komunikat. Niestety system AFIS nie umożliwia aby przy modyfikowaniu tej metody faktycznie odłaczyć ˛ pamieć ˛ zewnetrzn ˛ a. ˛ Stan faktyczny nie zgadza sie˛ wie˛ c z tym co zwraca metoda. Nie mniej jednak skoro aplikacja ja˛ wywołuje, to powinna sprawdzać i uzależniać swoje działanie od jej wyniku. Ponieważ na wiele testów przypadało znacznie wiecej ˛ niż jedno przecia˛żenie metody, na wykresie z rys. 5.29 przedstawiono średnia˛ liczbe˛ wywołań, które przypadały na jedno badanie w zależności od obserwowanej kategorii błedu. ˛ Rysunek 5.29. Średnia liczba wstrzyknieć ˛ błedów ˛ w zależności od wartości prawdopodobieństwa dla zakłócanej metody Environment.getExternalStorageState() 5.5. Android Browser Android Browser to standardowa przegladarka ˛ stron WWW systemu operacyjnego Android. Mimo iż wielu użytkowników doinstalowuje bardziej popularne aplikacje takie jak Chrome, Firefox czy Opera, to jednak warto przyjrzeć sie˛ tej domyślnej, która korzysta z dostarczanej biblioteki android.webkit. Analizie poddano aplikacje˛ w wersji 4.1.2. 5.5.1. Rozpoznanie Na rysunku 5.30 zaprezentowano graf wywołań, wykorzystywanych przez badana˛ aplikacje˛ , metod systemowych. Dokładniejsza analiza rozpoznania pozwala określić miejsca wywołań tych metod: com.android.browser.provider. BrowserProvider2.updateHistoryInTransaction com.android.browser.provider. BrowserProvider2.insertInTransaction com.android.browser.provider. SQLiteContentProvider.insert com.android.browser.provider. SQLiteContentProvider.update com.android.browser.provider. SnapshotProvider.getWritableDatabase com.android.browser.provider. BrowserProvider2.updateBookmarksInTransaction com.android.browser.provider. BrowserProvider2.deleteInTransaction com.android.browser.provider. BrowserProvider2.updateInTransaction com.android.browser.provider. BrowserProvider2.deleteBookmarks com.android.browser.provider. BrowserProvider2.pruneImages com.android.browser.provider. SQLiteContentProvider.delete com.android.browser. AutoFillProfileDatabase.getDatabase com.android.browser.Tab.saveState com.android.browser.Tab.canGoForward android.webkit.GeolocationService. unregisterFromLocationUpdates android.webkit.GeolocationService. registerForLocationUpdates com.android.browser.Tab.canGoBack android.webkit.WebView.saveState android.webkit.WebView.canGoForward android.location.LocationManager. removeUpdates android.location.LocationManager. requestLocationUpdates android.webkit.WebView.canGoBack com.android.browser.provider. SnapshotProvider.getReadableDatabase android.database.sqlite. SQLiteOpenHelper.getReadableDatabase com.android.browser.provider. BrowserProvider2.query android.database.sqlite. SQLiteOpenHelper.getWritableDatabase 5.5. Android Browser 88 Rysunek 5.30. Graf wywołań metod podczas rozpoznania dla aplikacji Android Browser 5.5. Android Browser 89 — android.webkit.WebView.saveState(android.os.Bundle): — Tab.saveState(Tab.java:1718), — android.webkit.WebView.canGoBack(): — Tab.canGoBack(Tab.java:1947), — android.webkit.WebView.canGoForward(): — Tab.canGoForward(Tab.java:1951), — android.location.LocationManager.requestLocationUpdates( java.lang.String,long,float,android.location.LocationListener): — android.webkit.GeolocationService .registerForLocationUpdates(GeolocationService.java:162), — android.location.LocationManager .removeUpdates(android.location.LocationListener): — android.webkit.GeolocationService .unregisterFromLocationUpdates(GeolocationService.java:181), — android.database.sqlite.SQLiteOpenHelper.getReadableDatabase() (klasy i metody pochodza˛ z paczki com.android.browser): — AutoFillProfileDatabase.getDatabase(AutoFillProfileDatabase.java:95), — provider.BrowserProvider2.query(BrowserProvider2.java:879), — provider.SnapshotProvider.getReadableDatabase(SnapshotProvider.java:147), — android.database.sqlite.SQLiteOpenHelper.getWritableDatabase() (klasy i metody pochodza˛ z paczki provider): — BrowserProvider2.insertInTransaction(BrowserProvider2.java:1369), — BrowserProvider2.updateHistoryInTransaction(BrowserProvider2.java:1965), — BrowserProvider2.updateInTransaction(BrowserProvider2.java:1619), — SQLiteContentProvider.delete(SQLiteContentProvider.java:178), — BrowserProvider2.pruneImages(BrowserProvider2.java:2067), — BrowserProvider2.deleteBookmarks(BrowserProvider2.java:1211), — BrowserProvider2.deleteInTransaction(BrowserProvider2.java:1226), — SQLiteContentProvider.insert(SQLiteContentProvider.java:112), — SnapshotProvider.getWritableDatabase(SnapshotProvider.java:143), — BrowserProvider2.updateBookmarksInTransaction( BrowserProvider2.java:1828), — SQLiteContentProvider.update(SQLiteContentProvider.java:154), — android.net.LocalServerSocket.close(): — com.android.internal.os.ZygoteInit.closeServerSocket(ZygoteInit.java:196), — android.os.PowerManager.isScreenOn(): — android.view.ViewRootImpl.<init>(ViewRootImpl.java:403), — BrowserActivity .shouldIgnoreIntents(BrowserActivity.java:127), — android.net.LocalSocket.close(): — com.android.internal.os.ZygoteConnection .closeSocket(ZygoteConnection.java:271), Z wymienionych metod zostana˛ przetestowane wszystkie za wyjatkiem ˛ trzech ostatnich, których znaczenie jest znikome, a o czym wspominano przy okazji badania innych aplikacji 90 5.5. Android Browser 5.5.2. Badania metod wywoływanych z jednego miejsca android.webkit.WebView.saveState(android.os.Bundle) Metode˛ przygotowano aby zwracała pusty obiekt null. Powoduje to, że lista poprzednich stron nie jest zapamietywana ˛ po wyjściu z aplikacji. Informacja ta jest logowana jednak użytkownik, który w konsekwencji traci informacje˛ o ostatnio przegladanych ˛ stronach w danej karcie, nie jest powiadamiany w sposób przyst˛epny. Jest to bład ˛ kategorii 5. android.webkit.WebView.canGoBack() oraz android.webkit.WebView.canGoForward() Badanie tych metod nie może być przeprowadzone w sposób satysfakcjonujacy. ˛ Każda z nich zwraca wartość logiczna. ˛ Nie możemy wpłynać ˛ na obiekty przechowywane w aplikacji. Jeśli wiec ˛ poinformujemy program o możliwości wykonania operacji ’wstecz’ i nastapi ˛ bład, ˛ to jest on uzasadniony i trudno doszukać sie˛ w nim bł˛edu. Analogicznie działa to w przypadku operacji ’w przód’. Zaniechano testów tych metod. android.location.LocationManager.requestLocationUpdates( java.lang.String,long,float,android.location.LocationListener) ˛ za pomoca˛ dwóch wyjatków: ˛ Metoda da może sygnalizować bład IllegalArgumentException oraz SecurityException. System przygotowano tak aby wymuszać wspomniane sytuacje krytyczne. W każdy z tych przypadków aplikacja funkcjonowała normalnie i nie zaobserwowano żadnych problemów w pracy. Wnioskujac ˛ jednak po jej przeznaczeniu, odpowiada ona ze zarejestrowanie obiektu reagujacego ˛ na reakcje˛ zmiany lokalizacji. Być może gdyby któraś strona chciała wykorzystywać taka˛ funkcjonalność udałoby sie˛ to zauważyć. android.location.LocationManager.removeUpdates( android.location.LocationListener) Metoda, w przypadku błe˛ du, rzuca wyjatek ˛ IllegalArgumentException. Podczas badań aplikacja wyłaczała ˛ sie˛ w trakcie ładowania strony, który prosiła o dost˛ep do lokalizacji. Jest to bład ˛ kategorii 6. 5.5.3. Badania metod wywoływanych z wielu miejsc android.database.sqlite.SQLiteOpenHelper.getReadableDatabase() Zgodnie z dokumentacja˛ metoda ta może android.xdatabase.sqlite.SQLiteException. kończyć sie˛ Scenariusz Przygotowanie testu Numer Krok kroku Oczekiwany rezultat 1 Ekran główny aplikacji Uruchomienie aplikacji wyjatkiem ˛ 91 5.5. Android Browser 2 Wyświetlić historie˛ przegladania ˛ Wyświetla sie˛ historia przeglada˛ (Menu - Bookmarks - History) nych stron Tablica 5.17: Scenariusz badań dla metody SQLiteOpenHelper.getReadableDatabase() Analiza wyników Łacznie ˛ przeprowadzono 90 testów - po 30 dla każdej wartości prawdopodobieństwa: 0,1, 0,25, 0,5. Tabela 5.5.3 oraz wykres z rys. 5.31 prezentuja˛ zależności czasowe w wykonaniu wzorcowym. Numer Czas[s] wywołania Miejsca wołania metody Wszystkie metody, klasy com.android.browser 1 oraz pakiety pochodza˛ z paczki AutoFillProfileDatabase.getDatabase( 0.0 AutoFillProfileDatabase.java:95) 2 - 11 0,626 - provider.BrowserProvider2.query(BrowserProvider2.java:879) 13,287 12 13,437 provider.SnapshotProvider.getReadableDatabase( SnapshotProvider.java:147) 13 16 - 14,086 14,156 provider.BrowserProvider2.query(BrowserProvider2.java:879) Tablica 5.18: Zależności czasowe oraz miejsca wywołań testowanej metody SQLiteOpenHelper.getReadableDatabase() dla wykonania wzorcowego 5.5. Android Browser 92 Rysunek 5.31. Zależności czasowe poszczególnych wywołań metody SQLiteOpenHelper.getReadableDatabase() w wykonaniu wzorcowym Miejsca wywołań z wykonania wzorcowego pozwalaja˛ stwierdzić, że przedstawiony scenariusz pokrywa wykonania metody z rozpoznania w 100%. Przed rozpocze˛ ciem analizy, należy zaznaczyć, że ostatnie badanie dla wartości prawdopodobieństwa 0,1 zostało wykluczone i uznane za anomalie, ˛ gdyż testowana metoda została wykonana ponad 250 razy. Nie jest to z pewnościa˛ sytuacja normalna i mogła wynikać z błe˛ du w procedurze badawczej. Badana metoda została wywołana 520 razy. Zmodyfikowany kod wstrzyknieto ˛ w 114 przypadkach i za każdym razem powodowało to wyłaczenie ˛ aplikacji. Obserwujemy wie˛ c wyłacznie ˛ błedy ˛ z kategorii 6. Wykresy na rys. 5.32 oraz 5.33 jak również dokładna analiza badań zawartych w dodatku, pozwalaja˛ sadzić, ˛ że znaczaca ˛ cze˛ ść wywołań miała na miejsce w sekwencji startowej badanej aplikacji, co z pewnościa˛ powodowało jej czeste ˛ krytyczne zakończenie. Niemniej jednak, w żadnym przypadku nie zaobserwowano poprawnej obsługi. 5.5. Android Browser 93 Rysunek 5.32. Liczba testów w poszczególnych kategoriach błedów ˛ w zależności od numeru iteracji zakłócanej metody SQLiteOpenHelper.getReadableDatabase() Rysunek riach w 5.33. Liczba Liczba testów w poszczególnych zależności od miejsca wywołania zakłócanej SQLiteOpenHelper.getReadableDatabase() kategometody android.database.sqlite.SQLiteOpenHelper.getWritableDatabase() Podobnie jak wyżej testowana metoda, metoda ta może sygnalizować bład ˛ tym samym wyjatkiem, ˛ a wie˛ c android.database.sqlite.SQLiteException. 94 5.5. Android Browser Scenariusz Przygotowanie testu Wymagane jest połaczenie ˛ z internetem. Numer Krok kroku Oczekiwany rezultat 1 Uruchomienie aplikacji Ekran główny aplikacji 2 Załadowanie dowolnej strony Zniknał ˛ pasek postepu ˛ co świadczy o całkowitym załadowaniu strony 3 Dodajemy strone˛ do zakładek Komunikat o poprawnym dodaniu (Menu - Save to bookmarks - Ok) strony do zakładek 4 Przechodzimy do zakładek i usu- Komunikat o poprawnym usunie˛ wamy wybrana˛ zakładke˛ (Menu - ciu zakładki Bookmarks - Długie przytrzymanie na zakładce - Delete bookmark Ok) 5 Przyciskiem wstecz wracamy do Załadowana wcześniej strona ekranu głównego 6 Zapisujemy strone˛ do przegladania ˛ Lista zapisanych stron (co najoffline (Menu - Save for offline re- mniej jedna pozycja - aktualnie zaading) pisana strona) 7 Usuwamy zapisana˛ strone˛ (Długie Strona została usunieta ˛ z listy przytrzymanie na zapisanej stronie - Delete saved page) Tablica 5.19: Scenariusz badań dla metody SQLiteOpenHelper.getWritableDatabase() Analiza wyników W ramach badań przeprowadzono 90 testów po 30 badań z różnymi wartościami prawdopodobieństwa błe˛ du (0,1; 0,25 oraz 0,5). W tabeli 5.5.3 oraz na wykresie z rys. 5.31 wykazano zależności czasowe miedzy ˛ poszczególnymi wywołaniami badanej metody. Numer Czas[s] wywołania Miejsca wołania metody Wszystkie metoda, klasy oraz com.android.browser.provider pakiety pochodza˛ z paczki 5.5. Android Browser 1 0,0 2 0,547 95 SQLiteContentProvider.delete(SQLiteContentProvider.java:178) BrowserProvider2.deleteInTransaction( BrowserProvider2.java:1226) 3 1,99 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 4 2,362 BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 5 2,745 BrowserProvider2.updateHistoryInTransaction( BrowserProvider2.java:1965) 6 4,223 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 7 4,445 8 5,195 BrowserProvider2.pruneImages(BrowserProvider2.java:2067) BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 9 5,597 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 10 5,764 11 5,98 BrowserProvider2.pruneImages(BrowserProvider2.java:2067) SQLiteContentProvider.update( SQLiteContentProvider.java:154) 12 6,486 BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 13 7,698 14 8,303 BrowserProvider2.pruneImages(BrowserProvider2.java:2067) BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 15 11,569 16 12,214 SQLiteContentProvider.insert(SQLiteContentProvider.java:112) SQLiteContentProvider.update( SQLiteContentProvider.java:154) 17 20 - 12,715 14,307 BrowserProvider2.updateHistoryInTransaction( BrowserProvider2.java:1965) 5.5. Android Browser 21 14,611 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 22 15,769 BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 23 17,775 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 24 19,736 BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 25 20,693 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 26 21,508 BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 27 21,781 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 28 22,046 BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 29 22,098 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 30 22,455 BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 31 22,578 SQLiteContentProvider.update( SQLiteContentProvider.java:154) 32 22,64 BrowserProvider2.updateInTransaction( BrowserProvider2.java:1619) 33 24,929 SQLiteContentProvider.delete( SQLiteContentProvider.java:178) 34 24,937 BrowserProvider2.deleteInTransaction( BrowserProvider2.java:1226) 35 25,018 BrowserProvider2.deleteBookmarks( BrowserProvider2.java:1211) 96 5.5. Android Browser 36 25,065 97 BrowserProvider2.updateBookmarksInTransaction( BrowserProvider2.java:1828) 37 25,13 38 33,439 BrowserProvider2.pruneImages(BrowserProvider2.java:2067) SnapshotProvider.getWritableDatabase( SnapshotProvider.java:143) 39 41,84 SnapshotProvider.getWritableDatabase( SnapshotProvider.java:143) Tablica 5.20: Zależności czasowe oraz miejsca wywołań testowanej metody SQLiteOpenHelper.getWritableDatabase() dla wykonania wzorcowego Rysunek 5.34. Zależności czasowe poszczególnych wywołań metody SQLiteOpenHelper.getWritableDatabase() w wykonaniu wzorcowym Miejsca wyznaczone podczas rozpoznania, zostały pokryte w całości przez opracowany scenariusz. Badana metoda została wywołana 537 razy, z czego sytuacje˛ krytyczna˛ wymuszono w 108 przypadkach. W każdym z nich aplikacja nie reagowała poprawnie - naste˛ powało wyłaczenie ˛ aplikacji (bład ˛ kategorii 6). Podobnie jak w przypadku poprzedniej metody, zakończenie działania nastepowało ˛ w poczatkowej ˛ fazie użytkowania aplikacji. Jest ona bardzo czesto ˛ wykorzystywana i być może należałoby poszukać możliwości optymalizacyjnych w kodzie programu. Na wykresach 5.5. Android Browser 98 z rys. 5.35 oraz 5.36 przedstawiono dane dotyczace ˛ kategorii błedów ˛ w zależności od numeru iteracji i miejsca wywołania. Rysunek 5.35. Liczba testów w poszczególnych kategoriach w zależności od numeru wywołania zakłócanej metody SQLiteOpenHelper.getWritableDatabase() Rysunek 5.36. Liczba testów w poszczególnych kategoriach w zależności od miejsca wywołania zakłócanej metody SQLiteOpenHelper.getWritableDatabase() 6. Podsumowanie Głównym celem niniejszej pracy było stworzenie oprogramowania umożliwiaja˛ cego wygodne ingerowanie i wymuszanie sytuacji krytycznych w systemie Android. Zarówno dostarczone programy jak również modyfikacje źródeł systemu realizuja˛ założenia koncepcyjne, a przedstawione przykłady oraz badania pokazuja˛ jego przydatność i możliwości. Zarówno podczas tworzenia jak i użytkowania systemu dostrzeżono możliwości jego dalszego rozwoju oraz rozszerzenia funkcjonalności. Najważniejsza˛ z nich mogłaby być opcja umożliwiajaca ˛ warunkowe przecia˛żanie wybranych funkcji. Dokładniej, należałoby uzależnić wprowadzanie zakłóceń w zależności od poprzednich wywołań co umożliwiłoby ścisła˛ kontrole˛ ścieżki wywołania i realizacje˛ złożonych scenariuszy zakłóceń np. metoda stop byłaby modyfikowana tylko wtedy gdy wcześniej wykonano metode˛ start. Dodatkowo, system AFIS mógłby umożliwiać reagowanie na zdarzenia z systemu Android i od niego uzależniać swoje działanie. Być może udałoby sie˛ również zmienić identyfikacje˛ aplikacji, dla której stosujemy zmodyfikowany kod, gdyż numer procesu zmienia si˛e z każdym uruchomieniem programu i konieczne jest dostosowywanie konfiguracji albo stosowanie opcji wywołania dla numerów pid wiekszych ˛ niż podany, co jednak bywa ryzykowne gdyż wówczas opcje stosowane sa˛ dla każdego kolejno uruchamianego programu. Moduł AFIS Desktop Manager mógłby zostać rozszerzony o szereg funkcji ułatwiajacych ˛ konfigurowanie systemu. Przede wszystkim widok funkcji zostałby rozbudowany o wyszukiwarke˛ metod. Kolejna˛ zmiana˛ byłoby wprowadzenie drugiego widoku, który umożliwiałby wprowadzenie konfiguracji, a nastepnie ˛ wybór funkcji, dla których zostanie ona wprowadzona, co przyspieszyłoby obsługe˛ w ramach jednej aplikacji. Wysyłanie plików mogłoby odbywać sie˛ w sposób zautomatyzowany (np. po uaktualnieniu albo zapisaniu zmian) oraz za pomoca˛ jednego przycisku. Program analizatora AFIS Desktop Analyzer należy zmodyfikować tak, aby jedna analiza mogła zawierać wiele logów. Mimo, że nie jest dużym problemem wybieranie pliku do poszczególnych analiz, to jednak ułatwiałoby to utrzymanie porzadku ˛ w plikach. Aplikacja uruchamiana bezpośrednio na systemie Android - AFIS Android Manager - mogłaby okazać sie˛ bardziej pomocna gdyby zaimplementowano w niej funkcjonalność jej odpowiednika na komputery osobiste. Równie ważnym elementem pracy były przeprowadzone badania. Sumarycznie wykonano 990 testów, w ramach których przecia˛żane metody wywołane zostały 11080 razy, a ich działanie zakłócono w 2208 przypadkach. Średnio na jeden test poświe˛ cono około 2 minut. Wykres z rys. 6.1 prezentuje procentowy rozkład testów, które zakończyły sie˛ błe˛ dem danej kategorii uwzgledniaj ˛ ac ˛ wszystkie badania. Wynika z niego jasno, że najcześciej ˛ wstrzykiwane błedy ˛ powodowały wyłaczenie ˛ aplikacji oraz inne niepożadane ˛ efekty. Najlepsza˛ z testowanych aplikacji jest Google Music, która dzieki ˛ oddzieleniu widoku oraz modelu do różnych watków ˛ jest niezwykle odporna na błedy. ˛ Każdy z 6. Podsumowanie 100 Rysunek 6.1. Procentowy rozkład wymuszonych błedów ˛ w zależności od kategorii badanych programów nie obsługiwał poprawnie wyjatku ˛ SQLiteException rzucanego przez funkcje getReadableDatabase oraz getWritableDatabase. Zazwyczaj powodował on sytuacje krytyczne oraz bardzo czesto ˛ prowadził do wymuszenia zamknie˛ cia aplikacji. Testy doskonale pokazuja, ˛ że pomimo iż badano renomowane aplikacje nie ustrzegły sie˛ one błedów. ˛ Należy również uwzglednić ˛ fakt, że aplikacje te zostały już przetestowane w procesie wytwarzania oprogramowania, co świadczy o dużym potencjale stworzonego Android Fault Injection System. Bibliografia [1] Android 4.2-Gate: west Release, Here Are Some Of The Major Issues Plaguing Google’s Ne- 12.09.2013. http://www.androidpolice.com/2012/11/19/ android-4-2-gate-here-are-some-of-the-major-issues-plaguing-googles\ -newest-release/. [2] Android Mock - A Mocking Framework for the Dalvik VM, 12.09.2013. http://code. google.com/p/android-mock/. [3] Android Open Source Project, 12.09.2013. http://source.android.com. [4] Dokumentacja dla deweloperów systemu Android, 12.09.2013. http://developer. android.com/reference/packages.html. [5] Eric per Schmidt: day, Google now 12.09.2013. at 1.5 million Android activations http://www.engadget.com/2013/04/16/ eric-schmidt-google-now-at-1-5-million-android-activations-per/. [6] FindBugs - Find Bugs in Java Programs, 12.09.2013. http://findbugs. sourceforge.net. [7] Google Play hits 25 billion downloads, 12.09.2013. http://officialandroid. blogspot.com/2012/09/google-play-hits-25-billion-downloads.html. [8] JUnit. A programmer-oriented testing framework for Java, 12.09.2013. http:// junit.org/. [9] Robolectric: Unit Test your Android Application, 12.09.2013. http://pivotal. github.io/robolectric/. [10] Sureassert. An integrated Java unit testing solution for Eclipse, 12.09.2013. http: //www.sureassert.com/. [11] The History of Android, 12.09.2013. http://www.historyofandroid.com/. [12] Using NDK for Performance: Dalvik vs. Native, 12.09.2013. https://thenewcircle. com/s/post/96/using_ndk_for_performance_dalvik_versus_native. [13] Worldwide q1, Smartphone 12.09.2013. OS Market Share, 2012 q1 - 2013 http://www.icharts.net/chartchannel/ worldwide-smartphone-os-share-2012-q1-2013-q1_m3zryyngc. 102 Bibliografia [14] Android Operating System Statistics, 13.09.2013. http://www.appbrain.com/ stats. [15] Kumar Maji A., Kangli Hao, Bagchi S., Sultana S. Characterizing Failures in Mobile OSes: A Case Study with Android and Symbian. Software Reliability Engineering (ISSRE), 2010 IEEE 21st International Symposium on, vol., no., pp.249,258, 1-4 Nov. 2010. [16] Piotr Gawkowski. Kierunki rozwoju systemów programowej symulacji błedów. ˛ Raport Instytutowy, Instytut Informatyki, Politechnika Warszawska, 2009. [17] Piotr Gawkowski, Mariusz Markowski, Grzegorz Smulko, Łukasz Karolewski. Fault injection techniques towards software quality assessment. w: Information Systems in Management XVI: Modern ICT for Evaluation of Business Information Systems / Piotr Jałowiecki, Piotr Łukasiewicz, Arkadiusz Orłowski ( eds. ), 2012, SGGW, pp. 17-28. [18] Piotr Gawkowski, Przemysław Pawełczyk, Janusz Sosnowski, Krzysztof Cabaj, Marcin Gajda. LRFI – Fault Injection Tool for Testing Mobile Software. w: Emerging Intelligent Technologies in Industry / Ryżko Dominik Paweł [et al.] ( eds. ), Studies in Computational Intelligence, vol. 369, 2011, Springer, pp. 269-282. [19] Cliff Jones, Brian Randell. Dependable Pervasive Systems. Technical Report Series CS-TR-839, University of Newcastle upon Tyne, 2004. [20] Cinque M. Enabling On-Line Dependability Assessment of Android Smart Phones. Dependable Systems and Networks Workshops (DSN-W), 2011 IEEE/IFIP 41st International Conference on , vol., no., pp.286,291, 27-30 June 2011. [21] Lars Vogel. Android application testing with the Android test framework. 2013. http: //www.vogella.com/articles/AndroidTesting/article.html. [22] Karolewski Łukasz, Smulko Grzegorz. Praca magisterska: Środowisko testów aplikacji systemu Windows ze szczególnym uwzglednieniem ˛ platformy .NET. Instytut Informatyki, Politechnika Warszawska, 2010. A. Zawartość płyty CD Ścieżka Opis doc Dokumenty zwiazane ˛ z praca˛ doc/PracaDyplomowa.pdf Treść pracy dyplomowej doc/ModifiedFunctions.ods Lista metod (wraz z opisem) przecia˛żonych przez system AFIS doc/csv_to_xml.py Skrypt do konwersji pliku csv na xml (dla programów systemu AFIS) doc/SzczegółoweWynikiBadań.pdf Załacznik ˛ do pracy zawierajacy ˛ szczegółowe wyniki badań src Zawiera kody źródłowe systemu src/AFISAndroidManager Kod źródłowy aplikacji AFIS Android Manager dla systemu Android src/AFISAndroidManager/ AFISAndroidManager.apk Paczka instalacyjna aplikacji AFIS Android Manager dla systemu Android src/AFISAndroidManager/doc Dokumentacja kodu Android Manager src/AFISDesktopAnalyzer Kod źródłowy aplikacji AFIS Desktop Analyzer src/AFISDesktopAnalyzer/doc Dokumentacja kodu źródłowego aplikacji AFIS Desktop Analyzer src/AFISDesktopManager Kod źródłowy aplikacji AFIS Desktop Manager src/AFISDesktopManager/doc Dokumentacja kodu źródłowego aplikacji AFIS Desktop Manager src/afiscore Zawiera kody źródłowe modułu AFIS Core oraz skrypt do automatycznej modyfikacji źródeł Tablica A.1: Zawartość płyty CD aplikacji AFIS