Merge "Allow only selected priv apps to run OOB" into pi-dev

am: 792d36c170

Change-Id: Iad80a321e1b76f19935a23290594a36fd057840c
This commit is contained in:
Victor Hsieh
2018-05-09 12:37:38 -07:00
committed by android-build-merger
8 changed files with 179 additions and 92 deletions

View File

@@ -8909,6 +8909,14 @@ public final class Settings {
*/
public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled";
/**
* Comma separated list of privileged package names, which will be running out-of-box APK.
* Default: "ALL"
*
* @hide
*/
public static final String PRIV_APP_OOB_LIST = "priv_app_oob_list";
/**
* The interval in milliseconds at which location requests will be throttled when they are
* coming from the background.

View File

@@ -358,6 +358,7 @@ public class SettingsBackupTest {
Settings.Global.POWER_MANAGER_CONSTANTS,
Settings.Global.PREFERRED_NETWORK_MODE,
Settings.Global.PRIV_APP_OOB_ENABLED,
Settings.Global.PRIV_APP_OOB_LIST,
Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
Settings.Global.RADIO_BLUETOOTH,
Settings.Global.RADIO_CELL,

View File

@@ -466,6 +466,7 @@ import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
import com.android.server.utils.PriorityDump;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.PinnedStackWindowController;
@@ -4311,7 +4312,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
if (app.info.isPrivilegedApp() &&
SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
DexManager.isPackageSelectedToRunOob(app.pkgList.keySet())) {
runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
}

View File

@@ -34,6 +34,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.DexoptUtils;
import com.android.server.pm.dex.PackageDexUsage;
@@ -495,10 +496,9 @@ public class PackageDexOptimizer {
boolean isUsedByOtherApps) {
int flags = info.flags;
boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
// When pm.dexopt.priv-apps-oob is true, we only verify privileged apps.
if (info.isPrivilegedApp() &&
SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
return "verify";
// When a priv app is configured to run out of box, only verify it.
if (info.isPrivilegedApp() && DexManager.isPackageSelectedToRunOob(info.packageName)) {
return "verify";
}
if (vmSafeMode) {
return getSafeModeCompilerFilter(targetCompilerFilter);

View File

@@ -578,8 +578,6 @@ public class PackageManagerService extends IPackageManager.Stub
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 */
private static final Intent sBrowserIntent;
static {
@@ -2459,7 +2457,7 @@ public class PackageManagerService extends IPackageManager.Stub
"*dexopt*");
DexManager.Listener dexManagerListener = DexLogger.getListener(this,
installer, mInstallLock);
mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock,
mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock,
dexManagerListener);
mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
@@ -10428,11 +10426,7 @@ public class PackageManagerService extends IPackageManager.Stub
Log.d(TAG, "Scanning package " + pkg.packageName);
}
if (Build.IS_DEBUGGABLE &&
pkg.isPrivileged() &&
SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
}
DexManager.maybeLogUnexpectedPackageDetails(pkg);
// Initialize package source and resource directories
final File scanFile = new File(pkg.codePath);
@@ -21038,23 +21032,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
.getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
co.onChange(true);
// This observer provides an one directional mapping from Global.PRIV_APP_OOB_ENABLED to
// pm.dexopt.priv-apps-oob property. This is only for experiment and should be removed once
// it is done.
ContentObserver privAppOobObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
int oobEnabled = Global.getInt(resolver, Global.PRIV_APP_OOB_ENABLED, 0);
SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB,
oobEnabled == 1 ? "true" : "false");
}
};
mContext.getContentResolver().registerContentObserver(
Global.getUriFor(Global.PRIV_APP_OOB_ENABLED), false, privAppOobObserver,
UserHandle.USER_SYSTEM);
// At boot, restore the value from the setting, which persists across reboot.
privAppOobObserver.onChange(true);
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
@@ -21143,6 +21120,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
storage.registerListener(mStorageListener);
mInstallerService.systemReady();
mDexManager.systemReady();
mPackageDexOptimizer.systemReady();
StorageManagerInternal StorageManagerInternal = LocalServices.getService(

View File

@@ -26,7 +26,6 @@ import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.server.EventLogTags;
import com.android.server.pm.dex.DexManager;
@@ -56,7 +55,6 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.PackageUtils;
import android.util.Slog;
import android.util.jar.StrictJarFile;
import android.util.proto.ProtoOutputStream;
import dalvik.system.VMRuntime;
@@ -85,12 +83,10 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
/**
* Class containing helper methods for the PackageManagerService.
@@ -317,61 +313,6 @@ public class PackageManagerServiceUtils {
return maxModifiedTime;
}
/**
* Checks that the archive located at {@code fileName} has uncompressed dex file and so
* files that can be direclty mapped.
*/
public static void logApkHasUncompressedCode(String fileName) {
StrictJarFile jarFile = null;
try {
jarFile = new StrictJarFile(fileName,
false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
Iterator<ZipEntry> it = jarFile.iterator();
while (it.hasNext()) {
ZipEntry entry = it.next();
if (entry.getName().endsWith(".dex")) {
if (entry.getMethod() != ZipEntry.STORED) {
Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
entry.getName());
} else if ((entry.getDataOffset() & 0x3) != 0) {
Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
entry.getName());
}
} else if (entry.getName().endsWith(".so")) {
if (entry.getMethod() != ZipEntry.STORED) {
Slog.w(TAG, "APK " + fileName + " has compressed native code " +
entry.getName());
} else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
entry.getName());
}
}
}
} catch (IOException ignore) {
Slog.wtf(TAG, "Error when parsing APK " + fileName);
} finally {
try {
if (jarFile != null) {
jarFile.close();
}
} catch (IOException ignore) {}
}
return;
}
/**
* Checks that the APKs in the given package have uncompressed dex file and so
* files that can be direclty mapped.
*/
public static void logPackageHasUncompressedCode(PackageParser.Package pkg) {
logApkHasUncompressedCode(pkg.baseCodePath);
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
for (int i = 0; i < pkg.splitCodePaths.length; i++) {
logApkHasUncompressedCode(pkg.splitCodePaths[i]);
}
}
}
private static File getSettingsProblemFile() {
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");

View File

@@ -16,17 +16,25 @@
package com.android.server.pm.dex;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageParser;
import android.database.ContentObserver;
import android.os.Build;
import android.os.FileUtils;
import android.os.RemoteException;
import android.os.storage.StorageManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.util.Slog;
import android.util.jar.StrictJarFile;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PackageDexOptimizer;
@@ -36,13 +44,16 @@ import com.android.server.pm.PackageManagerServiceCompilerMapping;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
@@ -59,8 +70,14 @@ import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
public class DexManager {
private static final String TAG = "DexManager";
private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
"pm.dexopt.priv-apps-oob-list";
private static final boolean DEBUG = false;
private final Context mContext;
// Maps package name to code locations.
// It caches the code locations for the installed packages. This allows for
// faster lookups (no locks) when finding what package owns the dex file.
@@ -106,8 +123,9 @@ public class DexManager {
String dexPath, int storageFlags);
}
public DexManager(IPackageManager pms, PackageDexOptimizer pdo,
public DexManager(Context context, IPackageManager pms, PackageDexOptimizer pdo,
Installer installer, Object installLock, Listener listener) {
mContext = context;
mPackageCodeLocationsCache = new HashMap<>();
mPackageDexUsage = new PackageDexUsage();
mPackageManager = pms;
@@ -117,6 +135,10 @@ public class DexManager {
mListener = listener;
}
public void systemReady() {
registerSettingObserver();
}
/**
* Notify about dex files loads.
* Note that this method is invoked when apps load dex files and it should
@@ -641,6 +663,141 @@ public class DexManager {
mPackageDexUsage.writeNow();
}
private void registerSettingObserver() {
final ContentResolver resolver = mContext.getContentResolver();
// This observer provides a one directional mapping from Global.PRIV_APP_OOB_ENABLED to
// pm.dexopt.priv-apps-oob property. This is only for experiment and should be removed once
// it is done.
ContentObserver privAppOobObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
int oobEnabled = Global.getInt(resolver, Global.PRIV_APP_OOB_ENABLED, 0);
SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB,
oobEnabled == 1 ? "true" : "false");
}
};
resolver.registerContentObserver(
Global.getUriFor(Global.PRIV_APP_OOB_ENABLED), false, privAppOobObserver,
UserHandle.USER_SYSTEM);
// At boot, restore the value from the setting, which persists across reboot.
privAppOobObserver.onChange(true);
ContentObserver privAppOobListObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
String oobList = Global.getString(resolver, Global.PRIV_APP_OOB_LIST);
if (oobList == null) {
oobList = "ALL";
}
SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, oobList);
}
};
resolver.registerContentObserver(
Global.getUriFor(Global.PRIV_APP_OOB_LIST), false, privAppOobListObserver,
UserHandle.USER_SYSTEM);
// At boot, restore the value from the setting, which persists across reboot.
privAppOobListObserver.onChange(true);
}
/**
* Returns whether the given package is in the list of privilaged apps that should run out of
* box. This only makes sense if PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB is true. Note that when
* the the OOB list is empty, all priv apps will run in OOB mode.
*/
public static boolean isPackageSelectedToRunOob(String packageName) {
return isPackageSelectedToRunOob(Arrays.asList(packageName));
}
/**
* Returns whether any of the given packages are in the list of privilaged apps that should run
* out of box. This only makes sense if PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB is true. Note that
* when the the OOB list is empty, all priv apps will run in OOB mode.
*/
public static boolean isPackageSelectedToRunOob(Collection<String> packageNamesInSameProcess) {
if (!SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
return false;
}
String oobListProperty = SystemProperties.get(
PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL");
if ("ALL".equals(oobListProperty)) {
return true;
}
for (String oobPkgName : oobListProperty.split(",")) {
if (packageNamesInSameProcess.contains(oobPkgName)) {
return true;
}
}
return false;
}
/**
* Generates package related log if the package has code stored in unexpected way.
*/
public static void maybeLogUnexpectedPackageDetails(PackageParser.Package pkg) {
if (!Build.IS_DEBUGGABLE) {
return;
}
if (pkg.isPrivileged() && isPackageSelectedToRunOob(pkg.packageName)) {
logIfPackageHasUncompressedCode(pkg);
}
}
/**
* Generates log if the APKs in the given package have uncompressed dex file and so
* files that can be direclty mapped.
*/
private static void logIfPackageHasUncompressedCode(PackageParser.Package pkg) {
logIfApkHasUncompressedCode(pkg.baseCodePath);
if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
for (int i = 0; i < pkg.splitCodePaths.length; i++) {
logIfApkHasUncompressedCode(pkg.splitCodePaths[i]);
}
}
}
/**
* Generates log if the archive located at {@code fileName} has uncompressed dex file and so
* files that can be direclty mapped.
*/
private static void logIfApkHasUncompressedCode(String fileName) {
StrictJarFile jarFile = null;
try {
jarFile = new StrictJarFile(fileName,
false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
Iterator<ZipEntry> it = jarFile.iterator();
while (it.hasNext()) {
ZipEntry entry = it.next();
if (entry.getName().endsWith(".dex")) {
if (entry.getMethod() != ZipEntry.STORED) {
Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
entry.getName());
} else if ((entry.getDataOffset() & 0x3) != 0) {
Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
entry.getName());
}
} else if (entry.getName().endsWith(".so")) {
if (entry.getMethod() != ZipEntry.STORED) {
Slog.w(TAG, "APK " + fileName + " has compressed native code " +
entry.getName());
} else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
entry.getName());
}
}
}
} catch (IOException ignore) {
Slog.wtf(TAG, "Error when parsing APK " + fileName);
} finally {
try {
if (jarFile != null) {
jarFile.close();
}
} catch (IOException ignore) {}
}
}
public static class RegisterDexModuleResult {
public RegisterDexModuleResult() {
this(false, null);

View File

@@ -111,7 +111,8 @@ public class DexManagerTests {
DELEGATE_LAST_CLASS_LOADER_NAME);
mDexManager = new DexManager(
mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock, mListener);
/*Context*/ null, mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock,
mListener);
// Foo and Bar are available to user0.
// Only Bar is available to user1;