12

Ich habe eine App, die, wenn durch eine ContentObserver einer Änderung an eine ContentProvider gemeldet, versucht, den Anbieter auf einem Hintergrund Thread abzufragen. Dies bewirkt, dass ein SecurityException geworfen werden:Wie würde ein von einer App erstellter Thread als eine andere App als der ContentProvider der App angesehen?

 
8-10 15:54:29.577 3057-3200/com.xxxx.mobile.android.xxx W/Binder﹕ Caught a RuntimeException from the binder stub implementation. 
    java.lang.SecurityException: Permission Denial: reading com.xxx.mobile.android.mdk.model.customer.ContentProvider uri content://com.xxx.mobile.android.consumer.xxx/vehicle from pid=0, uid=1000 requires the provider be exported, or grantUriPermission() 
at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:539) 
      at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:452) 
      at android.content.ContentProvider$Transport.query(ContentProvider.java:205) 
      at android.content.ContentResolver.query(ContentResolver.java:478) 
      at android.content.ContentResolver.query(ContentResolver.java:422) 

Wie würde ein Faden durch eine App mit einer anderen UID aus der Contentprovider App am Ende erstellt?

eine Ausnahme Haltepunkt in android.content.ContentProvider Indem ich sehe, dass UserHandle.isSameApp(uid, mMyUid) ist false und UserHandle.isSameUser(uid, mMyUid)true ist. Ich sehe auch, dass die Provider-UID 10087 ist.

+0

Fragen Sie nach uid = 1000 - das ist die Benutzer-ID des Android-Systems. Es ist wahrscheinlich, dass die Anforderung intern an das System zur Verarbeitung weitergeleitet wird. – adelphus

+0

@adelphus Ja. Ich dachte, das sei der Grund für die Sicherheitsausnahme, aber jetzt bin ich mir nicht sicher, weil 'UserHandle.isSameUser'' true' zurückgibt. –

+0

Android-Benutzer sind nicht mit App-uid-Werten verbunden. Verwechsle sie nicht! App UID-Werte werden verwendet, um Sandboxing zwischen Apps zu erzwingen, Benutzersicherheit wird anders implementiert. – adelphus

Antwort

1

Ich habe das gleiche Problem beim Versuch, mit meinem ContentProvider in einem Systemrückruf (LeScanCallback) zu interagieren. Das Problem ist, dass der Callback-Thread dem Android-System gehört und nicht von meiner App, selbst wenn der Code in meiner App ist.

Die Übergabe der Arbeit vom Rückruf an einen meiner App-Threads vor dem Versuch, mit meinem ContentProvider zu interagieren, hat das Problem erfolgreich gelöst.

Um die Standardwerte für die Erstellung und Wiederverwendung von Threads zu reduzieren (für häufige Rückrufe erforderlich, um den Verwaltungsaufwand zu reduzieren), verwendete ich AndroidAnnotation's @Background annotation für meine Delegate-Methode.

5

Der UID-Wert von 1000 gehört zum Android-System. Bei vielen Funktionen von Android werden Anforderungen an den Systemthread zur Verarbeitung weitergeleitet. Wenn währenddessen eine Ausnahme ausgelöst wird, enthält der Fehler die uid des Systems und nicht den ursprünglichen Anforderer.

Für die anderen Punkte:

UserHandle.isSameApp(uid, mMyUid) is false

UserHandle.isSameUser(uid, mMyUid) is true

Diese sind am einfachsten, indem man die source zu erklären. Auf einem Android-Gerät mit Unterstützung für mehrere Benutzer wird jeder Benutzer durch eine Reihe von UIDs definiert. isSameApp ist falsch, weil die Modul des IDs nicht übereinstimmen:

public static final boolean isSameApp(int uid1, int uid2) { 
     return getAppId(uid1) == getAppId(uid2); 
} 

public static final int getAppId(int uid) { 
     return uid % PER_USER_RANGE; 
} 

ähnlich ist die beiden IDs zu demselben Benutzer gehören, weil sie im gleichen Bereich leben:

