Die folgende Übung zeigt die Verwendung von Berechtigungen unter Android, das Fehlerverhalten im Fall einer fehlenden Berechtigung sowie die Möglichkeiten zur Fehleranalyse nachdem eine App abgestürzt ist.

Berechtigungen erlauben einer App den Zugriff auf verschiedene Systemkomponenten (wie z.B. Zugriff auf die Kamera, SMS, Internet, etc.). Die von der App benötigten Berechtigungen werden in der Datei AndroidManifest.xml angegeben. Vor der Installation einer App wird der Benutzer über die von der App verlangten Berechtigungen gewarnt, weswegen nur die Berechtigungen angegeben werden sollten, die auch tatsächlich benötigt werden.
Wenn eine App eine für den Zugriff auf eine Komponente notwendige Berechtigung nicht gesetzt hat, führt dies zu einer Fehlermeldung und häufig zu einer Exception und infolgedessen zum Absturz der App. Hierzu folgt nun ein kurzes Beispiel:

Beispiel: Absturz bei fehlender Berechtigung

  1. Wir starten mit dem Erstellen eines neuen Android Projektes mit mit dem Namen Permissions und einem Activity vom Typ Empty Activity.
  2. Als nächstes weisen Sie bitte der Hello World TextView in res/layout/activity_main.xml die id textView1 zu.
  3. Fügen Sie nun den im folgenden Beispielcode markierten Bereich zum Abfragen des Netzwerkstatus zur Methode onCreate() der Klasse MainActivity.java hinzu:
    
    package com.individuapp.permissions;
    
    import android.app.Activity;
    import android.content.Context;
    import android.net.ConnectivityManager;
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class MainActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		
    		ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    		TextView textView = (TextView) findViewById(R.id.textView1);
    		boolean isWifiConnected = conMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected();
    		textView.setText("Netzwerk verbunden: "+isWifiConnected);
    	}
    }
    
  4. Programmabsturz bei fehlender Android BerechtigungWird die App nun ausgeführt, erscheint eine Fehlermeldung wie in der Abbildung rechts und die App wird beendet. Nach einem kurzen Blick in die Logcat-Ausgabe finden wir dort folgende Meldung, welche uns über das Fehlen der Berechtigung ACCESS_NETWORK_STATE informiert:
     
    07-31 20:49:42.548: E/AndroidRuntime(24712): java.lang.RuntimeException: 
    Unable to start activity ComponentInfo{com.individuapp.permissions/com.individuapp.permissions.MainActivity}: 
    java.lang.SecurityException: ConnectivityService: Neither user 10099 nor current process has android.permission.ACCESS_NETWORK_STATE.
    
  5. Zum Beheben des Fehlers muss nun noch die Berechtigung ACCESS_NETWORK_STATE, wie in folgendem Beispiel auf Zeile 11, im Android Manifest angegeben werden.
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.individuapp.permissions"
        android:versionCode="1"
        android:versionName="1.0" >
     
        <uses-sdk
            android:minSdkVersion="14"
            android:targetSdkVersion="21" />
     
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
     
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
     
    </manifest>
    
  6. Wird die App nun gestartet, lässt sie sich ohne Probleme ausführen und zeigt den WIFI Verbindungszustand.

Debugging

Nach einem Programmabsturz erscheint im Geräteprotokoll ein Stacktrace, aus dem die Reihenfolge der aufgerufenen Methoden, die zum Absturtz geführt haben, ersichtlich ist.
Wenn zum Zeitpunkt des Absturzes der Debugger mit dem Gerät verbunden ist, erscheint die Ausgabe außerdem in der Logcat Ansicht von Eclipse.

Über die Methoden der Klasse Log kann zu jedem beliebigen Zeitpunkt eine Nachricht in das Geräteprotokoll geschrieben werden:

Log.e("TAG", "This is an error message");
Log.w("TAG", "This is a warning message");
Log.i("TAG", "This is an info message");
Log.d("TAG", "This is a debug message"); 

Im ersten Parameter wird der Name der App übergeben, wodurch die Ausgabe von Protokolleinträgen einfach auf einzelne Apps beschränkt werden kann. Der zweite Parameter enthält die auszugebende Nachricht.

Eine weitere nützliche Methode wird von der Klasse Thread zur Verfügung gestellt und ermöglicht die Ausgabe eines Stackttrace:

Thread.dumpStack();

Auslesen des Geräteprotokolls mittels adb.exe

Das Geräteprotokoll kann über das Kommandozeilenprogramm adb.exe (Android Debug Bridge) ausgelesen werden. adb.exe befindet sich im Verzeichnis <AndroidSDK>/platform-tools. Zum Auslesen des Geräteprotokolls eine Kommandozeile öffnen, in das Verzeichnis <AndroidSDK>/platform-tools wechseln und den folgenden Befehl ausführen:

adb logcat

Hierzu müssen sowohl die Entwickleroptionen sowie USB-Debugging aktiviert sein und das Gerät über USB mit dem Computer verbunden sein.

Die Ausgabe von adb logcat kann auf einzelne Programme begrenzt werden:

adb logcat MyApp:D *:S

MyApp:D gibt die Geräteprotokolleinträge ab der Log-Priorität Debug des Programms MyApp aus. Folgende Log-Prioritäten stehen zur Verfügung:

  • V – Verbose (niedrigste Priorität)
  • D – Debug
  • I – Info (default)
  • W – Warning
  • E – Error
  • F – Fatal
  • S – Silent (höchste Priorität, es wird nichts ausgegeben)

Die Option *:S verhindert die Ausgabe von Geräteprotokolleinträgen aller Apps mit Ausnahme der explizit angegebenen, wodurch die Ausgabe auf Logmeldungen einzelner Apps begrenzt werden kann. Beispiel:

adb logcat ActivityManager:I MyApp:D *:S