Merge "Allow only selected priv apps to run OOB" into pi-dev
am: 792d36c170
Change-Id: Iad80a321e1b76f19935a23290594a36fd057840c
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user