From ca3872ce36c94090ae18519dc7fe0cf39d834c4a Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 30 Oct 2017 14:19:32 -0700 Subject: Fully implement "install" and "install-write" in PackageManagerShellCommand. We can use the new mechanism to ask the calling shell to open a file in order to implement the rest of these commands, allowing you to give the path to an apk to install. That API is thus extended to allow you to open readable files, not just opening file for writing. Doing this however means we no longer can pass a file path to AssetManager for the apk to parse, we only have an already open fd for that. Extending AssetManager to allow adding apks from fds is not that hard, however, since the underlying zip library already supports this. This main thing this changes is in AssetManager.cpp where we retrieve the open zip file for a particular apk that has been added. This used to look up the zip file by path every time it was needed, but that won't work anymore now that we can have things added by fd. Instead, we keep track of each opened zip in the AssetManager, so we can just directly retrieve it from the asset_path representing the item that was added. As a side-effect, this means for normal paths we no longer need to look up by name, but just have the opened zip file directly accessible. (This is probably good, but it does mean that we no longer run the logic of seeing if the zip file's timestamp has changed and re-opening it if it has. We probably shouldn't be relying on that for an active AssetManager anyway, and maybe it is even good that we don't allow the zip file to change under it?) A follow-up change will finally remove the Pm.java implementation and turn the pm "command" into a simple shell script that runs cmd package. Test: manual Change-Id: Ie103e3bdaa5b706796cc329254f2638151a3924f --- libs/androidfw/AssetManager.cpp | 87 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 8 deletions(-) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 5603508eaf09..3c8736ea0c4c 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -150,6 +150,14 @@ AssetManager::~AssetManager() { ALOGI("Destroying AssetManager in %p #%d\n", this, count); } + // Manually close any fd paths for which we have not yet opened their zip (which + // will take ownership of the fd and close it when done). + for (size_t i=0; i= 0 && mAssetPaths[i].zip == NULL) { + close(mAssetPaths[i].rawFd); + } + } + delete mConfig; delete mResources; @@ -280,7 +288,35 @@ bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie) } return true; - } +} + +bool AssetManager::addAssetFd( + int fd, const String8& debugPathName, int32_t* cookie, bool appAsLib, + bool assume_ownership) { + AutoMutex _l(mLock); + + asset_path ap; + + ap.path = debugPathName; + ap.rawFd = fd; + ap.type = kFileTypeRegular; + ap.assumeOwnership = assume_ownership; + + ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.string()); + + mAssetPaths.add(ap); + + // new paths are always added at the end + if (cookie) { + *cookie = static_cast(mAssetPaths.size()); + } + + if (mResources != NULL) { + appendPathToResTable(ap, appAsLib); + } + + return true; +} bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath, uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize) @@ -505,7 +541,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con Asset* idmap = openIdmapLocked(ap); size_t nextEntryIdx = mResources->getTableCount(); ALOGV("Looking for resource asset in '%s'\n", ap.path.string()); - if (ap.type != kFileTypeDirectory) { + if (ap.type != kFileTypeDirectory && ap.rawFd < 0) { if (nextEntryIdx == 0) { // The first item is typically the framework resources, // which we want to avoid parsing every time. @@ -738,6 +774,8 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m { Asset* pAsset = NULL; + ALOGV("openNonAssetInPath: name=%s type=%d fd=%d", fileName, ap.type, ap.rawFd); + /* look at the filesystem on disk */ if (ap.type == kFileTypeDirectory) { String8 path(ap.path); @@ -752,7 +790,7 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m } if (pAsset != NULL) { - //printf("FOUND NA '%s' on disk\n", fileName); + ALOGV("FOUND NA '%s' on disk", fileName); pAsset->setAssetSource(path); } @@ -763,10 +801,10 @@ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode m /* check the appropriate Zip file */ ZipFileRO* pZip = getZipFileLocked(ap); if (pZip != NULL) { - //printf("GOT zip, checking NA '%s'\n", (const char*) path); + ALOGV("GOT zip, checking NA '%s'", (const char*) path); ZipEntryRO entry = pZip->findEntryByName(path.string()); if (entry != NULL) { - //printf("FOUND NA in Zip file for %s\n", appName ? appName : kAppCommon); + ALOGV("FOUND NA in Zip file for %s", (const char*) path); pAsset = openAssetFromZipLocked(pZip, entry, mode, path); pZip->releaseEntry(entry); } @@ -817,7 +855,17 @@ ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap) { ALOGV("getZipFileLocked() in %p\n", this); - return mZipSet.getZip(ap.path); + if (ap.zip != NULL) { + return ap.zip->getZip(); + } + + if (ap.rawFd < 0) { + ap.zip = mZipSet.getSharedZip(ap.path); + } else { + ap.zip = SharedZip::create(ap.rawFd, ap.path); + + } + return ap.zip != NULL ? ap.zip->getZip() : NULL; } /* @@ -1374,6 +1422,21 @@ AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen) } } +AssetManager::SharedZip::SharedZip(int fd, const String8& path) + : mPath(path), mZipFile(NULL), mModWhen(0), + mResourceTableAsset(NULL), mResourceTable(NULL) +{ + if (kIsDebug) { + ALOGI("Creating SharedZip %p fd=%d %s\n", this, fd, (const char*)mPath); + } + ALOGV("+++ opening zip fd=%d '%s'\n", fd, mPath.string()); + mZipFile = ZipFileRO::openFd(fd, mPath.string()); + if (mZipFile == NULL) { + ::close(fd); + ALOGD("failed to open Zip archive fd=%d '%s'\n", fd, mPath.string()); + } +} + sp AssetManager::SharedZip::get(const String8& path, bool createIfNotPresent) { @@ -1389,7 +1452,11 @@ sp AssetManager::SharedZip::get(const String8& path, zip = new SharedZip(path, modWhen); gOpen.add(path, zip); return zip; +} +sp AssetManager::SharedZip::create(int fd, const String8& path) +{ + return new SharedZip(fd, path); } ZipFileRO* AssetManager::SharedZip::getZip() @@ -1500,11 +1567,15 @@ void AssetManager::ZipSet::closeZip(int idx) mZipFile.editItemAt(idx) = NULL; } - /* * Retrieve the appropriate Zip file from the set. */ ZipFileRO* AssetManager::ZipSet::getZip(const String8& path) +{ + return getSharedZip(path)->getZip(); +} + +const sp AssetManager::ZipSet::getSharedZip(const String8& path) { int idx = getIndex(path); sp zip = mZipFile[idx]; @@ -1512,7 +1583,7 @@ ZipFileRO* AssetManager::ZipSet::getZip(const String8& path) zip = SharedZip::get(path); mZipFile.editItemAt(idx) = zip; } - return zip->getZip(); + return zip; } Asset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path) -- cgit v1.2.3-59-g8ed1b From 1704e3cf0c445512f0a9644485dd3449e874556b Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 31 Oct 2017 19:55:42 +0000 Subject: The pm command is no more. It is now just a shell of itself. :) Also brings in a few fixes to never try to open files from the system process. Test: manual Change-Id: Ia8187196af597046fd2e7092dbf19ce1dc1ea457 --- cmds/pm/Android.mk | 10 +- cmds/pm/pm | 8 +- cmds/pm/src/com/android/commands/pm/Pm.java | 822 --------------------- core/java/android/os/ShellCallback.java | 3 + core/java/android/os/ShellCommand.java | 12 +- .../internal/content/NativeLibraryHelper.java | 13 + .../android/internal/content/PackageHelper.java | 9 +- ...ndroid_internal_content_NativeLibraryHelper.cpp | 20 + libs/androidfw/AssetManager.cpp | 32 +- libs/androidfw/include/androidfw/AssetManager.h | 8 +- .../server/pm/PackageManagerShellCommand.java | 2 +- 11 files changed, 83 insertions(+), 856 deletions(-) delete mode 100644 cmds/pm/src/com/android/commands/pm/Pm.java (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/cmds/pm/Android.mk b/cmds/pm/Android.mk index 6a03defc9e2c..960c8052f935 100644 --- a/cmds/pm/Android.mk +++ b/cmds/pm/Android.mk @@ -2,15 +2,9 @@ # LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_MODULE := pmlib -LOCAL_MODULE_STEM := pm -include $(BUILD_JAVA_LIBRARY) - include $(CLEAR_VARS) LOCAL_MODULE := pm -LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_SRC_FILES := pm -LOCAL_REQUIRED_MODULES := pmlib +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional include $(BUILD_PREBUILT) diff --git a/cmds/pm/pm b/cmds/pm/pm index 53f85b2f9c51..4d1f94554a78 100755 --- a/cmds/pm/pm +++ b/cmds/pm/pm @@ -1,8 +1,2 @@ #!/system/bin/sh -# Script to start "pm" on the device, which has a very rudimentary -# shell. -# -base=/system -export CLASSPATH=$base/framework/pm.jar -exec app_process $base/bin com.android.commands.pm.Pm "$@" - +cmd package "$@" diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java deleted file mode 100644 index 9490880afe0f..000000000000 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ /dev/null @@ -1,822 +0,0 @@ -/* - * Copyright (C) 2007 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.commands.pm; - -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; - -import android.accounts.IAccountManager; -import android.app.ActivityManager; -import android.app.PackageInstallObserver; -import android.content.ComponentName; -import android.content.Context; -import android.content.IIntentReceiver; -import android.content.IIntentSender; -import android.content.Intent; -import android.content.IntentSender; -import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageDataObserver; -import android.content.pm.IPackageInstaller; -import android.content.pm.IPackageManager; -import android.content.pm.PackageInfo; -import android.content.pm.PackageInstaller; -import android.content.pm.PackageInstaller.SessionInfo; -import android.content.pm.PackageInstaller.SessionParams; -import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.PackageParser.ApkLite; -import android.content.pm.PackageParser.PackageLite; -import android.content.pm.PackageParser.PackageParserException; -import android.content.pm.UserInfo; -import android.net.Uri; -import android.os.Binder; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.IUserManager; -import android.os.ParcelFileDescriptor; -import android.os.Process; -import android.os.RemoteException; -import android.os.ResultReceiver; -import android.os.SELinux; -import android.os.ServiceManager; -import android.os.ShellCallback; -import android.os.SystemClock; -import android.os.UserHandle; -import android.os.UserManager; -import android.os.storage.StorageManager; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.util.Log; -import android.util.Pair; - -import com.android.internal.content.PackageHelper; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.SizedInputStream; - -import libcore.io.IoUtils; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.TimeUnit; - -public final class Pm { - private static final String TAG = "Pm"; - private static final String STDIN_PATH = "-"; - - IPackageManager mPm; - IPackageInstaller mInstaller; - IUserManager mUm; - IAccountManager mAm; - - private String[] mArgs; - private int mNextArg; - private String mCurArgData; - - private static final String PM_NOT_RUNNING_ERR = - "Error: Could not access the Package Manager. Is the system running?"; - - public static void main(String[] args) { - int exitCode = 1; - try { - exitCode = new Pm().run(args); - } catch (Exception e) { - Log.e(TAG, "Error", e); - System.err.println("Error: " + e); - if (e instanceof RemoteException) { - System.err.println(PM_NOT_RUNNING_ERR); - } - } - System.exit(exitCode); - } - - public int run(String[] args) throws RemoteException { - if (args.length < 1) { - return runShellCommand("package", mArgs); - } - mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE)); - mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE)); - mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); - - if (mPm == null) { - System.err.println(PM_NOT_RUNNING_ERR); - return 1; - } - mInstaller = mPm.getPackageInstaller(); - - mArgs = args; - String op = args[0]; - mNextArg = 1; - - if ("install".equals(op)) { - return runInstall(); - } - - if ("install-create".equals(op)) { - return runInstallCreate(); - } - - if ("install-write".equals(op)) { - return runInstallWrite(); - } - - if ("install-commit".equals(op)) { - return runInstallCommit(); - } - - if ("install-abandon".equals(op) || "install-destroy".equals(op)) { - return runInstallAbandon(); - } - - return runShellCommand("package", mArgs); - } - - static final class MyShellCallback extends ShellCallback { - @Override public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext, - String mode) { - File file = new File(path); - final ParcelFileDescriptor fd; - try { - fd = ParcelFileDescriptor.open(file, - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE | - ParcelFileDescriptor.MODE_WRITE_ONLY); - } catch (FileNotFoundException e) { - String msg = "Unable to open file " + path + ": " + e; - System.err.println(msg); - throw new IllegalArgumentException(msg); - } - if (seLinuxContext != null) { - final String tcon = SELinux.getFileContext(file.getAbsolutePath()); - if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) { - try { - fd.close(); - } catch (IOException e) { - } - String msg = "System server has no access to file context " + tcon; - System.err.println(msg + " (from path " + file.getAbsolutePath() - + ", context " + seLinuxContext + ")"); - throw new IllegalArgumentException(msg); - } - } - return fd; - } - } - - private int runShellCommand(String serviceName, String[] args) { - final HandlerThread handlerThread = new HandlerThread("results"); - handlerThread.start(); - try { - ServiceManager.getService(serviceName).shellCommand( - FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, - args, new MyShellCallback(), - new ResultReceiver(new Handler(handlerThread.getLooper()))); - return 0; - } catch (RemoteException e) { - e.printStackTrace(); - } finally { - handlerThread.quitSafely(); - } - return -1; - } - - private static class LocalIntentReceiver { - private final SynchronousQueue mResult = new SynchronousQueue<>(); - - private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { - @Override - public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, - IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { - try { - mResult.offer(intent, 5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - }; - - public IntentSender getIntentSender() { - return new IntentSender((IIntentSender) mLocalSender); - } - - public Intent getResult() { - try { - return mResult.take(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } - - private int translateUserId(int userId, String logContext) { - return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), - userId, true, true, logContext, "pm command"); - } - - private static String checkAbiArgument(String abi) { - if (TextUtils.isEmpty(abi)) { - throw new IllegalArgumentException("Missing ABI argument"); - } - if ("-".equals(abi)) { - return abi; - } - final String[] supportedAbis = Build.SUPPORTED_ABIS; - for (String supportedAbi : supportedAbis) { - if (supportedAbi.equals(abi)) { - return abi; - } - } - throw new IllegalArgumentException("ABI " + abi + " not supported on this device"); - } - - /* - * Keep this around to support existing users of the "pm install" command that may not be - * able to be updated [or, at least informed the API has changed] such as ddmlib. - * - * Moving the implementation of "pm install" to "cmd package install" changes the executing - * context. Instead of being a stand alone process, "cmd package install" runs in the - * system_server process. Due to SELinux rules, system_server cannot access many directories; - * one of which being the package install staging directory [/data/local/tmp]. - * - * The use of "adb install" or "cmd package install" over "pm install" is highly encouraged. - */ - private int runInstall() throws RemoteException { - long startedTime = SystemClock.elapsedRealtime(); - final InstallParams params = makeInstallParams(); - final String inPath = nextArg(); - if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) { - File file = new File(inPath); - if (file.isFile()) { - try { - ApkLite baseApk = PackageParser.parseApkLite(file, 0); - PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, - null, null); - params.sessionParams.setSize( - PackageHelper.calculateInstalledSize(pkgLite, - params.sessionParams.abiOverride)); - } catch (PackageParserException | IOException e) { - System.err.println("Error: Failed to parse APK file: " + e); - return 1; - } - } else { - System.err.println("Error: Can't open non-file: " + inPath); - return 1; - } - } - - final int sessionId = doCreateSession(params.sessionParams, - params.installerPackageName, params.userId); - - try { - if (inPath == null && params.sessionParams.sizeBytes == -1) { - System.err.println("Error: must either specify a package size or an APK file"); - return 1; - } - if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk", - false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { - return 1; - } - Pair status = doCommitSession(sessionId, false /*logSuccess*/); - if (status.second != PackageInstaller.STATUS_SUCCESS) { - return 1; - } - Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime() - - startedTime) + " ms"); - System.out.println("Success"); - return 0; - } finally { - try { - mInstaller.abandonSession(sessionId); - } catch (Exception ignore) { - } - } - } - - private int runInstallAbandon() throws RemoteException { - final int sessionId = Integer.parseInt(nextArg()); - return doAbandonSession(sessionId, true /*logSuccess*/); - } - - private int runInstallCommit() throws RemoteException { - final int sessionId = Integer.parseInt(nextArg()); - return doCommitSession(sessionId, true /*logSuccess*/).second; - } - - private int runInstallCreate() throws RemoteException { - final InstallParams installParams = makeInstallParams(); - final int sessionId = doCreateSession(installParams.sessionParams, - installParams.installerPackageName, installParams.userId); - - // NOTE: adb depends on parsing this string - System.out.println("Success: created install session [" + sessionId + "]"); - return PackageInstaller.STATUS_SUCCESS; - } - - private int runInstallWrite() throws RemoteException { - long sizeBytes = -1; - - String opt; - while ((opt = nextOption()) != null) { - if (opt.equals("-S")) { - sizeBytes = Long.parseLong(nextArg()); - } else { - throw new IllegalArgumentException("Unknown option: " + opt); - } - } - - final int sessionId = Integer.parseInt(nextArg()); - final String splitName = nextArg(); - final String path = nextArg(); - return doWriteSession(sessionId, path, sizeBytes, splitName, true /*logSuccess*/); - } - - private static class InstallParams { - SessionParams sessionParams; - String installerPackageName; - int userId = UserHandle.USER_ALL; - } - - private InstallParams makeInstallParams() { - final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL); - final InstallParams params = new InstallParams(); - params.sessionParams = sessionParams; - String opt; - while ((opt = nextOption()) != null) { - switch (opt) { - case "-l": - sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK; - break; - case "-r": - sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; - break; - case "-i": - params.installerPackageName = nextArg(); - if (params.installerPackageName == null) { - throw new IllegalArgumentException("Missing installer package"); - } - break; - case "-t": - sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST; - break; - case "-s": - sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL; - break; - case "-f": - sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL; - break; - case "-d": - sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; - break; - case "-g": - sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS; - break; - case "--dont-kill": - sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP; - break; - case "--originating-uri": - sessionParams.originatingUri = Uri.parse(nextOptionData()); - break; - case "--referrer": - sessionParams.referrerUri = Uri.parse(nextOptionData()); - break; - case "-p": - sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING; - sessionParams.appPackageName = nextOptionData(); - if (sessionParams.appPackageName == null) { - throw new IllegalArgumentException("Missing inherit package name"); - } - break; - case "--pkg": - sessionParams.appPackageName = nextOptionData(); - if (sessionParams.appPackageName == null) { - throw new IllegalArgumentException("Missing package name"); - } - break; - case "-S": - final long sizeBytes = Long.parseLong(nextOptionData()); - if (sizeBytes <= 0) { - throw new IllegalArgumentException("Size must be positive"); - } - sessionParams.setSize(sizeBytes); - break; - case "--abi": - sessionParams.abiOverride = checkAbiArgument(nextOptionData()); - break; - case "--ephemeral": - case "--instant": - sessionParams.setInstallAsInstantApp(true /*isInstantApp*/); - break; - case "--full": - sessionParams.setInstallAsInstantApp(false /*isInstantApp*/); - break; - case "--user": - params.userId = UserHandle.parseUserArg(nextOptionData()); - break; - case "--install-location": - sessionParams.installLocation = Integer.parseInt(nextOptionData()); - break; - case "--force-uuid": - sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID; - sessionParams.volumeUuid = nextOptionData(); - if ("internal".equals(sessionParams.volumeUuid)) { - sessionParams.volumeUuid = null; - } - break; - case "--force-sdk": - sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK; - break; - default: - throw new IllegalArgumentException("Unknown option " + opt); - } - } - return params; - } - - private int doCreateSession(SessionParams params, String installerPackageName, int userId) - throws RemoteException { - userId = translateUserId(userId, "runInstallCreate"); - if (userId == UserHandle.USER_ALL) { - userId = UserHandle.USER_SYSTEM; - params.installFlags |= PackageManager.INSTALL_ALL_USERS; - } - - final int sessionId = mInstaller.createSession(params, installerPackageName, userId); - return sessionId; - } - - private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName, - boolean logSuccess) throws RemoteException { - if (STDIN_PATH.equals(inPath)) { - inPath = null; - } else if (inPath != null) { - final File file = new File(inPath); - if (file.isFile()) { - sizeBytes = file.length(); - } - } - - final SessionInfo info = mInstaller.getSessionInfo(sessionId); - - PackageInstaller.Session session = null; - InputStream in = null; - OutputStream out = null; - try { - session = new PackageInstaller.Session( - mInstaller.openSession(sessionId)); - - if (inPath != null) { - in = new FileInputStream(inPath); - } else { - in = new SizedInputStream(System.in, sizeBytes); - } - out = session.openWrite(splitName, 0, sizeBytes); - - int total = 0; - byte[] buffer = new byte[1024 * 1024]; - int c; - while ((c = in.read(buffer)) != -1) { - total += c; - out.write(buffer, 0, c); - - if (info.sizeBytes > 0) { - final float fraction = ((float) c / (float) info.sizeBytes); - session.addProgress(fraction); - } - } - session.fsync(out); - - if (logSuccess) { - System.out.println("Success: streamed " + total + " bytes"); - } - return PackageInstaller.STATUS_SUCCESS; - } catch (IOException e) { - System.err.println("Error: failed to write; " + e.getMessage()); - return PackageInstaller.STATUS_FAILURE; - } finally { - IoUtils.closeQuietly(out); - IoUtils.closeQuietly(in); - IoUtils.closeQuietly(session); - } - } - - private Pair doCommitSession(int sessionId, boolean logSuccess) - throws RemoteException { - PackageInstaller.Session session = null; - try { - session = new PackageInstaller.Session( - mInstaller.openSession(sessionId)); - - final LocalIntentReceiver receiver = new LocalIntentReceiver(); - session.commit(receiver.getIntentSender()); - - final Intent result = receiver.getResult(); - final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); - if (status == PackageInstaller.STATUS_SUCCESS) { - if (logSuccess) { - System.out.println("Success"); - } - } else { - System.err.println("Failure [" - + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); - } - return new Pair<>(result.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME), status); - } finally { - IoUtils.closeQuietly(session); - } - } - - private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException { - PackageInstaller.Session session = null; - try { - session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); - session.abandon(); - if (logSuccess) { - System.out.println("Success"); - } - return PackageInstaller.STATUS_SUCCESS; - } finally { - IoUtils.closeQuietly(session); - } - } - - class LocalPackageInstallObserver extends PackageInstallObserver { - boolean finished; - int result; - String extraPermission; - String extraPackage; - - @Override - public void onPackageInstalled(String name, int status, String msg, Bundle extras) { - synchronized (this) { - finished = true; - result = status; - if (status == PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION) { - extraPermission = extras.getString( - PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION); - extraPackage = extras.getString( - PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); - } - notifyAll(); - } - } - } - - private static boolean isNumber(String s) { - try { - Integer.parseInt(s); - } catch (NumberFormatException nfe) { - return false; - } - return true; - } - - static class ClearCacheObserver extends IPackageDataObserver.Stub { - boolean finished; - boolean result; - - @Override - public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { - synchronized (this) { - finished = true; - result = succeeded; - notifyAll(); - } - } - - } - - static class ClearDataObserver extends IPackageDataObserver.Stub { - boolean finished; - boolean result; - - @Override - public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { - synchronized (this) { - finished = true; - result = succeeded; - notifyAll(); - } - } - } - - /** - * Displays the package file for a package. - * @param pckg - */ - private int displayPackageFilePath(String pckg, int userId) { - try { - PackageInfo info = mPm.getPackageInfo(pckg, 0, userId); - if (info != null && info.applicationInfo != null) { - System.out.print("package:"); - System.out.println(info.applicationInfo.sourceDir); - if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) { - for (String splitSourceDir : info.applicationInfo.splitSourceDirs) { - System.out.print("package:"); - System.out.println(splitSourceDir); - } - } - return 0; - } - } catch (RemoteException e) { - System.err.println(e.toString()); - System.err.println(PM_NOT_RUNNING_ERR); - } - return 1; - } - - private String nextOption() { - if (mNextArg >= mArgs.length) { - return null; - } - String arg = mArgs[mNextArg]; - if (!arg.startsWith("-")) { - return null; - } - mNextArg++; - if (arg.equals("--")) { - return null; - } - if (arg.length() > 1 && arg.charAt(1) != '-') { - if (arg.length() > 2) { - mCurArgData = arg.substring(2); - return arg.substring(0, 2); - } else { - mCurArgData = null; - return arg; - } - } - mCurArgData = null; - return arg; - } - - private String nextOptionData() { - if (mCurArgData != null) { - return mCurArgData; - } - if (mNextArg >= mArgs.length) { - return null; - } - String data = mArgs[mNextArg]; - mNextArg++; - return data; - } - - private String nextArg() { - if (mNextArg >= mArgs.length) { - return null; - } - String arg = mArgs[mNextArg]; - mNextArg++; - return arg; - } - - private static int showUsage() { - System.err.println("usage: pm path [--user USER_ID] PACKAGE"); - System.err.println(" pm dump PACKAGE"); - System.err.println(" pm install [-lrtsfdg] [-i PACKAGE] [--user USER_ID]"); - System.err.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]"); - System.err.println(" [--originating-uri URI] [---referrer URI]"); - System.err.println(" [--abi ABI_NAME] [--force-sdk]"); - System.err.println(" [--preload] [--instantapp] [--full] [--dont-kill]"); - System.err.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [PATH|-]"); - System.err.println(" pm install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID]"); - System.err.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]"); - System.err.println(" [--originating-uri URI] [---referrer URI]"); - System.err.println(" [--abi ABI_NAME] [--force-sdk]"); - System.err.println(" [--preload] [--instantapp] [--full] [--dont-kill]"); - System.err.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]"); - System.err.println(" pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH|-]"); - System.err.println(" pm install-commit SESSION_ID"); - System.err.println(" pm install-abandon SESSION_ID"); - System.err.println(" pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE"); - System.err.println(" pm set-installer PACKAGE INSTALLER"); - System.err.println(" pm move-package PACKAGE [internal|UUID]"); - System.err.println(" pm move-primary-storage [internal|UUID]"); - System.err.println(" pm clear [--user USER_ID] PACKAGE"); - System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT"); - System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT"); - System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT"); - System.err.println(" pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT"); - System.err.println(" pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT"); - System.err.println(" pm set-user-restriction [--user USER_ID] RESTRICTION VALUE"); - System.err.println(" pm hide [--user USER_ID] PACKAGE_OR_COMPONENT"); - System.err.println(" pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT"); - System.err.println(" pm grant [--user USER_ID] PACKAGE PERMISSION"); - System.err.println(" pm revoke [--user USER_ID] PACKAGE PERMISSION"); - System.err.println(" pm reset-permissions"); - System.err.println(" pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}"); - System.err.println(" pm get-app-link [--user USER_ID] PACKAGE"); - System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]"); - System.err.println(" pm get-install-location"); - System.err.println(" pm set-permission-enforced PERMISSION [true|false]"); - System.err.println(" pm trim-caches DESIRED_FREE_SPACE [internal|UUID]"); - System.err.println(" pm create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral] [--guest] USER_NAME"); - System.err.println(" pm remove-user USER_ID"); - System.err.println(" pm get-max-users"); - System.err.println(""); - System.err.println("NOTE: 'pm list' commands have moved! Run 'adb shell cmd package'"); - System.err.println(" to display the new commands."); - System.err.println(""); - System.err.println("pm path: print the path to the .apk of the given PACKAGE."); - System.err.println(""); - System.err.println("pm dump: print system state associated with the given PACKAGE."); - System.err.println(""); - System.err.println("pm install: install a single legacy package"); - System.err.println("pm install-create: create an install session"); - System.err.println(" -l: forward lock application"); - System.err.println(" -r: allow replacement of existing application"); - System.err.println(" -t: allow test packages"); - System.err.println(" -i: specify package name of installer owning the app"); - System.err.println(" -s: install application on sdcard"); - System.err.println(" -f: install application on internal flash"); - System.err.println(" -d: allow version code downgrade (debuggable packages only)"); - System.err.println(" -p: partial application install (new split on top of existing pkg)"); - System.err.println(" -g: grant all runtime permissions"); - System.err.println(" -S: size in bytes of entire session"); - System.err.println(" --dont-kill: installing a new feature split, don't kill running app"); - System.err.println(" --originating-uri: set URI where app was downloaded from"); - System.err.println(" --referrer: set URI that instigated the install of the app"); - System.err.println(" --pkg: specify expected package name of app being installed"); - System.err.println(" --abi: override the default ABI of the platform"); - System.err.println(" --instantapp: cause the app to be installed as an ephemeral install app"); - System.err.println(" --full: cause the app to be installed as a non-ephemeral full app"); - System.err.println(" --install-location: force the install location:"); - System.err.println(" 0=auto, 1=internal only, 2=prefer external"); - System.err.println(" --force-uuid: force install on to disk volume with given UUID"); - System.err.println(" --force-sdk: allow install even when existing app targets platform"); - System.err.println(" codename but new one targets a final API level"); - System.err.println(""); - System.err.println("pm install-write: write a package into existing session; path may"); - System.err.println(" be '-' to read from stdin"); - System.err.println(" -S: size in bytes of package, required for stdin"); - System.err.println(""); - System.err.println("pm install-commit: perform install of fully staged session"); - System.err.println("pm install-abandon: abandon session"); - System.err.println(""); - System.err.println("pm set-installer: set installer package name"); - System.err.println(""); - System.err.println("pm uninstall: removes a package from the system. Options:"); - System.err.println(" -k: keep the data and cache directories around after package removal."); - System.err.println(""); - System.err.println("pm clear: deletes all data associated with a package."); - System.err.println(""); - System.err.println("pm enable, disable, disable-user, disable-until-used, default-state:"); - System.err.println(" these commands change the enabled state of a given package or"); - System.err.println(" component (written as \"package/class\")."); - System.err.println(""); - System.err.println("pm grant, revoke: these commands either grant or revoke permissions"); - System.err.println(" to apps. The permissions must be declared as used in the app's"); - System.err.println(" manifest, be runtime permissions (protection level dangerous),"); - System.err.println(" and the app targeting SDK greater than Lollipop MR1."); - System.err.println(""); - System.err.println("pm reset-permissions: revert all runtime permissions to their default state."); - System.err.println(""); - System.err.println("pm get-install-location: returns the current install location."); - System.err.println(" 0 [auto]: Let system decide the best location"); - System.err.println(" 1 [internal]: Install on internal device storage"); - System.err.println(" 2 [external]: Install on external media"); - System.err.println(""); - System.err.println("pm set-install-location: changes the default install location."); - System.err.println(" NOTE: this is only intended for debugging; using this can cause"); - System.err.println(" applications to break and other undersireable behavior."); - System.err.println(" 0 [auto]: Let system decide the best location"); - System.err.println(" 1 [internal]: Install on internal device storage"); - System.err.println(" 2 [external]: Install on external media"); - System.err.println(""); - System.err.println("pm trim-caches: trim cache files to reach the given free space."); - System.err.println(""); - System.err.println("pm create-user: create a new user with the given USER_NAME,"); - System.err.println(" printing the new user identifier of the user."); - System.err.println(""); - System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,"); - System.err.println(" deleting all data associated with that user"); - System.err.println(""); - return 1; - } -} diff --git a/core/java/android/os/ShellCallback.java b/core/java/android/os/ShellCallback.java index ad9fbfbfae40..6a62424cc117 100644 --- a/core/java/android/os/ShellCallback.java +++ b/core/java/android/os/ShellCallback.java @@ -105,6 +105,9 @@ public class ShellCallback implements Parcelable { ShellCallback(Parcel in) { mLocal = false; mShellCallback = IShellCallback.Stub.asInterface(in.readStrongBinder()); + if (mShellCallback != null) { + Binder.allowBlocking(mShellCallback.asBinder()); + } } public static final Parcelable.Creator CREATOR diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java index d75219fdfd11..fa05a5e1b22e 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -91,7 +91,13 @@ public abstract class ShellCommand { mCmd = cmd; mResultReceiver = resultReceiver; - if (DEBUG) Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget); + if (DEBUG) { + RuntimeException here = new RuntimeException("here"); + here.fillInStackTrace(); + Slog.d(TAG, "Starting command " + mCmd + " on " + mTarget, here); + Slog.d(TAG, "Calling uid=" + Binder.getCallingUid() + + " pid=" + Binder.getCallingPid() + " ShellCallback=" + getShellCallback()); + } int res = -1; try { res = onCommand(mCmd); @@ -227,15 +233,19 @@ public abstract class ShellCommand { * @hide */ public ParcelFileDescriptor openFileForSystem(String path, String mode) { + if (DEBUG) Slog.d(TAG, "openFileForSystem: " + path + " mode=" + mode); try { ParcelFileDescriptor pfd = getShellCallback().openFile(path, "u:r:system_server:s0", mode); if (pfd != null) { + if (DEBUG) Slog.d(TAG, "Got file: " + pfd); return pfd; } } catch (RuntimeException e) { + if (DEBUG) Slog.d(TAG, "Failure opening file: " + e.getMessage()); getErrPrintWriter().println("Failure opening file: " + e.getMessage()); } + if (DEBUG) Slog.d(TAG, "Error: Unable to open file: " + path); getErrPrintWriter().println("Error: Unable to open file: " + path); getErrPrintWriter().println("Consider using a file under /data/local/tmp/"); return null; diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 83b7d2f948f8..a1e6fd8e22f9 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -43,6 +43,7 @@ import dalvik.system.VMRuntime; import java.io.Closeable; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.util.List; @@ -118,6 +119,17 @@ public class NativeLibraryHelper { return new Handle(apkHandles, multiArch, extractNativeLibs, debuggable); } + public static Handle createFd(PackageLite lite, FileDescriptor fd) throws IOException { + final long[] apkHandles = new long[1]; + final String path = lite.baseCodePath; + apkHandles[0] = nativeOpenApkFd(fd, path); + if (apkHandles[0] == 0) { + throw new IOException("Unable to open APK " + path + " from fd " + fd); + } + + return new Handle(apkHandles, lite.multiArch, lite.extractNativeLibs, lite.debuggable); + } + Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs, boolean debuggable) { this.apkHandles = apkHandles; @@ -152,6 +164,7 @@ public class NativeLibraryHelper { } private static native long nativeOpenApk(String path); + private static native long nativeOpenApkFd(FileDescriptor fd, String debugPath); private static native void nativeClose(long handle); private static native long nativeSumNativeBinaries(long handle, String cpuAbi, diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 59a7995ab2ac..e765ab1eae2f 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -42,6 +42,7 @@ import com.android.internal.annotations.VisibleForTesting; import libcore.io.IoUtils; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.util.Objects; import java.util.UUID; @@ -383,9 +384,15 @@ public class PackageHelper { public static long calculateInstalledSize(PackageLite pkg, String abiOverride) throws IOException { + return calculateInstalledSize(pkg, abiOverride, null); + } + + public static long calculateInstalledSize(PackageLite pkg, String abiOverride, + FileDescriptor fd) throws IOException { NativeLibraryHelper.Handle handle = null; try { - handle = NativeLibraryHelper.Handle.create(pkg); + handle = fd != null ? NativeLibraryHelper.Handle.createFd(pkg, fd) + : NativeLibraryHelper.Handle.create(pkg); return calculateInstalledSize(pkg, handle, abiOverride); } finally { IoUtils.closeQuietly(handle); diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index fce5dd58d7f9..17b98dade74f 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -557,6 +557,23 @@ com_android_internal_content_NativeLibraryHelper_openApk(JNIEnv *env, jclass, js return reinterpret_cast(zipFile); } +static jlong +com_android_internal_content_NativeLibraryHelper_openApkFd(JNIEnv *env, jclass, + jobject fileDescriptor, jstring debugPathName) +{ + ScopedUtfChars debugFilePath(env, debugPathName); + + int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); + if (fd < 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor"); + return 0; + } + + ZipFileRO* zipFile = ZipFileRO::openFd(fd, debugFilePath.c_str()); + + return reinterpret_cast(zipFile); +} + static void com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlong apkHandle) { @@ -567,6 +584,9 @@ static const JNINativeMethod gMethods[] = { {"nativeOpenApk", "(Ljava/lang/String;)J", (void *)com_android_internal_content_NativeLibraryHelper_openApk}, + {"nativeOpenApkFd", + "(Ljava/io/FileDescriptor;Ljava/lang/String;)J", + (void *)com_android_internal_content_NativeLibraryHelper_openApkFd}, {"nativeClose", "(J)V", (void *)com_android_internal_content_NativeLibraryHelper_close}, diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 3c8736ea0c4c..0485625e81e8 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -148,11 +148,15 @@ AssetManager::~AssetManager() { int count = android_atomic_dec(&gCount); if (kIsDebug) { ALOGI("Destroying AssetManager in %p #%d\n", this, count); + } else { + ALOGV("Destroying AssetManager in %p #%d\n", this, count); } // Manually close any fd paths for which we have not yet opened their zip (which // will take ownership of the fd and close it when done). for (size_t i=0; i= 0 && mAssetPaths[i].zip == NULL) { close(mAssetPaths[i].rawFd); } @@ -202,7 +206,7 @@ bool AssetManager::addAssetPath( ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string()); ap.isSystemAsset = isSystemAsset; - mAssetPaths.add(ap); + ssize_t apPos = mAssetPaths.add(ap); // new paths are always added at the end if (cookie) { @@ -219,7 +223,7 @@ bool AssetManager::addAssetPath( #endif if (mResources != NULL) { - appendPathToResTable(ap, appAsLib); + appendPathToResTable(mAssetPaths.editItemAt(apPos), appAsLib); } return true; @@ -304,7 +308,7 @@ bool AssetManager::addAssetFd( ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.string()); - mAssetPaths.add(ap); + ssize_t apPos = mAssetPaths.add(ap); // new paths are always added at the end if (cookie) { @@ -312,7 +316,7 @@ bool AssetManager::addAssetFd( } if (mResources != NULL) { - appendPathToResTable(ap, appAsLib); + appendPathToResTable(mAssetPaths.editItemAt(apPos), appAsLib); } return true; @@ -442,7 +446,8 @@ Asset* AssetManager::open(const char* fileName, AccessMode mode) i--; ALOGV("Looking for asset '%s' in '%s'\n", assetName.string(), mAssetPaths.itemAt(i).path.string()); - Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, mAssetPaths.itemAt(i)); + Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode, + mAssetPaths.editItemAt(i)); if (pAsset != NULL) { return pAsset != kExcludedAsset ? pAsset : NULL; } @@ -471,7 +476,7 @@ Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode, int32_t i--; ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string()); Asset* pAsset = openNonAssetInPathLocked( - fileName, mode, mAssetPaths.itemAt(i)); + fileName, mode, mAssetPaths.editItemAt(i)); if (pAsset != NULL) { if (outCookie != NULL) *outCookie = static_cast(i + 1); return pAsset != kExcludedAsset ? pAsset : NULL; @@ -493,7 +498,7 @@ Asset* AssetManager::openNonAsset(const int32_t cookie, const char* fileName, Ac ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(which).path.string()); Asset* pAsset = openNonAssetInPathLocked( - fileName, mode, mAssetPaths.itemAt(which)); + fileName, mode, mAssetPaths.editItemAt(which)); if (pAsset != NULL) { return pAsset != kExcludedAsset ? pAsset : NULL; } @@ -527,7 +532,7 @@ FileType AssetManager::getFileType(const char* fileName) } } -bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const { +bool AssetManager::appendPathToResTable(asset_path& ap, bool appAsLib) const { // skip those ap's that correspond to system overlays if (ap.isSystemOverlay) { return true; @@ -645,7 +650,8 @@ const ResTable* AssetManager::getResTable(bool required) const bool onlyEmptyResources = true; const size_t N = mAssetPaths.size(); for (size_t i=0; i(this)->mAssetPaths.editItemAt(i)); onlyEmptyResources = onlyEmptyResources && empty; } @@ -770,7 +776,7 @@ void AssetManager::getLocales(Vector* locales, bool includeSystemLocale * be used. */ Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode, - const asset_path& ap) + asset_path& ap) { Asset* pAsset = NULL; @@ -851,17 +857,19 @@ String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* roo * Return a pointer to one of our open Zip archives. Returns NULL if no * matching Zip file exists. */ -ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap) +ZipFileRO* AssetManager::getZipFileLocked(asset_path& ap) { - ALOGV("getZipFileLocked() in %p\n", this); + ALOGV("getZipFileLocked() in %p: ap=%p zip=%p", this, &ap, ap.zip.get()); if (ap.zip != NULL) { return ap.zip->getZip(); } if (ap.rawFd < 0) { + ALOGV("getZipFileLocked: Creating new zip from path %s", ap.path.string()); ap.zip = mZipSet.getSharedZip(ap.path); } else { + ALOGV("getZipFileLocked: Creating new zip from fd %d", ap.rawFd); ap.zip = SharedZip::create(ap.rawFd, ap.path); } diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index 4254614c8448..ecc5dc1ad331 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -222,16 +222,16 @@ private: bool isSystemOverlay; bool isSystemAsset; bool assumeOwnership; - mutable sp zip; + sp zip; }; Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode, - const asset_path& path); + asset_path& path); String8 createPathNameLocked(const asset_path& path, const char* rootDir); String8 createZipSourceNameLocked(const String8& zipFileName, const String8& dirName, const String8& fileName); - ZipFileRO* getZipFileLocked(const asset_path& path); + ZipFileRO* getZipFileLocked(asset_path& path); Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode); Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile, const ZipEntryRO entry, AccessMode mode, const String8& entryName); @@ -247,7 +247,7 @@ private: const ResTable* getResTable(bool required = true) const; void setLocaleLocked(const char* locale); void updateResourceParamsLocked() const; - bool appendPathToResTable(const asset_path& ap, bool appAsLib=false) const; + bool appendPathToResTable(asset_path& ap, bool appAsLib=false) const; Asset* openIdmapLocked(const struct asset_path& ap) const; diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 807eb1a8aac4..0b9514ab6627 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -264,7 +264,7 @@ class PackageManagerShellCommand extends ShellCommand { PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, null, null); params.sessionParams.setSize(PackageHelper.calculateInstalledSize( - pkgLite, params.sessionParams.abiOverride)); + pkgLite, params.sessionParams.abiOverride, fd.getFileDescriptor())); } catch (PackageParserException | IOException e) { getErrPrintWriter().println("Error: Failed to parse APK file: " + inPath); throw new IllegalArgumentException( -- cgit v1.2.3-59-g8ed1b From 1713d9e97aada3dc695800c18b1025238a11629d Mon Sep 17 00:00:00 2001 From: Jaekyun Seok Date: Fri, 12 Jan 2018 21:47:26 +0900 Subject: Support /product partition This CL will support the followings. - installing a RRO package for framework from /product/overlay - installing apps from /product/app - installing priv-apps from /product/priv-app - installing permissions from /product/etc/[default-permissions|permissions|sysconfig] Bug: 64195575 Test: `mm` under frameworks/base/tests/[libs|privapp]-permissions adb sync && adb reboot adb shell cmd package list libraries => confirmed com.android.test.libs.product library adb shell cmd package dump \ com.android.framework.permission.privapp.tests.product => confirmed that the package is a priv-app And I moved vendor/overlay/framework-res__auto_generated_rro.apk into system/product/overlay/ on sailfish, and I confirmed that the RRO was installed properly. Change-Id: I16175933cebd9ec665d190cc5d564b5414a91827 --- core/java/android/content/pm/ApplicationInfo.java | 13 +++ core/java/android/content/pm/PackageParser.java | 5 + core/java/android/os/Environment.java | 12 +++ core/java/com/android/server/SystemConfig.java | 26 +++++- core/jni/android_util_AssetManager.cpp | 4 + core/jni/fd_utils.cpp | 6 +- libs/androidfw/AssetManager.cpp | 1 + libs/androidfw/include/androidfw/AssetManager.h | 1 + .../com/android/server/pm/OtaDexoptService.java | 7 +- .../android/server/pm/PackageManagerService.java | 102 +++++++++++++++++++-- .../server/pm/PackageManagerShellCommand.java | 31 +++++-- .../java/com/android/server/pm/PackageSetting.java | 4 + .../java/com/android/server/pm/SettingBase.java | 1 + .../core/java/com/android/server/pm/Settings.java | 3 + .../permission/DefaultPermissionGrantPolicy.java | 4 + .../pm/permission/PermissionManagerService.java | 29 ++++-- tests/libs-permissions/Android.mk | 15 +++ .../product/com.android.test.libs.product.xml | 20 ++++ .../android/test/libs/product/LibsProductTest.java | 29 ++++++ tests/privapp-permissions/Android.mk | 14 +++ .../product/AndroidManifest.xml | 23 +++++ .../product/privapp-permissions-test.xml | 6 ++ 22 files changed, 331 insertions(+), 25 deletions(-) create mode 100644 tests/libs-permissions/Android.mk create mode 100644 tests/libs-permissions/product/com.android.test.libs.product.xml create mode 100644 tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java create mode 100644 tests/privapp-permissions/product/AndroidManifest.xml create mode 100644 tests/privapp-permissions/product/privapp-permissions-test.xml (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 746a090264c2..f6697e8148a0 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -602,6 +602,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_VENDOR = 1 << 18; + /** + * Value for {@linl #privateFlags}: whether this app is pre-installed on the + * product partition of the system image. + * @hide + */ + public static final int PRIVATE_FLAG_PRODUCT = 1 << 19; + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -619,6 +626,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_OEM, PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, PRIVATE_FLAG_PRIVILEGED, + PRIVATE_FLAG_PRODUCT, PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, PRIVATE_FLAG_STATIC_SHARED_LIBRARY, PRIVATE_FLAG_VENDOR, @@ -1699,6 +1707,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; } + /** @hide */ + public boolean isProduct() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; + } + /** * Returns whether or not this application was installed as a virtual preload. */ diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index c705ef52f6b5..d1ce72ed1011 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -6378,6 +6378,11 @@ public class PackageParser { return applicationInfo.isVendor(); } + /** @hide */ + public boolean isProduct() { + return applicationInfo.isProduct(); + } + /** @hide */ public boolean isPrivileged() { return applicationInfo.isPrivilegedApp(); diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 62731e84a401..d543a0222d46 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -41,6 +41,7 @@ public class Environment { private static final String ENV_OEM_ROOT = "OEM_ROOT"; private static final String ENV_ODM_ROOT = "ODM_ROOT"; private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT"; + private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT"; /** {@hide} */ public static final String DIR_ANDROID = "Android"; @@ -62,6 +63,7 @@ public class Environment { private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem"); private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm"); private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor"); + private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product"); private static UserEnvironment sCurrentUser; private static boolean sUserRequired; @@ -179,6 +181,16 @@ public class Environment { return DIR_VENDOR_ROOT; } + /** + * Return root directory of the "product" partition holding product-specific + * customizations if any. If present, the partition is mounted read-only. + * + * @hide + */ + public static File getProductDirectory() { + return DIR_PRODUCT_ROOT; + } + /** * Return the system directory for a user. This is for use by system * services to store files relating to the user. This directory will be diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index c5af89727575..111934f9d005 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -149,6 +149,9 @@ public class SystemConfig { final ArrayMap> mVendorPrivAppPermissions = new ArrayMap<>(); final ArrayMap> mVendorPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap> mProductPrivAppPermissions = new ArrayMap<>(); + final ArrayMap> mProductPrivAppDenyPermissions = new ArrayMap<>(); + final ArrayMap> mOemPermissions = new ArrayMap<>(); public static SystemConfig getInstance() { @@ -240,6 +243,14 @@ public class SystemConfig { return mVendorPrivAppDenyPermissions.get(packageName); } + public ArraySet getProductPrivAppPermissions(String packageName) { + return mProductPrivAppPermissions.get(packageName); + } + + public ArraySet getProductPrivAppDenyPermissions(String packageName) { + return mProductPrivAppDenyPermissions.get(packageName); + } + public Map getOemPermissions(String packageName) { final Map oemPermissions = mOemPermissions.get(packageName); if (oemPermissions != null) { @@ -278,6 +289,14 @@ public class SystemConfig { Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); readPermissions(Environment.buildPath( Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag); + + // Allow Product to customize system configs around libs, features, permissions and apps + int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS | + ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS; + readPermissions(Environment.buildPath( + Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag); + readPermissions(Environment.buildPath( + Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag); } void readPermissions(File libraryDir, int permissionFlag) { @@ -598,15 +617,20 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) { - // privapp permissions from system and vendor partitions are stored + // privapp permissions from system, vendor and product partitions are stored // separately. This is to prevent xml files in the vendor partition from // granting permissions to priv apps in the system partition and vice // versa. boolean vendor = permFile.toPath().startsWith( Environment.getVendorDirectory().toPath()); + boolean product = permFile.toPath().startsWith( + Environment.getProductDirectory().toPath()); if (vendor) { readPrivAppPermissions(parser, mVendorPrivAppPermissions, mVendorPrivAppDenyPermissions); + } else if (product) { + readPrivAppPermissions(parser, mProductPrivAppPermissions, + mProductPrivAppDenyPermissions); } else { readPrivAppPermissions(parser, mPrivAppPermissions, mPrivAppDenyPermissions); diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 403937be7088..7e17a4909cee 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -174,6 +174,10 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::OVERLAY_DIR; } + if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR; + } + // Finally, invoke idmap (if any overlay directory exists) if (argc > 5) { execv(AssetManager::IDMAP_BIN, (char* const*)argv); diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 956b7249660f..3b7b14c58d0a 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -85,11 +85,15 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kOverlayDir = "/system/vendor/overlay/"; static const char* kVendorOverlayDir = "/vendor/overlay"; static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/"; + static const char* kSystemProductOverlayDir = "/system/product/overlay/"; + static const char* kProductOverlayDir = "/product/overlay"; static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) || android::base::StartsWith(path, kOverlaySubdir) - || android::base::StartsWith(path, kVendorOverlayDir)) + || android::base::StartsWith(path, kVendorOverlayDir) + || android::base::StartsWith(path, kSystemProductOverlayDir) + || android::base::StartsWith(path, kProductOverlayDir)) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 0485625e81e8..a5698af18f6b 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -73,6 +73,7 @@ static volatile int32_t gCount = 0; const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; +const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index ecc5dc1ad331..08da7319de85 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -60,6 +60,7 @@ public: static const char* RESOURCES_FILENAME; static const char* IDMAP_BIN; static const char* OVERLAY_DIR; + static const char* PRODUCT_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay * APKs in OVERLAY_DIR/ in addition to diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 03950119ea13..4fddec9c133e 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -361,9 +361,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub { continue; } - // If the path is in /system or /vendor, ignore. It will have been ota-dexopted into - // /data/ota and moved into the dalvik-cache already. - if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")) { + // If the path is in /system, /vendor or /product, ignore. It will have been + // ota-dexopted into /data/ota and moved into the dalvik-cache already. + if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor") + || pkg.codePath.startsWith("/product")) { continue; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5dfd3ae4b8e8..704646571f06 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -464,6 +464,7 @@ public class PackageManagerService extends IPackageManager.Stub static final int SCAN_AS_PRIVILEGED = 1<<18; static final int SCAN_AS_OEM = 1<<19; static final int SCAN_AS_VENDOR = 1<<20; + static final int SCAN_AS_PRODUCT = 1<<21; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -568,6 +569,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay"; + private static final String PRODUCT_OVERLAY_DIR = "/product/overlay"; + private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob"; /** Canonical intent used to identify what counts as a "web browser" app */ @@ -2550,7 +2553,7 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE; } - // Collect vendor overlay packages. (Do this before scanning any apps.) + // Collect vendor/product overlay packages. (Do this before scanning any apps.) // For security and version matching reason, only consider // overlay packages if they reside in the right directory. scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), @@ -2560,6 +2563,13 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM | SCAN_AS_VENDOR, 0); + scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR), + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT, + 0); mParallelPackageParserCallback.findStaticOverlayPackages(); @@ -2593,8 +2603,7 @@ public class PackageManagerService extends IPackageManager.Stub 0); // Collected privileged vendor packages. - File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), - "priv-app"); + File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); try { privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile(); } catch (IOException e) { @@ -2634,6 +2643,37 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_OEM, 0); + // Collected privileged product packages. + File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app"); + try { + privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(privilegedProductAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT + | SCAN_AS_PRIVILEGED, + 0); + + // Collect ordinary product packages. + File productAppDir = new File(Environment.getProductDirectory(), "app"); + try { + productAppDir = productAppDir.getCanonicalFile(); + } catch (IOException e) { + // failed to look up canonical path, continue with original one + } + scanDirTracedLI(productAppDir, + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT, + 0); + // Prune any system packages that no longer exist. final List possiblyDeletedUpdatedSystemApps = new ArrayList<>(); // Stub packages must either be replaced with full versions in the /data @@ -2840,6 +2880,23 @@ Slog.e("TODD", scanFlags | SCAN_AS_SYSTEM | SCAN_AS_OEM; + } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) { + reparseFlags = + mDefParseFlags | + PackageParser.PARSE_IS_SYSTEM_DIR; + rescanFlags = + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT + | SCAN_AS_PRIVILEGED; + } else if (FileUtils.contains(productAppDir, scanFile)) { + reparseFlags = + mDefParseFlags | + PackageParser.PARSE_IS_SYSTEM_DIR; + rescanFlags = + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_PRODUCT; } else { Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile); continue; @@ -9826,6 +9883,7 @@ Slog.e("TODD", *
  • {@link #SCAN_AS_PRIVILEGED}
  • *
  • {@link #SCAN_AS_OEM}
  • *
  • {@link #SCAN_AS_VENDOR}
  • + *
  • {@link #SCAN_AS_PRODUCT}
  • *
  • {@link #SCAN_AS_INSTANT_APP}
  • *
  • {@link #SCAN_AS_VIRTUAL_PRELOAD}
  • * @@ -9848,6 +9906,10 @@ Slog.e("TODD", & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) { scanFlags |= SCAN_AS_VENDOR; } + if ((disabledPkgSetting.pkgPrivateFlags + & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) { + scanFlags |= SCAN_AS_PRODUCT; + } } if (pkgSetting != null) { final int userId = ((user == null) ? 0 : user.getIdentifier()); @@ -10626,6 +10688,10 @@ Slog.e("TODD", pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR; } + if ((scanFlags & SCAN_AS_PRODUCT) != 0) { + pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT; + } + if (!isSystemApp(pkg)) { // Only system apps can use these features. pkg.mOriginalPackages = null; @@ -11672,6 +11738,8 @@ Slog.e("TODD", codeRoot = Environment.getOemDirectory(); } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) { codeRoot = Environment.getVendorDirectory(); + } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) { + codeRoot = Environment.getProductDirectory(); } else { // Unrecognized code path; take its top real segment as the apk root: // e.g. /something/app/blah.apk => /something @@ -16074,7 +16142,7 @@ Slog.e("TODD", boolean sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { - // Set the system/privileged/oem/vendor flags as needed + // Set the system/privileged/oem/vendor/product flags as needed final boolean privileged = (oldPackage.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; @@ -16084,12 +16152,16 @@ Slog.e("TODD", final boolean vendor = (oldPackage.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + final boolean product = + (oldPackage.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; final @ParseFlags int systemParseFlags = parseFlags; final @ScanFlags int systemScanFlags = scanFlags | SCAN_AS_SYSTEM | (privileged ? SCAN_AS_PRIVILEGED : 0) | (oem ? SCAN_AS_OEM : 0) - | (vendor ? SCAN_AS_VENDOR : 0); + | (vendor ? SCAN_AS_VENDOR : 0) + | (product ? SCAN_AS_PRODUCT : 0); replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags, user, allUsers, installerPackageName, res, installReason); @@ -17339,6 +17411,10 @@ Slog.e("TODD", return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; } + private static boolean isProductApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; + } + private static boolean hasDomainURLs(PackageParser.Package pkg) { return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; } @@ -18078,8 +18154,10 @@ Slog.e("TODD", try { final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app"); + final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app"); return path.startsWith(privilegedAppDir.getCanonicalPath()) - || path.startsWith(privilegedVendorAppDir.getCanonicalPath()); + || path.startsWith(privilegedVendorAppDir.getCanonicalPath()) + || path.startsWith(privilegedProductAppDir.getCanonicalPath()); } catch (IOException e) { Slog.e(TAG, "Unable to access code path " + path); } @@ -18104,6 +18182,15 @@ Slog.e("TODD", return false; } + static boolean locationIsProduct(String path) { + try { + return path.startsWith(Environment.getProductDirectory().getCanonicalPath()); + } catch (IOException e) { + Slog.e(TAG, "Unable to access code path " + path); + } + return false; + } + /* * Tries to delete system package. */ @@ -18228,6 +18315,9 @@ Slog.e("TODD", if (locationIsVendor(codePathString)) { scanFlags |= SCAN_AS_VENDOR; } + if (locationIsProduct(codePathString)) { + scanFlags |= SCAN_AS_PRODUCT; + } final File codePath = new File(codePathString); final PackageParser.Package pkg = diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 47cd81326932..686c4a5eb321 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1555,6 +1555,15 @@ class PackageManagerShellCommand extends ShellCommand { } } + private boolean isProductApp(String pkg) { + try { + final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM); + return info != null && info.applicationInfo.isProduct(); + } catch (RemoteException e) { + return false; + } + } + private int runGetPrivappPermissions() { final String pkg = getNextArg(); if (pkg == null) { @@ -1562,9 +1571,14 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } - ArraySet privAppPermissions = isVendorApp(pkg) ? - SystemConfig.getInstance().getVendorPrivAppPermissions(pkg) - : SystemConfig.getInstance().getPrivAppPermissions(pkg); + ArraySet privAppPermissions = null; + if (isVendorApp(pkg)) { + privAppPermissions = SystemConfig.getInstance().getVendorPrivAppPermissions(pkg); + } else if (isProductApp(pkg)) { + privAppPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg); + } else { + privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg); + } getOutPrintWriter().println(privAppPermissions == null ? "{}" : privAppPermissions.toString()); @@ -1578,9 +1592,14 @@ class PackageManagerShellCommand extends ShellCommand { return 1; } - ArraySet privAppPermissions = isVendorApp(pkg) ? - SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg) - : SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); + ArraySet privAppPermissions = null; + if (isVendorApp(pkg)) { + privAppPermissions = SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg); + } else if (isProductApp(pkg)) { + privAppPermissions = SystemConfig.getInstance().getProductPrivAppDenyPermissions(pkg); + } else { + privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); + } getOutPrintWriter().println(privAppPermissions == null ? "{}" : privAppPermissions.toString()); diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 2a2430c07980..3e2bd4a1b3ba 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -173,6 +173,10 @@ public final class PackageSetting extends PackageSettingBase { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; } + public boolean isProduct() { + return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; + } + public boolean isForwardLocked() { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; } diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index 46ba0060d93e..7c92045c7c5e 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -62,6 +62,7 @@ abstract class SettingBase { & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED | ApplicationInfo.PRIVATE_FLAG_OEM | ApplicationInfo.PRIVATE_FLAG_VENDOR + | ApplicationInfo.PRIVATE_FLAG_PRODUCT | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 8ce412e5783a..5e9019dfea04 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -851,6 +851,8 @@ public final class Settings { pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR; + pkgSetting.pkgPrivateFlags |= + pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT; pkgSetting.primaryCpuAbiString = primaryCpuAbi; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; if (childPkgNames != null) { @@ -4397,6 +4399,7 @@ public final class Settings { ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER", ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY", ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR", + ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT", ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD", }; diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 6e07eaac9c44..e2123c25dd81 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -1215,6 +1215,10 @@ public final class DefaultPermissionGrantPolicy { if (dir.isDirectory() && dir.canRead()) { Collections.addAll(ret, dir.listFiles()); } + dir = new File(Environment.getProductDirectory(), "etc/default-permissions"); + if (dir.isDirectory() && dir.canRead()) { + Collections.addAll(ret, dir.listFiles()); + } return ret.isEmpty() ? null : ret.toArray(new File[0]); } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 786b998862de..cb3b1073a593 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -954,9 +954,16 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); *

    This handles parent/child apps. */ private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) { - ArraySet wlPermissions = pkg.isVendor() ? - SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName) - : SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName); + ArraySet wlPermissions = null; + if (pkg.isVendor()) { + wlPermissions = + SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName); + } else if (pkg.isProduct()) { + wlPermissions = + SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName); + } else { + wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName); + } // Let's check if this package is whitelisted... boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm); // If it's not, we'll also tail-recurse to the parent. @@ -979,11 +986,17 @@ Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); // Only report violations for apps on system image if (!mSystemReady && !pkg.isUpdatedSystemApp()) { // it's only a reportable violation if the permission isn't explicitly denied - final ArraySet deniedPermissions = pkg.isVendor() ? - SystemConfig.getInstance() - .getVendorPrivAppDenyPermissions(pkg.packageName) - : SystemConfig.getInstance() - .getPrivAppDenyPermissions(pkg.packageName); + ArraySet deniedPermissions = null; + if (pkg.isVendor()) { + deniedPermissions = SystemConfig.getInstance() + .getVendorPrivAppDenyPermissions(pkg.packageName); + } else if (pkg.isProduct()) { + deniedPermissions = SystemConfig.getInstance() + .getProductPrivAppDenyPermissions(pkg.packageName); + } else { + deniedPermissions = SystemConfig.getInstance() + .getPrivAppDenyPermissions(pkg.packageName); + } final boolean permissionViolation = deniedPermissions == null || !deniedPermissions.contains(perm); if (permissionViolation) { diff --git a/tests/libs-permissions/Android.mk b/tests/libs-permissions/Android.mk new file mode 100644 index 000000000000..eb3862390338 --- /dev/null +++ b/tests/libs-permissions/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.test.libs.product +LOCAL_PRODUCT_MODULE := true +LOCAL_SRC_FILES := $(call all-java-files-under, product/java) +LOCAL_REQUIRED_MODULES := com.android.test.libs.product.xml +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.test.libs.product.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions +LOCAL_SRC_FILES:= product/com.android.test.libs.product.xml +include $(BUILD_PREBUILT) diff --git a/tests/libs-permissions/product/com.android.test.libs.product.xml b/tests/libs-permissions/product/com.android.test.libs.product.xml new file mode 100644 index 000000000000..0a955e9df7fd --- /dev/null +++ b/tests/libs-permissions/product/com.android.test.libs.product.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java b/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java new file mode 100644 index 000000000000..f49b46e72c25 --- /dev/null +++ b/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018 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.test.libs.product; + +/** + * Test class for product libs. + */ +public class LibsProductTest { + + /** + * Dummpy method for testing. + */ + public static void test() { + } +} diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk index b001c8c466a9..3c80ad8587af 100644 --- a/tests/privapp-permissions/Android.mk +++ b/tests/privapp-permissions/Android.mk @@ -29,3 +29,17 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/permissions LOCAL_SRC_FILES:= vendor/privapp-permissions-test.xml include $(BUILD_PREBUILT) +include $(CLEAR_VARS) +LOCAL_PACKAGE_NAME := ProductPrivAppPermissionTest +LOCAL_PRIVILEGED_MODULE := true +LOCAL_MANIFEST_FILE := product/AndroidManifest.xml +LOCAL_PRODUCT_MODULE := true +LOCAL_REQUIRED_MODULES := productprivapp-permissions-test.xml +include $(BUILD_PACKAGE) + +include $(CLEAR_VARS) +LOCAL_MODULE := productprivapp-permissions-test.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions +LOCAL_SRC_FILES:= product/privapp-permissions-test.xml +include $(BUILD_PREBUILT) diff --git a/tests/privapp-permissions/product/AndroidManifest.xml b/tests/privapp-permissions/product/AndroidManifest.xml new file mode 100644 index 000000000000..3d9415c3df41 --- /dev/null +++ b/tests/privapp-permissions/product/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + diff --git a/tests/privapp-permissions/product/privapp-permissions-test.xml b/tests/privapp-permissions/product/privapp-permissions-test.xml new file mode 100644 index 000000000000..f298f9da41b7 --- /dev/null +++ b/tests/privapp-permissions/product/privapp-permissions-test.xml @@ -0,0 +1,6 @@ + + + + + + -- cgit v1.2.3-59-g8ed1b