summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dario Freni <dariofreni@google.com> 2018-12-04 05:05:42 -0800
committer android-build-merger <android-build-merger@google.com> 2018-12-04 05:05:42 -0800
commit110abbf49a91298b826816d43bea7c36becd0ae5 (patch)
tree90d6261c2b61dcf20b625a6c3471478107ce1b7c
parentf29f0de34c7423efc0c6e7a3328078d0c4f17959 (diff)
parent2d03586435e40cbe843debfe34a67c701778ef69 (diff)
Merge changes from topic "apex_adb" am: f64909587b
am: 2d03586435 Change-Id: I217e06b2e131e6eb3f21c6f25207699f9b15b28f
-rw-r--r--Android.bp1
-rwxr-xr-xapi/current.txt2
-rw-r--r--core/java/android/content/pm/PackageInfo.java18
-rw-r--r--core/java/android/content/pm/PackageManager.java20
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java5
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java93
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java8
8 files changed, 157 insertions, 12 deletions
diff --git a/Android.bp b/Android.bp
index 0ac3153da9fc..066d13815d4b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -675,6 +675,7 @@ java_defaults {
],
static_libs: [
+ "apex_aidl_interface-java",
"framework-protos",
"android.hidl.base-V1.0-java",
"android.hardware.cas-V1.0-java",
diff --git a/api/current.txt b/api/current.txt
index 7c33ec50fa4c..ef729d3f2b8b 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -11012,6 +11012,7 @@ package android.content.pm {
field public int[] gids;
field public int installLocation;
field public android.content.pm.InstrumentationInfo[] instrumentation;
+ field public boolean isApex;
field public long lastUpdateTime;
field public java.lang.String packageName;
field public android.content.pm.PermissionInfo[] permissions;
@@ -11390,6 +11391,7 @@ package android.content.pm {
field public static final int INSTALL_REASON_UNKNOWN = 0; // 0x0
field public static final int INSTALL_REASON_USER = 4; // 0x4
field public static final int MATCH_ALL = 131072; // 0x20000
+ field public static final int MATCH_APEX = 1073741824; // 0x40000000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
field public static final int MATCH_DIRECT_BOOT_AWARE = 524288; // 0x80000
field public static final int MATCH_DIRECT_BOOT_UNAWARE = 262144; // 0x40000
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 9e2050327ece..ecdd810653ec 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -18,6 +18,7 @@ package android.content.pm;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
+import android.apex.ApexInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -390,6 +391,11 @@ public class PackageInfo implements Parcelable {
@Nullable
public String compileSdkVersionCodename;
+ /**
+ * Whether the package is an APEX package.
+ */
+ public boolean isApex;
+
public PackageInfo() {
}
@@ -472,6 +478,7 @@ public class PackageInfo implements Parcelable {
} else {
dest.writeInt(0);
}
+ dest.writeBoolean(isApex);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -533,7 +540,7 @@ public class PackageInfo implements Parcelable {
if (hasSigningInfo != 0) {
signingInfo = SigningInfo.CREATOR.createFromParcel(source);
}
-
+ isApex = source.readBoolean();
// The component lists were flattened with the redundant ApplicationInfo
// instances omitted. Distribute the canonical one here as appropriate.
if (applicationInfo != null) {
@@ -544,6 +551,15 @@ public class PackageInfo implements Parcelable {
}
}
+ /**
+ * @hide
+ */
+ public PackageInfo(ApexInfo apexInfo) {
+ packageName = apexInfo.packageName;
+ setLongVersionCode(apexInfo.versionCode);
+ isApex = true;
+ }
+
private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
if (components != null) {
for (ComponentInfo ci : components) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2597f1d53937..1394c358868c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -145,6 +145,7 @@ public abstract class PackageManager {
MATCH_FACTORY_ONLY,
MATCH_DEBUG_TRIAGED_MISSING,
MATCH_INSTANT,
+ MATCH_APEX,
GET_DISABLED_COMPONENTS,
GET_DISABLED_UNTIL_USED_COMPONENTS,
GET_UNINSTALLED_PACKAGES,
@@ -531,6 +532,17 @@ public abstract class PackageManager {
public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 0x20000000;
/**
+ * {@link PackageInfo} flag: include APEX packages that are currently
+ * installed. In APEX terminology, this corresponds to packages that are
+ * currently active, i.e. mounted and available to other processes of the OS.
+ * In particular, this flag alone will not match APEX files that are staged
+ * for activation at next reboot.
+ * TODO(b/119767311): include uninstalled/inactive APEX if
+ * MATCH_UNINSTALLED_PACKAGES is set.
+ */
+ public static final int MATCH_APEX = 0x40000000;
+
+ /**
* Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
* resolving an intent that matches the {@code CrossProfileIntentFilter},
* the current profile will be skipped. Only activities in the target user
@@ -846,6 +858,14 @@ public abstract class PackageManager {
*/
public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000;
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that this package
+ * is an APEX package
+ *
+ * @hide
+ */
+ public static final int INSTALL_APEX = 0x00020000;
+
/** @hide */
@IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
DONT_KILL_APP
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0b32d1a5d69b..6ccd0406bfcc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -58,7 +58,6 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SELinux;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
@@ -646,8 +645,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
try {
- Os.mkdir(stageDir.getAbsolutePath(), 0755);
- Os.chmod(stageDir.getAbsolutePath(), 0755);
+ Os.mkdir(stageDir.getAbsolutePath(), 0775);
+ Os.chmod(stageDir.getAbsolutePath(), 0775);
} catch (ErrnoException e) {
// This purposefully throws if directory already exists
throw new IOException("Failed to prepare session dir: " + stageDir, e);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 81a836749a7f..57deb3f18969 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -42,6 +42,7 @@ import static com.android.server.pm.PackageInstallerService.prepareStageDir;
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.apex.IApexService;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
@@ -73,6 +74,7 @@ import android.os.ParcelableException;
import android.os.Process;
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManager;
@@ -858,12 +860,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
resolveStageDirLocked();
mSealed = true;
-
- // Verify that stage looks sane with respect to existing application.
- // This currently only ensures packageName, versionCode, and certificate
- // consistency.
try {
- validateInstallLocked(pkgInfo);
+ if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ validateApexInstallLocked(pkgInfo);
+ } else {
+ // Verify that stage looks sane with respect to existing application.
+ // This currently only ensures packageName, versionCode, and certificate
+ // consistency.
+ validateApkInstallLocked(pkgInfo);
+ }
} catch (PackageManagerException e) {
throw e;
} catch (Throwable e) {
@@ -942,6 +947,31 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
Preconditions.checkNotNull(mSigningDetails);
Preconditions.checkNotNull(mResolvedBaseFile);
+ if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ commitApexLocked();
+ } else {
+ commitApkLocked();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void commitApexLocked() throws PackageManagerException {
+ try {
+ IApexService apex = IApexService.Stub.asInterface(
+ ServiceManager.getService("apexservice"));
+ apex.stagePackage(mResolvedBaseFile.toString());
+ } catch (Throwable e) {
+ // Convert all exceptions into package manager exceptions as only those are handled
+ // in the code above
+ throw new PackageManagerException(e);
+ } finally {
+ destroyInternal();
+ dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void commitApkLocked() throws PackageManagerException {
if (needToAskForPermissionsLocked()) {
// User needs to accept permissions; give installer an intent they
// can use to involve user.
@@ -1063,6 +1093,57 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
(params.installFlags & PackageManager.DONT_KILL_APP) != 0;
}
+ @GuardedBy("mLock")
+ private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo)
+ throws PackageManagerException {
+ mResolvedStagedFiles.clear();
+ mResolvedInheritedFiles.clear();
+
+ try {
+ resolveStageDirLocked();
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
+ "Failed to resolve stage location", e);
+ }
+
+ final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
+ if (ArrayUtils.isEmpty(addedFiles)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ }
+
+ if (addedFiles.length > 1) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Only one APEX file at a time might be installed");
+ }
+ File addedFile = addedFiles[0];
+ final ApkLite apk;
+ try {
+ apk = PackageParser.parseApkLite(
+ addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
+ } catch (PackageParserException e) {
+ throw PackageManagerException.from(e);
+ }
+
+ mPackageName = apk.packageName;
+ mVersionCode = apk.getLongVersionCode();
+ mSigningDetails = apk.signingDetails;
+ mResolvedBaseFile = addedFile;
+
+ assertApkConsistentLocked(String.valueOf(addedFile), apk);
+
+ if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
+ try {
+ // STOPSHIP: For APEX we should also implement proper APK Signature verification.
+ mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
+ pkgInfo.applicationInfo.sourceDir,
+ PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
+ } catch (PackageParserException e) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Couldn't obtain signatures from base APK");
+ }
+ }
+ }
+
/**
* Validate install by confirming that all application packages are have
* consistent package name, version code, and signing certificates.
@@ -1076,7 +1157,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
* {@link PackageManagerService}.
*/
@GuardedBy("mLock")
- private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
+ private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo)
throws PackageManagerException {
mPackageName = null;
mVersionCode = -1;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 89351eb56537..9345ad1339af 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -65,6 +65,7 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.MATCH_APEX;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
@@ -123,6 +124,8 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.apex.ApexInfo;
+import android.apex.IApexService;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
@@ -7912,6 +7915,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
flags = updateFlagsForPackage(flags, userId, null);
final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
+ final boolean listApex = (flags & MATCH_APEX) != 0;
+
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /* requireFullPermission */, false /* checkShell */,
"get installed packages");
@@ -7950,7 +7955,22 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
}
-
+ if (listApex) {
+ final IApexService apex = IApexService.Stub.asInterface(
+ ServiceManager.getService("apexservice"));
+ if (apex != null) {
+ try {
+ final ApexInfo[] activePkgs = apex.getActivePackages();
+ for (ApexInfo apexInfo : activePkgs) {
+ list.add(new PackageInfo(apexInfo));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to retrieve packages from apexservice: " + e.toString());
+ }
+ } else {
+ Log.e(TAG, "Unable to connect to apexservice for querying packages.");
+ }
+ }
return new ParceledListSlice<>(list);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 96bf44ac6d5a..580126f5c330 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -915,7 +915,10 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println("Error: must either specify a package size or an APK file");
return 1;
}
- if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+ final boolean isApex =
+ (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
+ String splitName = "base." + (isApex ? "apex" : "apk");
+ if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
@@ -2229,6 +2232,9 @@ class PackageManagerShellCommand extends ShellCommand {
case "--force-sdk":
sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
break;
+ case "--apex":
+ sessionParams.installFlags |= PackageManager.INSTALL_APEX;
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}