diff options
8 files changed, 122 insertions, 23 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 347abb3..80bd125 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -10,16 +10,9 @@ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> <uses-permission android:name="android.permission.MANAGE_USERS" /> <uses-permission android:name="android.permission.PROCESS_PHONE_ACCOUNT_REGISTRATION" /> - <uses-permission android:name="android.permission.READ_CONTACTS" /> - <uses-permission android:name="android.permission.READ_PROFILE" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.SEND_CALL_LOG_CHANGE" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> - <uses-permission android:name="android.permission.WRITE_CONTACTS" /> - <uses-permission android:name="android.permission.WRITE_PROFILE" /> - <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> - <uses-permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL" /> - <uses-permission android:name="com.android.voicemail.permission.READ_VOICEMAIL" /> <permission android:name="android.permission.SEND_CALL_LOG_CHANGE" diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java index 5cbca9e..8fce6a6 100644 --- a/src/com/android/providers/contacts/ContactsProvider2.java +++ b/src/com/android/providers/contacts/ContactsProvider2.java @@ -159,6 +159,7 @@ import com.android.providers.contacts.MetadataEntryParser.MetadataEntry; import com.android.providers.contacts.MetadataEntryParser.RawContactInfo; import com.android.providers.contacts.MetadataEntryParser.UsageStats; import com.android.providers.contacts.util.Clock; +import com.android.providers.contacts.util.ContactsPermissions; import com.android.providers.contacts.util.DbQueryUtils; import com.android.providers.contacts.util.NeededForTesting; import com.android.providers.contacts.util.UserUtils; @@ -2214,7 +2215,7 @@ public class ContactsProvider2 extends AbstractContactsProvider response.putParcelable(Authorization.KEY_AUTHORIZED_URI, authUri); return response; } else if (PinnedPositions.UNDEMOTE_METHOD.equals(method)) { - getContext().enforceCallingOrSelfPermission(WRITE_PERMISSION, null); + ContactsPermissions.enforceCallingOrSelfPermission(getContext(), WRITE_PERMISSION); final long id; try { id = Long.valueOf(arg); @@ -2970,8 +2971,8 @@ public class ContactsProvider2 extends AbstractContactsProvider private void enforceSocialStreamReadPermission(Uri uri) { if (SOCIAL_STREAM_URIS.contains(sUriMatcher.match(uri)) && !isValidPreAuthorizedUri(uri)) { - getContext().enforceCallingOrSelfPermission( - "android.permission.READ_SOCIAL_STREAM", null); + ContactsPermissions.enforceCallingOrSelfPermission(getContext(), + "android.permission.READ_SOCIAL_STREAM"); } } @@ -2982,8 +2983,8 @@ public class ContactsProvider2 extends AbstractContactsProvider */ private void enforceSocialStreamWritePermission(Uri uri) { if (SOCIAL_STREAM_URIS.contains(sUriMatcher.match(uri))) { - getContext().enforceCallingOrSelfPermission( - "android.permission.WRITE_SOCIAL_STREAM", null); + ContactsPermissions.enforceCallingOrSelfPermission(getContext(), + "android.permission.WRITE_SOCIAL_STREAM"); } } diff --git a/src/com/android/providers/contacts/ProfileProvider.java b/src/com/android/providers/contacts/ProfileProvider.java index d01195d..ee18a5e 100644 --- a/src/com/android/providers/contacts/ProfileProvider.java +++ b/src/com/android/providers/contacts/ProfileProvider.java @@ -15,6 +15,8 @@ */ package com.android.providers.contacts; +import com.android.providers.contacts.util.ContactsPermissions; + import android.content.ContentValues; import android.content.Context; import android.content.Intent; @@ -51,7 +53,7 @@ public class ProfileProvider extends AbstractContactsProvider { */ public void enforceReadPermission(Uri uri) { if (!mDelegate.isValidPreAuthorizedUri(uri)) { - mDelegate.getContext().enforceCallingOrSelfPermission(READ_PERMISSION, null); + ContactsPermissions.enforceCallingOrSelfPermission(getContext(), READ_PERMISSION); } } @@ -59,7 +61,7 @@ public class ProfileProvider extends AbstractContactsProvider { * Performs a permission check on the write profile permission. */ public void enforceWritePermission() { - mDelegate.getContext().enforceCallingOrSelfPermission(WRITE_PERMISSION, null); + ContactsPermissions.enforceCallingOrSelfPermission(getContext(), WRITE_PERMISSION); } @Override diff --git a/src/com/android/providers/contacts/VoicemailContentProvider.java b/src/com/android/providers/contacts/VoicemailContentProvider.java index ba51b8e..e4f6a05 100644 --- a/src/com/android/providers/contacts/VoicemailContentProvider.java +++ b/src/com/android/providers/contacts/VoicemailContentProvider.java @@ -35,6 +35,7 @@ import android.provider.VoicemailContract.Voicemails; import android.util.Log; import com.android.providers.contacts.ContactsDatabaseHelper.Tables; +import com.android.providers.contacts.util.ContactsPermissions; import com.android.providers.contacts.util.SelectionBuilder; import com.android.providers.contacts.util.TypedUriMatcherImpl; import com.google.common.annotations.VisibleForTesting; @@ -291,8 +292,8 @@ public class VoicemailContentProvider extends ContentProvider private UriData checkPermissionsAndCreateUriDataForRead(Uri uri) { // If the caller has been explicitly granted read permission to this URI then no need to // check further. - if (context().checkCallingUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) - == PackageManager.PERMISSION_GRANTED) { + if (ContactsPermissions.hasCallerUriPermission( + getContext(), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)) { return UriData.createUriData(uri); } diff --git a/src/com/android/providers/contacts/VoicemailPermissions.java b/src/com/android/providers/contacts/VoicemailPermissions.java index e1c9b57..50f2447 100644 --- a/src/com/android/providers/contacts/VoicemailPermissions.java +++ b/src/com/android/providers/contacts/VoicemailPermissions.java @@ -16,8 +16,9 @@ package com.android.providers.contacts; +import com.android.providers.contacts.util.ContactsPermissions; + import android.content.Context; -import android.content.pm.PackageManager; import android.telecom.DefaultDialerManager; /** @@ -105,13 +106,11 @@ public class VoicemailPermissions { /** Determines if the given package has the given permission. */ private boolean packageHasPermission(String packageName, String permission) { - return mContext.getPackageManager().checkPermission(permission, packageName) - == PackageManager.PERMISSION_GRANTED; + return ContactsPermissions.hasPackagePermission(mContext, permission, packageName); } /** Determines if the calling process has the given permission. */ private boolean callerHasPermission(String permission) { - return mContext.checkCallingOrSelfPermission(permission) - == PackageManager.PERMISSION_GRANTED; + return ContactsPermissions.hasCallerOrSelfPermission(mContext, permission); } } diff --git a/src/com/android/providers/contacts/util/ContactsPermissions.java b/src/com/android/providers/contacts/util/ContactsPermissions.java new file mode 100644 index 0000000..6dda50b --- /dev/null +++ b/src/com/android/providers/contacts/util/ContactsPermissions.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.providers.contacts.util; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Binder; +import android.os.Process; +import android.util.Log; + +public class ContactsPermissions { + private static final String TAG = "ContactsPermissions"; + + private static final boolean DEBUG = false; // DO NOT submit with true + + // Normally, we allow calls from self, *except* in unit tests, where we clear this flag + // to emulate calls from other apps. + public static boolean ALLOW_SELF_CALL = true; + + private ContactsPermissions() { + } + + public static boolean hasCallerOrSelfPermission(Context context, String permission) { + boolean ok = false; + + if (ALLOW_SELF_CALL && Binder.getCallingPid() == Process.myPid()) { + ok = true; // Called by self; always allow. + } else { + ok = context.checkCallingOrSelfPermission(permission) + == PackageManager.PERMISSION_GRANTED; + } + if (DEBUG) { + Log.d(TAG, "hasCallerOrSelfPermission: " + + " perm=" + permission + + " caller=" + Binder.getCallingPid() + + " self=" + Process.myPid() + + " ok=" + ok); + } + return ok; + } + + public static void enforceCallingOrSelfPermission(Context context, String permission) { + final boolean ok = hasCallerOrSelfPermission(context, permission); + if (!ok) { + throw new SecurityException(String.format("The caller must have the %s permission.", + permission)); + } + } + + public static boolean hasPackagePermission(Context context, String permission, String pkg) { + boolean ok = false; + if (ALLOW_SELF_CALL && context.getPackageName().equals(pkg)) { + ok = true; // Called by self; always allow. + } else { + ok = context.getPackageManager().checkPermission(permission, pkg) + == PackageManager.PERMISSION_GRANTED; + } + if (DEBUG) { + Log.d(TAG, "hasCallerOrSelfPermission: " + + " perm=" + permission + + " pkg=" + pkg + + " self=" + context.getPackageName() + + " ok=" + ok); + } + return ok; + } + + public static boolean hasCallerUriPermission(Context context, Uri uri, int modeFlags) { + boolean ok = false; + if (ALLOW_SELF_CALL && Binder.getCallingPid() == Process.myPid()) { + ok = true; // Called by self; always allow. + } else { + ok = context.checkCallingUriPermission(uri, modeFlags) + == PackageManager.PERMISSION_GRANTED; + } + if (DEBUG) { + Log.d(TAG, "hasCallerUriPermission: " + + " uri=" + uri + + " caller=" + Binder.getCallingPid() + + " self=" + Process.myPid() + + " ok=" + ok); + } + return ok; + } +} diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml index 91fceae..e08429a 100644 --- a/tests/AndroidManifest.xml +++ b/tests/AndroidManifest.xml @@ -18,8 +18,6 @@ package="com.android.providers.contacts.tests" android:sharedUserId="android.uid.shared"> - <uses-permission android:name="android.permission.READ_CONTACTS" /> - <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> diff --git a/tests/src/com/android/providers/contacts/ContactsActor.java b/tests/src/com/android/providers/contacts/ContactsActor.java index bad7d5d..3ff4086 100644 --- a/tests/src/com/android/providers/contacts/ContactsActor.java +++ b/tests/src/com/android/providers/contacts/ContactsActor.java @@ -65,6 +65,7 @@ import android.test.mock.MockContentResolver; import android.test.mock.MockContext; import android.util.Log; +import com.android.providers.contacts.util.ContactsPermissions; import com.android.providers.contacts.util.MockSharedPreferences; import com.google.android.collect.Sets; @@ -263,6 +264,10 @@ public class ContactsActor { */ public ContactsActor(final Context overallContext, String packageName, Class<? extends ContentProvider> providerClass, String authority) throws Exception { + + // Force permission check even when called by self. + ContactsPermissions.ALLOW_SELF_CALL = false; + resolver = new MockContentResolver(); context = new RestrictionMockContext(overallContext, packageName, resolver, mGrantedPermissions, mGrantedUriPermissions); |