public static final boolean isSameUser(int uid1, int uid2) { 
     return getUserId(uid1) == getUserId(uid2); 
} 

public static final int getUserId(int uid) { 
     if (MU_ENABLED) { 
      return uid/PER_USER_RANGE; 
     } else { 
      return 0; 
     } 
} 

Beachten Sie, dass diese Logik ist fehlerhaft, weil es bedeutet, dass alle Android-System-UIDs (< 10000) als "zugehörig" zum ersten Benutzer angenommen werden. Wenn ein zweiter Benutzer mehr als 1000 Apps (!) Installiert, besteht die Möglichkeit, dass eine App mit einer System-App verwechselt wird (beide uid % PER_USER_RANGE geben 1000 zurück). Es wird aber nicht wirklich wichtig sein, denn das starke Sandboxing würde alles verhindern, dass zu schlecht passiert.

+0

Das hilft mir zu verstehen, wie IDs funktionieren. Vielen Dank. Haben Sie einen Vorschlag, wie ich die Sicherheitsausnahme vermeiden könnte, ohne den Inhaltsanbieter für den Zugriff durch andere Apps zu öffnen? –

+0

Der normale Weg zum Schützen von Inhaltsanbietern besteht darin, benutzerdefinierte Berechtigungen zu definieren und einzuschließen [http://stackoverflow.com/questions/14793672/requesting-read-permission-from-my-own-contentprovider-in-an-other- App). Aber ich bin mir nicht ganz sicher, was Sie erreichen wollen, also ist es vielleicht nicht das, was Sie brauchen. – adelphus

+0

Dieser Link scheint nützlich zu sein, um eine App mit dem Inhaltsanbieter eines anderen zu verbinden. Aber in meinem Fall habe ich nur eine App. Und der Inhaltsanbieter dieser App scheint zu glauben, dass ein von der App erstellter Thread von einer anderen App stammt, und löst daher eine Sicherheitsausnahme aus. –

2

Wenn eine Thread von einer beliebigen Komponente der Anwendung gestartet wird, die den Anbieter hat, können Sie auf die ContentProvider ohne SecurityException zugreifen.

Ich verwende eine ContentProvider in meiner Anwendung nur als eine zusätzliche Abstraktionsschicht und ich habe den Inhalt nicht zu anderen Anwendungen ausgesetzt. Ich greife auf die ContentProvider im Hintergrund Thread (Nicht AsyncTask, aber eine einfache java.lang.Thread). Ich bekomme keine SecurityException. Das Folgende ist der Code aus meiner Anwendung.

AndroidManifest.xml

<provider 
    android:authorities="com.sample.provider" 
    android:name="com.sample.MyProvider" 
    android:exported="false" /> 

MainActivity

public void performContinue(Bundle extras){ 
    Thread thread = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      String AUTHORITY = "com.sample.provider"; 
      Uri BASE_URI = Uri.parse("content://" + AUTHORITY); 
      Uri currentUri = BASE_URI.buildUpon().appendPath("SAMPLE_COUNT").build(); 
      final Cursor query = InputActivity.this.getContentResolver().query(currentUri, null, null, null, null); 
      if (query != null) { 
       final int count = query.getCount(); 
       Log.d("DEBUG","CONTENT = " + count); 
      }else{ 
       Log.d("DEBUG","CONTENT = CURSOR NULL"); 
      } 
     } 
    }); 
    thread.setName("THREAD_1"); 
    thread.start(); 
} 


Ich scheine keine SecurityException zu bekommen. Idealerweise müssen wir AsyncQueryHandler für den Zugriff auf die ContentProvider verwenden, da Sie damit den gesamten Abholprozess im Hintergrundthread durchführen können und den UI-Thread verwenden werden, um die Ergebnisse in der Benutzeroberfläche zu veröffentlichen. Aber nachdem ich diesen Beitrag gesehen hatte, wollte ich nur sehen, ob ich einfach Thread verwenden konnte und prüfen, ob ich immer noch ohne Ausnahme darauf zugreifen konnte. Es funktioniert gut.

Verwandte Themen