diff options
Diffstat (limited to 'src')
3 files changed, 0 insertions, 964 deletions
diff --git a/src/com/android/packageinstaller/wear/WearPackageIconProvider.java b/src/com/android/packageinstaller/wear/WearPackageIconProvider.java deleted file mode 100644 index 02b9d298..00000000 --- a/src/com/android/packageinstaller/wear/WearPackageIconProvider.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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; - } -} diff --git a/src/com/android/packageinstaller/wear/WearPackageInstallerService.java b/src/com/android/packageinstaller/wear/WearPackageInstallerService.java deleted file mode 100644 index e9ea21e1..00000000 --- a/src/com/android/packageinstaller/wear/WearPackageInstallerService.java +++ /dev/null @@ -1,608 +0,0 @@ -/* - * 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.Nullable; -import android.app.Service; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.FeatureInfo; -import android.content.pm.IPackageDeleteObserver; -import android.content.pm.IPackageInstallObserver; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import android.os.PowerManager; -import android.os.Process; -import android.text.TextUtils; -import android.util.Log; - -import com.android.packageinstaller.PackageUtil; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * Service that will install/uninstall packages. It will check for permissions and features as well. - * - * ----------- - * - * Debugging information: - * - * Install Action example: - * adb shell am startservice -a com.android.packageinstaller.wear.INSTALL_PACKAGE \ - * -t vnd.android.cursor.item/wearable_apk \ - * -d content://com.google.android.clockwork.home.provider/host/com.google.android.wearable.app/wearable/com.google.android.gms/apk \ - * --es android.intent.extra.INSTALLER_PACKAGE_NAME com.google.android.gms \ - * --ez com.google.android.clockwork.EXTRA_CHECK_PERMS false \ - * --eu com.google.android.clockwork.EXTRA_PERM_URI content://com.google.android.clockwork.home.provider/host/com.google.android.wearable.app/permissions \ - * com.android.packageinstaller/com.android.packageinstaller.wear.WearPackageInstallerService - * - * Retry GMS: - * adb shell am startservice -a com.android.packageinstaller.wear.RETRY_GMS \ - * com.android.packageinstaller/com.android.packageinstaller.wear.WearPackageInstallerService - */ -public class WearPackageInstallerService extends Service { - private static final String TAG = "WearPkgInstallerService"; - - private static final String KEY_PERM_URI = - "com.google.android.clockwork.EXTRA_PERM_URI"; - private static final String KEY_CHECK_PERMS = - "com.google.android.clockwork.EXTRA_CHECK_PERMS"; - private static final String KEY_SKIP_IF_SAME_VERSION = - "com.google.android.clockwork.EXTRA_SKIP_IF_SAME_VERSION"; - private static final String KEY_COMPRESSION_ALG = - "com.google.android.clockwork.EXTRA_KEY_COMPRESSION_ALG"; - private static final String KEY_COMPANION_SDK_VERSION = - "com.google.android.clockwork.EXTRA_KEY_COMPANION_SDK_VERSION"; - private static final String KEY_COMPANION_DEVICE_VERSION = - "com.google.android.clockwork.EXTRA_KEY_COMPANION_DEVICE_VERSION"; - - private static final String KEY_PACKAGE_NAME = - "com.google.android.clockwork.EXTRA_PACKAGE_NAME"; - private static final String KEY_APP_LABEL = "com.google.android.clockwork.EXTRA_APP_LABEL"; - private static final String KEY_APP_ICON_URI = - "com.google.android.clockwork.EXTRA_APP_ICON_URI"; - private static final String KEY_PERMS_LIST = "com.google.android.clockwork.EXTRA_PERMS_LIST"; - private static final String KEY_HAS_LAUNCHER = - "com.google.android.clockwork.EXTRA_HAS_LAUNCHER"; - - private static final String HOME_APP_PACKAGE_NAME = "com.google.android.wearable.app"; - private static final String SHOW_PERMS_SERVICE_CLASS = - "com.google.android.clockwork.packagemanager.ShowPermsService"; - - private static final String ASSET_URI_ARG = "assetUri"; - private static final String PACKAGE_NAME_ARG = "packageName"; - private static final String PERM_URI_ARG = "permUri"; - private static final String START_ID_ARG = "startId"; - private static final String CHECK_PERMS_ARG = "checkPerms"; - private static final String SKIP_IF_SAME_VERSION_ARG = "skipIfSameVersion"; - private static final String COMPRESSION_ALG = "compressionAlg"; - private static final String COMPANION_SDK_VERSION = "companionSdkVersion"; - private static final String COMPANION_DEVICE_VERSION = "companionDeviceVersion"; - - /** - * Normally sent by the Play store (See http://go/playstore-gms_updated), we instead - * broadcast, ourselves. http://b/17387718 - */ - private static final String GMS_UPDATED_BROADCAST = "com.google.android.gms.GMS_UPDATED"; - public static final String GMS_PACKAGE_NAME = "com.google.android.gms"; - - private final int START_INSTALL = 1; - private final int START_UNINSTALL = 2; - - private final class ServiceHandler extends Handler { - public ServiceHandler(Looper looper) { - super(looper); - } - - public void handleMessage(Message msg) { - switch (msg.what) { - case START_INSTALL: - installPackage(msg.getData().getString(PACKAGE_NAME_ARG), - (Uri) msg.getData().getParcelable(ASSET_URI_ARG), - (Uri) msg.getData().getParcelable(PERM_URI_ARG), - msg.getData().getInt(START_ID_ARG), - msg.getData().getBoolean(CHECK_PERMS_ARG), - msg.getData().getBoolean(SKIP_IF_SAME_VERSION_ARG), - msg.getData().getString(COMPRESSION_ALG), - msg.getData().getInt(COMPANION_SDK_VERSION), - msg.getData().getInt(COMPANION_DEVICE_VERSION)); - break; - case START_UNINSTALL: - uninstallPackage(msg.getData().getString(PACKAGE_NAME_ARG), - msg.getData().getInt(START_ID_ARG)); - break; - } - } - } - private ServiceHandler mServiceHandler; - - private static volatile PowerManager.WakeLock lockStatic = null; - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public void onCreate() { - super.onCreate(); - HandlerThread thread = new HandlerThread("PackageInstallerThread", - Process.THREAD_PRIORITY_BACKGROUND); - thread.start(); - - mServiceHandler = new ServiceHandler(thread.getLooper()); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (!WearPackageUtil.isWear(this)) { - Log.w(TAG, "Not running on wearable"); - return START_NOT_STICKY; - } - PowerManager.WakeLock lock = getLock(this.getApplicationContext()); - if (!lock.isHeld()) { - lock.acquire(); - } - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Got install/uninstall request " + intent); - } - if (intent != null) { - if (Intent.ACTION_INSTALL_PACKAGE.equals(intent.getAction())) { - final Message msg = mServiceHandler.obtainMessage(START_INSTALL); - final Bundle startInstallArgs = new Bundle(); - startInstallArgs.putParcelable(ASSET_URI_ARG, intent.getData()); - startInstallArgs.putString(PACKAGE_NAME_ARG, intent.getStringExtra( - Intent.EXTRA_INSTALLER_PACKAGE_NAME)); - startInstallArgs.putInt(START_ID_ARG, startId); - Uri permUri = intent.getParcelableExtra(KEY_PERM_URI); - startInstallArgs.putParcelable(PERM_URI_ARG, permUri); - startInstallArgs.putBoolean(CHECK_PERMS_ARG, - intent.getBooleanExtra(KEY_CHECK_PERMS, true)); - startInstallArgs.putBoolean(SKIP_IF_SAME_VERSION_ARG, - intent.getBooleanExtra(KEY_SKIP_IF_SAME_VERSION, false)); - startInstallArgs.putString(COMPRESSION_ALG, - intent.getStringExtra(KEY_COMPRESSION_ALG)); - startInstallArgs.putInt(COMPANION_SDK_VERSION, - intent.getIntExtra(KEY_COMPANION_SDK_VERSION, 0)); - startInstallArgs.putInt(COMPANION_DEVICE_VERSION, - intent.getIntExtra(KEY_COMPANION_DEVICE_VERSION, 0)); - msg.setData(startInstallArgs); - mServiceHandler.sendMessage(msg); - } else if (Intent.ACTION_UNINSTALL_PACKAGE.equals(intent.getAction())) { - Message msg = mServiceHandler.obtainMessage(START_UNINSTALL); - Bundle startUninstallArgs = new Bundle(); - startUninstallArgs.putString(PACKAGE_NAME_ARG, intent.getStringExtra( - Intent.EXTRA_INSTALLER_PACKAGE_NAME)); - startUninstallArgs.putInt(START_ID_ARG, startId); - msg.setData(startUninstallArgs); - mServiceHandler.sendMessage(msg); - } - } - return START_NOT_STICKY; - } - - private void installPackage(String packageName, Uri packageUri, Uri permUri, int startId, - boolean checkPerms, boolean skipIfSameVersion, @Nullable String compressionAlg, - int companionSdkVersion, int companionDeviceVersion) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Installing package: " + packageName + ", packageUri: " + packageUri + - ",permUri: " + permUri + ", startId: " + startId + ", checkPerms: " + - checkPerms + ", skipIfSameVersion: " + skipIfSameVersion + - ", compressionAlg: " + compressionAlg + ", companionSdkVersion: " + - companionSdkVersion + ", companionDeviceVersion: " + companionDeviceVersion); - } - final PackageManager pm = getPackageManager(); - File tempFile = null; - int installFlags = 0; - PowerManager.WakeLock lock = getLock(this.getApplicationContext()); - boolean messageSent = false; - try { - PackageInfo existingPkgInfo = null; - try { - existingPkgInfo = pm.getPackageInfo(packageName, - PackageManager.GET_UNINSTALLED_PACKAGES); - if(existingPkgInfo != null) { - installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; - } - } catch (PackageManager.NameNotFoundException e) { - // Ignore this exception. We could not find the package, will treat as a new - // installation. - } - if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Replacing package:" + packageName); - } - } - ParcelFileDescriptor parcelFd = getContentResolver() - .openFileDescriptor(packageUri, "r"); - tempFile = WearPackageUtil.getFileFromFd(WearPackageInstallerService.this, - parcelFd, packageName, compressionAlg); - if (tempFile == null) { - Log.e(TAG, "Could not create a temp file from FD for " + packageName); - return; - } - PackageParser.Package pkg = PackageUtil.getPackageInfo(tempFile); - if (pkg == null) { - Log.e(TAG, "Could not parse apk information for " + packageName); - return; - } - - if (!pkg.packageName.equals(packageName)) { - Log.e(TAG, "Wearable Package Name has to match what is provided for " + - packageName); - return; - } - - List<String> wearablePerms = pkg.requestedPermissions; - - // Log if the installed pkg has a higher version number. - if (existingPkgInfo != null) { - if (existingPkgInfo.versionCode == pkg.mVersionCode) { - if (skipIfSameVersion) { - Log.w(TAG, "Version number (" + pkg.mVersionCode + - ") of new app is equal to existing app for " + packageName + - "; not installing due to versionCheck"); - return; - } else { - Log.w(TAG, "Version number of new app (" + pkg.mVersionCode + - ") is equal to existing app for " + packageName); - } - } else if (existingPkgInfo.versionCode > pkg.mVersionCode) { - Log.w(TAG, "Version number of new app (" + pkg.mVersionCode + - ") is lower than existing app ( " + existingPkgInfo.versionCode + - ") for " + packageName); - } - - // Following the Android Phone model, we should only check for permissions for any - // newly defined perms. - if (existingPkgInfo.requestedPermissions != null) { - for (int i = 0; i < existingPkgInfo.requestedPermissions.length; ++i) { - // If the permission is granted, then we will not ask to request it again. - if ((existingPkgInfo.requestedPermissionsFlags[i] & - PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) { - wearablePerms.remove(existingPkgInfo.requestedPermissions[i]); - } - } - } - } - - // Check permissions on both the new wearable package and also on the already installed - // wearable package. - // If the app is targeting API level 23, we will also start a service in ClockworkHome - // which will ultimately prompt the user to accept/reject permissions. - if (checkPerms && !checkPermissions(pkg, companionSdkVersion, companionDeviceVersion, - permUri, wearablePerms, tempFile)) { - Log.w(TAG, "Wearable does not have enough permissions."); - return; - } - - // Check that the wearable has all the features. - boolean hasAllFeatures = true; - if (pkg.reqFeatures != null) { - for (FeatureInfo feature : pkg.reqFeatures) { - if (feature.name != null && !pm.hasSystemFeature(feature.name) && - (feature.flags & FeatureInfo.FLAG_REQUIRED) != 0) { - Log.e(TAG, "Wearable does not have required feature: " + feature + - " for " + packageName); - hasAllFeatures = false; - } - } - } - - if (!hasAllFeatures) { - return; - } - - // Finally install the package. - pm.installPackage(Uri.fromFile(tempFile), - new PackageInstallObserver(this, lock, startId), installFlags, packageName); - messageSent = true; - Log.i(TAG, "Sent installation request for " + packageName); - } catch (FileNotFoundException e) { - Log.e(TAG, "Could not find the file with URI " + packageUri, e); - } finally { - if (!messageSent) { - // Some error happened. If the message has been sent, we can wait for the observer - // which will finish the service. - if (tempFile != null) { - tempFile.delete(); - } - finishService(lock, startId); - } - } - } - - private void uninstallPackage(String packageName, int startId) { - final PackageManager pm = getPackageManager(); - PowerManager.WakeLock lock = getLock(this.getApplicationContext()); - pm.deletePackage(packageName, new PackageDeleteObserver(lock, startId), - PackageManager.DELETE_ALL_USERS); - startPermsServiceForUninstall(packageName); - Log.i(TAG, "Sent delete request for " + packageName); - } - - private boolean checkPermissions(PackageParser.Package pkg, int companionSdkVersion, - int companionDeviceVersion, Uri permUri, List<String> wearablePermissions, - File apkFile) { - if (permUri == null) { - Log.e(TAG, "Permission URI is null"); - return false; - } - Cursor permCursor = getContentResolver().query(permUri, null, null, null, null); - if (permCursor == null) { - Log.e(TAG, "Could not get the cursor for the permissions"); - return false; - } - - final String packageName = pkg.packageName; - - Set<String> grantedPerms = new HashSet<>(); - Set<String> ungrantedPerms = new HashSet<>(); - while(permCursor.moveToNext()) { - // Make sure that the MatrixCursor returned by the ContentProvider has 2 columns and - // verify their types. - if (permCursor.getColumnCount() == 2 - && Cursor.FIELD_TYPE_STRING == permCursor.getType(0) - && Cursor.FIELD_TYPE_INTEGER == permCursor.getType(1)) { - String perm = permCursor.getString(0); - Integer granted = permCursor.getInt(1); - if (granted == 1) { - grantedPerms.add(perm); - } else { - ungrantedPerms.add(perm); - } - } - } - permCursor.close(); - - ArrayList<String> unavailableWearablePerms = new ArrayList<>(); - for (String wearablePerm : wearablePermissions) { - if (!grantedPerms.contains(wearablePerm)) { - unavailableWearablePerms.add(wearablePerm); - if (!ungrantedPerms.contains(wearablePerm)) { - // This is an error condition. This means that the wearable has permissions that - // are not even declared in its host app. This is a developer error. - Log.e(TAG, "Wearable " + packageName + " has a permission \"" + wearablePerm - + "\" that is not defined in the host application's manifest."); - } else { - Log.w(TAG, "Wearable " + packageName + " has a permission \"" + wearablePerm + - "\" that is not granted in the host application."); - } - } - } - - - // If the Wear App is targeted for M-release, since the permission model has been changed, - // permissions may not be granted on the phone yet. We need a different flow for user to - // accept these permissions. - // - // Case 1: Companion App >= 23 (and running on M), Wear App targeting >= 23 - // - If Wear is running L (ie DMR1), show a dialog so that the user can accept all perms - // - If Wear is running M (ie E-release), use new permission model. - // Case 2: Companion App <= 22, Wear App targeting <= 22 - // - Default to old behavior. - // Case 3: Companion App <= 22, Wear App targeting >= 23 - // - If Wear is running L (ie DMR1), install the app as before. In effect, pretend - // like wear app is targeting 22. - // - If Wear is running M (ie E-release), use new permission model. - // Case 4: Companion App >= 23 (and running on M), Wear App targeting <= 22 - // - Show a warning below to the developer. - // - Show a dialog as in Case 1 with DMR1. This behavior will happen in E and DMR1. - // Case 5: We did not get Companion App's/Device's version (we have to guess here) - // - Show dialog if Wear App targeting >= 23 and Wear is not running M - if (unavailableWearablePerms.size() > 0) { - boolean isCompanionTargetingM = companionSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1; - boolean isCompanionRunningM = companionDeviceVersion > Build.VERSION_CODES.LOLLIPOP_MR1; - boolean isWearTargetingM = - pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1; - boolean isWearRunningM = Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1; - - if (companionSdkVersion == 0 || companionDeviceVersion == 0) { // Case 5 - if (isWearTargetingM && !isWearRunningM) { - startPermsServiceForInstall(pkg, apkFile, unavailableWearablePerms); - } - } else if (isCompanionTargetingM && isCompanionRunningM) { - if (!isWearTargetingM) { // Case 4 - Log.w(TAG, "MNC: Wear app's targetSdkVersion should be at least 23, if phone " + - "app is targeting at least 23."); - startPermsServiceForInstall(pkg, apkFile, unavailableWearablePerms); - } else if (!isWearRunningM) { // Case 1, part 1 - startPermsServiceForInstall(pkg, apkFile, unavailableWearablePerms); - } - } // Else, nothing to do. See explanation above. - } - - return unavailableWearablePerms.size() == 0; - } - - private void finishService(PowerManager.WakeLock lock, int startId) { - if (lock.isHeld()) { - lock.release(); - } - stopSelf(startId); - } - - private synchronized PowerManager.WakeLock getLock(Context context) { - if (lockStatic == null) { - PowerManager mgr = - (PowerManager) context.getSystemService(Context.POWER_SERVICE); - lockStatic = mgr.newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, context.getClass().getSimpleName()); - lockStatic.setReferenceCounted(true); - } - return lockStatic; - } - - private void startPermsServiceForInstall(final PackageParser.Package pkg, final File apkFile, - ArrayList<String> unavailableWearablePerms) { - final String packageName = pkg.packageName; - - Intent showPermsIntent = new Intent() - .setComponent(new ComponentName(HOME_APP_PACKAGE_NAME, SHOW_PERMS_SERVICE_CLASS)) - .setAction(Intent.ACTION_INSTALL_PACKAGE); - final PackageManager pm = getPackageManager(); - pkg.applicationInfo.publicSourceDir = apkFile.getPath(); - final CharSequence label = pkg.applicationInfo.loadLabel(pm); - final Uri iconUri = getIconFileUri(packageName, pkg.applicationInfo.loadIcon(pm)); - if (TextUtils.isEmpty(label) || iconUri == null) { - Log.e(TAG, "MNC: Could not launch service since either label " + label + - ", or icon Uri " + iconUri + " is invalid."); - } else { - showPermsIntent.putExtra(KEY_APP_LABEL, label); - showPermsIntent.putExtra(KEY_APP_ICON_URI, iconUri); - showPermsIntent.putExtra(KEY_PACKAGE_NAME, packageName); - showPermsIntent.putExtra(KEY_PERMS_LIST, - unavailableWearablePerms.toArray(new String[0])); - showPermsIntent.putExtra(KEY_HAS_LAUNCHER, WearPackageUtil.hasLauncherActivity(pkg)); - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "MNC: Launching Intent " + showPermsIntent + " for " + packageName + - " with name " + label); - } - startService(showPermsIntent); - } - } - - private void startPermsServiceForUninstall(final String packageName) { - Intent showPermsIntent = new Intent() - .setComponent(new ComponentName(HOME_APP_PACKAGE_NAME, SHOW_PERMS_SERVICE_CLASS)) - .setAction(Intent.ACTION_UNINSTALL_PACKAGE); - showPermsIntent.putExtra(KEY_PACKAGE_NAME, packageName); - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Launching Intent " + showPermsIntent + " for " + packageName); - } - startService(showPermsIntent); - } - - private Uri getIconFileUri(final String packageName, final Drawable d) { - if (d == null || !(d instanceof BitmapDrawable)) { - Log.e(TAG, "Drawable is not a BitmapDrawable for " + packageName); - return null; - } - File iconFile = WearPackageUtil.getIconFile(this, packageName); - - if (iconFile == null) { - Log.e(TAG, "Could not get icon file for " + packageName); - return null; - } - - FileOutputStream fos = null; - try { - // Convert bitmap to byte array - Bitmap bitmap = ((BitmapDrawable) d).getBitmap(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); - - // Write the bytes into the file - fos = new FileOutputStream(iconFile); - fos.write(bos.toByteArray()); - fos.flush(); - - return WearPackageIconProvider.getUriForPackage(packageName); - } catch (IOException e) { - Log.e(TAG, "Could not convert drawable to icon file for package " + packageName, e); - return null; - } finally { - if (fos != null) { - try { - fos.close(); - } catch (IOException e) { - // ignore - } - } - } - } - - private class PackageInstallObserver extends IPackageInstallObserver.Stub { - private Context mContext; - private PowerManager.WakeLock mWakeLock; - private int mStartId; - private PackageInstallObserver(Context context, PowerManager.WakeLock wakeLock, - int startId) { - mContext = context; - mWakeLock = wakeLock; - mStartId = startId; - } - - public void packageInstalled(String packageName, int returnCode) { - if (returnCode >= 0) { - Log.i(TAG, "Package " + packageName + " was installed."); - } else { - Log.e(TAG, "Package install failed " + packageName + ", returnCode " + returnCode); - } - - // Delete tempFile from the file system. - File tempFile = WearPackageUtil.getTemporaryFile(mContext, packageName); - if (tempFile != null) { - tempFile.delete(); - } - - // Broadcast the "UPDATED" gmscore intent, normally sent by play store. - // TODO: Remove this broadcast if/when we get the play store to do this for us. - if (GMS_PACKAGE_NAME.equals(packageName)) { - Intent gmsInstalledIntent = new Intent(GMS_UPDATED_BROADCAST); - gmsInstalledIntent.setPackage(GMS_PACKAGE_NAME); - mContext.sendBroadcast(gmsInstalledIntent); - } - - finishService(mWakeLock, mStartId); - } - } - - private class PackageDeleteObserver extends IPackageDeleteObserver.Stub { - private PowerManager.WakeLock mWakeLock; - private int mStartId; - - private PackageDeleteObserver(PowerManager.WakeLock wakeLock, int startId) { - mWakeLock = wakeLock; - mStartId = startId; - } - - public void packageDeleted(String packageName, int returnCode) { - if (returnCode >= 0) { - Log.i(TAG, "Package " + packageName + " was uninstalled."); - } else { - Log.e(TAG, "Package uninstall failed " + packageName + ", returnCode " + - returnCode); - } - finishService(mWakeLock, mStartId); - } - } -} diff --git a/src/com/android/packageinstaller/wear/WearPackageUtil.java b/src/com/android/packageinstaller/wear/WearPackageUtil.java deleted file mode 100644 index bec697d9..00000000 --- a/src/com/android/packageinstaller/wear/WearPackageUtil.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.Nullable; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.os.ParcelFileDescriptor; -import android.system.ErrnoException; -import android.system.Os; -import android.text.TextUtils; -import android.util.Log; - -import org.tukaani.xz.LZMAInputStream; -import org.tukaani.xz.XZInputStream; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; - -public class WearPackageUtil { - private static final String TAG = "WearablePkgInstaller"; - - private static final String COMPRESSION_LZMA = "lzma"; - private static final String COMPRESSION_XZ = "xz"; - - public static File getTemporaryFile(Context context, String packageName) { - try { - File newFileDir = new File(context.getFilesDir(), "tmp"); - newFileDir.mkdirs(); - Os.chmod(newFileDir.getAbsolutePath(), 0771); - File newFile = new File(newFileDir, packageName + ".apk"); - return newFile; - } catch (ErrnoException e) { - Log.e(TAG, "Failed to open.", e); - return null; - } - } - - public static File getIconFile(final Context context, final String packageName) { - try { - File newFileDir = new File(context.getFilesDir(), "images/icons"); - newFileDir.mkdirs(); - Os.chmod(newFileDir.getAbsolutePath(), 0771); - return new File(newFileDir, packageName + ".icon"); - } catch (ErrnoException e) { - Log.e(TAG, "Failed to open.", e); - return null; - } - } - - /** - * In order to make sure that the Wearable Asset Manager has a reasonable apk that can be used - * by the PackageManager, we will parse it before sending it to the PackageManager. - * Unfortunately, PackageParser needs a file to parse. So, we have to temporarily convert the fd - * to a File. - * - * @param context - * @param fd FileDescriptor to convert to File - * @param packageName Name of package, will define the name of the file - * @param compressionAlg Can be null. For ALT mode the APK will be compressed. We will - * decompress it here - */ - public static File getFileFromFd(Context context, ParcelFileDescriptor fd, - String packageName, @Nullable String compressionAlg) { - File newFile = getTemporaryFile(context, packageName); - if (fd == null || fd.getFileDescriptor() == null) { - return null; - } - InputStream fr = new ParcelFileDescriptor.AutoCloseInputStream(fd); - try { - if (TextUtils.equals(compressionAlg, COMPRESSION_XZ)) { - fr = new XZInputStream(fr); - } else if (TextUtils.equals(compressionAlg, COMPRESSION_LZMA)) { - fr = new LZMAInputStream(fr); - } - } catch (IOException e) { - Log.e(TAG, "Compression was set to " + compressionAlg + ", but could not decode ", e); - return null; - } - - int nRead; - byte[] data = new byte[1024]; - try { - final FileOutputStream fo = new FileOutputStream(newFile); - while ((nRead = fr.read(data, 0, data.length)) != -1) { - fo.write(data, 0, nRead); - } - fo.flush(); - fo.close(); - Os.chmod(newFile.getAbsolutePath(), 0644); - return newFile; - } catch (IOException e) { - Log.e(TAG, "Reading from Asset FD or writing to temp file failed ", e); - return null; - } catch (ErrnoException e) { - Log.e(TAG, "Could not set permissions on file ", e); - return null; - } finally { - try { - fr.close(); - } catch (IOException e) { - Log.e(TAG, "Failed to close the file from FD ", e); - } - } - } - - public static boolean hasLauncherActivity(PackageParser.Package pkg) { - if (pkg == null || pkg.activities == null) { - return false; - } - - final int activityCount = pkg.activities.size(); - for (int i = 0; i < activityCount; ++i) { - if (pkg.activities.get(i).intents != null) { - ArrayList<PackageParser.ActivityIntentInfo> intents = - pkg.activities.get(i).intents; - final int intentsCount = intents.size(); - for (int j = 0; j < intentsCount; ++j) { - final PackageParser.ActivityIntentInfo intentInfo = intents.get(j); - if (intentInfo.hasAction(Intent.ACTION_MAIN)) { - if (intentInfo.hasCategory(Intent.CATEGORY_INFO) || - intentInfo .hasCategory(Intent.CATEGORY_LAUNCHER)) { - return true; - } - } - } - } - } - return false; - } - - public static boolean isWear(final Context context) { - return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); - } -} |