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

Podobne dokumenty