diff options
author | Steve Kondik <steve@cyngn.com> | 2016-03-10 18:24:23 -0800 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2016-03-10 18:24:23 -0800 |
commit | e002f536cba85cb90655e44e15497054c1a5651a (patch) | |
tree | 82ced13a5969a87673836a935a0f67d3cf16d5b5 /src/com/android/packageinstaller/wear/WearPackageIconProvider.java | |
parent | cb079ef38ce9881687ab9c89e1c321ded722c1b3 (diff) | |
parent | b145bb2c34c495a51b83bf755e560d7b931ea8f7 (diff) | |
download | android_packages_apps_PackageInstaller-e002f536cba85cb90655e44e15497054c1a5651a.tar.gz android_packages_apps_PackageInstaller-e002f536cba85cb90655e44e15497054c1a5651a.tar.bz2 android_packages_apps_PackageInstaller-e002f536cba85cb90655e44e15497054c1a5651a.zip |
Merge tag 'android-6.0.1_r22' of https://android.googlesource.com/platform/packages/apps/PackageInstaller into cm-13.0staging/cm-13.0+r22
Android 6.0.1 release 22
Diffstat (limited to 'src/com/android/packageinstaller/wear/WearPackageIconProvider.java')
-rw-r--r-- | src/com/android/packageinstaller/wear/WearPackageIconProvider.java | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/com/android/packageinstaller/wear/WearPackageIconProvider.java b/src/com/android/packageinstaller/wear/WearPackageIconProvider.java new file mode 100644 index 00000000..02b9d298 --- /dev/null +++ b/src/com/android/packageinstaller/wear/WearPackageIconProvider.java @@ -0,0 +1,202 @@ +/* + * 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.packageinstaller.wear; + +import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Binder; +import android.os.Build; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.List; + +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +public class WearPackageIconProvider extends ContentProvider { + private static final String TAG = "WearPackageIconProvider"; + public static final String AUTHORITY = "com.google.android.packageinstaller.wear.provider"; + + private static final String REQUIRED_PERMISSION = + "com.google.android.permission.INSTALL_WEARABLE_PACKAGES"; + + /** MIME types. */ + public static final String ICON_TYPE = "vnd.android.cursor.item/cw_package_icon"; + + @Override + public boolean onCreate() { + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + throw new UnsupportedOperationException("Query is not supported."); + } + + @Override + public String getType(Uri uri) { + if (uri == null) { + throw new IllegalArgumentException("URI passed in is null."); + } + + if (AUTHORITY.equals(uri.getEncodedAuthority())) { + return ICON_TYPE; + } + return null; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException("Insert is not supported."); + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + if (uri == null) { + throw new IllegalArgumentException("URI passed in is null."); + } + + enforcePermissions(uri); + + if (ICON_TYPE.equals(getType(uri))) { + final File file = WearPackageUtil.getIconFile( + this.getContext().getApplicationContext(), getPackageNameFromUri(uri)); + if (file != null) { + file.delete(); + } + } + + return 0; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("Update is not supported."); + } + + @Override + public ParcelFileDescriptor openFile( + Uri uri, @SuppressWarnings("unused") String mode) throws FileNotFoundException { + if (uri == null) { + throw new IllegalArgumentException("URI passed in is null."); + } + + enforcePermissions(uri); + + if (ICON_TYPE.equals(getType(uri))) { + final File file = WearPackageUtil.getIconFile( + this.getContext().getApplicationContext(), getPackageNameFromUri(uri)); + if (file != null) { + return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); + } + } + return null; + } + + public static Uri getUriForPackage(final String packageName) { + return Uri.parse("content://" + AUTHORITY + "/icons/" + packageName + ".icon"); + } + + private String getPackageNameFromUri(Uri uri) { + if (uri == null) { + return null; + } + List<String> pathSegments = uri.getPathSegments(); + String packageName = pathSegments.get(pathSegments.size() - 1); + + if (packageName.endsWith(".icon")) { + packageName = packageName.substring(0, packageName.lastIndexOf(".")); + } + return packageName; + } + + /** + * Make sure the calling app is either a system app or the same app or has the right permission. + * @throws SecurityException if the caller has insufficient permissions. + */ + @TargetApi(Build.VERSION_CODES.BASE_1_1) + private void enforcePermissions(Uri uri) { + // Redo some of the permission check in {@link ContentProvider}. Just add an extra check to + // allow System process to access this provider. + Context context = getContext(); + final int pid = Binder.getCallingPid(); + final int uid = Binder.getCallingUid(); + final int myUid = android.os.Process.myUid(); + + if (uid == myUid || isSystemApp(context, pid)) { + return; + } + + if (context.checkPermission(REQUIRED_PERMISSION, pid, uid) == PERMISSION_GRANTED) { + return; + } + + // last chance, check against any uri grants + if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION) + == PERMISSION_GRANTED) { + return; + } + + throw new SecurityException("Permission Denial: reading " + + getClass().getName() + " uri " + uri + " from pid=" + pid + + ", uid=" + uid); + } + + /** + * From the pid of the calling process, figure out whether this is a system app or not. We do + * this by checking the application information corresponding to the pid and then checking if + * FLAG_SYSTEM is set. + */ + @TargetApi(Build.VERSION_CODES.CUPCAKE) + private boolean isSystemApp(Context context, int pid) { + // Get the Activity Manager Object + ActivityManager aManager = + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + // Get the list of running Applications + List<ActivityManager.RunningAppProcessInfo> rapInfoList = + aManager.getRunningAppProcesses(); + for (ActivityManager.RunningAppProcessInfo rapInfo : rapInfoList) { + if (rapInfo.pid == pid) { + try { + PackageInfo pkgInfo = context.getPackageManager().getPackageInfo( + rapInfo.pkgList[0], 0); + if (pkgInfo != null && pkgInfo.applicationInfo != null && + (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + Log.d(TAG, pid + " is a system app."); + return true; + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Could not find package information.", e); + return false; + } + } + } + return false; + } +} |