summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGriff Hazen <griff@google.com>2015-09-08 22:59:10 +0000
committerGriff Hazen <griff@google.com>2015-09-08 22:59:10 +0000
commit5b26c2e64ceeaa1e71436b36a28f53100e358ed8 (patch)
tree17533ebd4b80fe86599ede069e06ce7ceae6a9e1
parentaa4368cafc3c92b33a99c3fbe0e6af08d7e092e4 (diff)
downloadandroid_packages_apps_PackageInstaller-5b26c2e64ceeaa1e71436b36a28f53100e358ed8.tar.gz
android_packages_apps_PackageInstaller-5b26c2e64ceeaa1e71436b36a28f53100e358ed8.tar.bz2
android_packages_apps_PackageInstaller-5b26c2e64ceeaa1e71436b36a28f53100e358ed8.zip
Revert "Move ClockworkPackageInstaller functionality here"
Breaking ub-wear-dinar/ub-wear-master builds This reverts commit aa4368cafc3c92b33a99c3fbe0e6af08d7e092e4. Change-Id: Ib22189891e9cd9eef61cdaa5ac329d05ab9783e8
-rw-r--r--Android.mk1
-rw-r--r--AndroidManifest.xml23
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageIconProvider.java202
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageInstallerService.java608
-rw-r--r--src/com/android/packageinstaller/wear/WearPackageUtil.java154
5 files changed, 0 insertions, 988 deletions
diff --git a/Android.mk b/Android.mk
index 4b2864ba..e95d905b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,7 +15,6 @@ LOCAL_STATIC_JAVA_LIBRARIES += \
android-support-v14-preference \
android-support-v17-preference-leanback \
android-support-v17-leanback \
- xz-java
LOCAL_RESOURCE_DIR := \
frameworks/support/v17/leanback/res \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bfa98483..9120e7ec 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,11 +16,8 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" />
<uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.KILL_UID" />
- <uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" />
-
<application android:label="@string/app_name"
android:allowBackup="false"
android:theme="@style/Theme.DialogWhenLarge"
@@ -102,26 +99,6 @@
<action android:name="android.intent.action.GET_PERMISSIONS_COUNT" />
</intent-filter>
</receiver>
-
- <!-- Wearable Components -->
- <service android:name=".wear.WearPackageInstallerService"
- android:permission="com.google.android.permission.INSTALL_WEARABLE_PACKAGES"
- android:exported="true">
- <intent-filter>
- <action android:name="com.android.packageinstaller.wear.INSTALL_PACKAGE"/>
- <data android:scheme="content" android:mimeType="vnd.android.cursor.item/*"/>
- </intent-filter>
- <intent-filter>
- <action android:name="com.android.packageinstaller.wear.UNINSTALL_PACKAGE"/>
- </intent-filter>
- </service>
-
- <provider android:name=".wear.WearPackageIconProvider"
- android:authorities="com.android.packageinstaller.wear.provider"
- android:grantUriPermissions="true"
- android:exported="true" />
-
-
</application>
</manifest>
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);
- }
-}