java.lang.SecurityException:Permission Denial:reading

时间:2014-08-20 06:37:25

标签: android android-contentprovider

我有App A有内容提供商,它工作正常。 代码是:

public class StudentsProvider extends ContentProvider {

static final String PROVIDER_NAME = "com.example.mycontentprovider";
static final String URL = "content://" + PROVIDER_NAME + "/students";
static final Uri CONTENT_URI = Uri.parse(URL);

static final String _ID = "_id";
static final String NAME = "name";
static final String GRADE = "grade";

private static HashMap<String, String> STUDENTS_PROJECTION_MAP;

static final int STUDENTS = 1;
static final int STUDENT_ID = 2;

static final UriMatcher uriMatcher;
static{
  uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  uriMatcher.addURI(PROVIDER_NAME, "students", STUDENTS);
  uriMatcher.addURI(PROVIDER_NAME, "students/#", STUDENT_ID);
 }

 /**
* Database specific constant declarations
*/
private SQLiteDatabase db;
static final String DATABASE_NAME = "College";
static final String STUDENTS_TABLE_NAME = "students";
static final int DATABASE_VERSION = 1;
static final String CREATE_DB_TABLE = 
  " CREATE TABLE " + STUDENTS_TABLE_NAME +
  " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " + 
  " name TEXT NOT NULL, " +
  " grade TEXT NOT NULL);";

/**
* Helper class that actually creates and manages 
* the provider's underlying data repository.
 */
  private static class DatabaseHelper extends SQLiteOpenHelper {
   DatabaseHelper(Context context){
      super(context, DATABASE_NAME, null, DATABASE_VERSION);
   }

   @Override
   public void onCreate(SQLiteDatabase db)
   {
      db.execSQL(CREATE_DB_TABLE);
   }

   @Override
   public void onUpgrade(SQLiteDatabase db, int oldVersion, 
                         int newVersion) {
      db.execSQL("DROP TABLE IF EXISTS " +  STUDENTS_TABLE_NAME);
      onCreate(db);
   }
 }

 @Override
 public boolean onCreate() {
  Context context = getContext();
  DatabaseHelper dbHelper = new DatabaseHelper(context);
  /**
   * Create a write able database which will trigger its 
   * creation if it doesn't already exist.
   */
  db = dbHelper.getWritableDatabase();
  return (db == null)? false:true;
 }

 @Override
 public Uri insert(Uri uri, ContentValues values) {
  /**
   * Add a new student record
   */
  long rowID = db.insert(   STUDENTS_TABLE_NAME, "", values);
  /** 
   * If record is added successfully
   */
  if (rowID > 0)
  {
     Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID);
     getContext().getContentResolver().notifyChange(_uri, null);
     return _uri;
  }
  throw new SQLException("Failed to add a record into " + uri);
 }

 @Override
 public Cursor query(Uri uri, String[] projection, String selection,    
                   String[] selectionArgs, String sortOrder) {

  SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
  qb.setTables(STUDENTS_TABLE_NAME);

  switch (uriMatcher.match(uri)) {
  case STUDENTS:
     qb.setProjectionMap(STUDENTS_PROJECTION_MAP);
     break;
  case STUDENT_ID:
     qb.appendWhere( _ID + "=" + uri.getPathSegments().get(1));
     break;
  default:
     throw new IllegalArgumentException("Unknown URI " + uri);
  }
  if (sortOrder == null || sortOrder == ""){
     /** 
      * By default sort on student names
      */
     sortOrder = NAME;
  }
  Cursor c = qb.query(db,   projection, selection, selectionArgs, 
                      null, null, sortOrder);
  /** 
   * register to watch a content URI for changes
   */
  c.setNotificationUri(getContext().getContentResolver(), uri);

  return c;
  }

  @Override
  public int delete(Uri uri, String selection, String[] selectionArgs) {
  int count = 0;

  switch (uriMatcher.match(uri)){
  case STUDENTS:
     count = db.delete(STUDENTS_TABLE_NAME, selection, selectionArgs);
     break;
  case STUDENT_ID:
     String id = uri.getPathSegments().get(1);
     count = db.delete( STUDENTS_TABLE_NAME, _ID +  " = " + id + 
            (!TextUtils.isEmpty(selection) ? " AND (" + 
            selection + ')' : ""), selectionArgs);
     break;
  default: 
     throw new IllegalArgumentException("Unknown URI " + uri);
  }

  getContext().getContentResolver().notifyChange(uri, null);
  return count;
 }

 @Override
 public int update(Uri uri, ContentValues values, String selection, 
                 String[] selectionArgs) {
  int count = 0;

  switch (uriMatcher.match(uri)){
  case STUDENTS:
     count = db.update(STUDENTS_TABLE_NAME, values, 
             selection, selectionArgs);
     break;
  case STUDENT_ID:
     count = db.update(STUDENTS_TABLE_NAME, values, _ID + 
             " = " + uri.getPathSegments().get(1) + 
             (!TextUtils.isEmpty(selection) ? " AND (" +
             selection + ')' : ""), selectionArgs);
     break;
  default: 
     throw new IllegalArgumentException("Unknown URI " + uri );
  }
  getContext().getContentResolver().notifyChange(uri, null);
  return count;
 }

 @Override
 public String getType(Uri uri) {
   switch (uriMatcher.match(uri)){
  /**
   * Get all student records 
   */
  case STUDENTS:
     return "vnd.android.cursor.dir/vnd.example.students";
  /** 
   * Get a particular student
   */
  case STUDENT_ID:
     return "vnd.android.cursor.item/vnd.example.students";
  default:
     throw new IllegalArgumentException("Unsupported URI: " + uri);
  }
 }
 }

App A的清单文件是:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.example.mycontentprovider"
 android:versionCode="1"
 android:versionName="1.0" >

  <uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="17" />

   <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="com.example.mycontentprovider.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>
    <provider android:name="StudentsProvider" 
       android:authorities="com.example.mycontentprovider"
       android:exported="true"
       android:grantUriPermissions="true"
       android:readPermission="com.example.mycontentprovider.permRead"
       >
    </provider>
 </application>

当我尝试在App B中访问此内容提供程序时,我收到以下错误:

08-20 10:55:12.232: I/System.out(2620): Error123 : java.lang.SecurityException:       
Permission Denial: reading com.example.mycontentprovider.StudentsProvider uri   
content://com.example.mycontentprovider/students from pid=2620, uid=10081 requires  
android.permission.permRead, or grantUriPermission()

即使B的清单文件中已有权限。

App B代码是:

 Uri yourURI = Uri.parse("content://com.example.mycontentprovider/students");
 ContentProviderClient yourCR =  getContentResolver().acquireContentProviderClient(yourURI );
 Cursor c =yourCR.query(yourURI, null, null, null, null );               
 Toast.makeText(getApplicationContext(), c.getCount(), Toast.LENGTH_LONG).show(); 

App B的清单文件是:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test33"
android:versionCode="1"
android:versionName="1.0" >

<uses-permission android:name="com.example.mycontentprovider.permRead" />

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="15" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".MainActivity"
        android:label="@string/title_activity_main" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
  </application>
 </manifest>

这里有人可以告诉我这里有什么不对/缺失。

非常感谢。

2 个答案:

答案 0 :(得分:5)

您需要将权限声明为应用程序A.

<permission
    android:name="com.example.mycontentprovider.permRead"
    android:description="@string/permission_desc"
    android:label="@string/permission_label"
    android:protectionLevel="signature" />

并添加

<uses-permission android:name="com.example.mycontentprovider.permRead" />

进入相同的应用程序A。


您需要阅读How to use custom permissions in Android?permission doc

答案 1 :(得分:1)

在App A的AndroidManifest.xml中,provider标签应该是这样的:

   <provider android:name="StudentsProvider" 
   android:authorities="com.example.mycontentprovider"
   android:exported="true">

在这种情况下,访问此类内容提供商不需要特定权限。所以在App B中,这条线变得毫无用处:

   <uses-permission android:name="com.example.mycontentprovider.permRead" />