Merge "Marked apks loaded by isolated processes as usedByOthers"
This commit is contained in:
@@ -9903,10 +9903,10 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
@Override
|
@Override
|
||||||
public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
|
public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
|
||||||
String loaderIsa) {
|
String loaderIsa) {
|
||||||
if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName)
|
int callingUid = Binder.getCallingUid();
|
||||||
&& Binder.getCallingUid() != Process.SYSTEM_UID) {
|
if (PLATFORM_PACKAGE_NAME.equals(loadingPackageName) && callingUid != Process.SYSTEM_UID) {
|
||||||
Slog.w(TAG, "Non System Server process reporting dex loads as system server. uid="
|
Slog.w(TAG, "Non System Server process reporting dex loads as system server. uid="
|
||||||
+ Binder.getCallingUid());
|
+ callingUid);
|
||||||
// Do not record dex loads from processes pretending to be system server.
|
// Do not record dex loads from processes pretending to be system server.
|
||||||
// Only the system server should be assigned the package "android", so reject calls
|
// Only the system server should be assigned the package "android", so reject calls
|
||||||
// that don't satisfy the constraint.
|
// that don't satisfy the constraint.
|
||||||
@@ -9917,6 +9917,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
// in order to verify the expectations.
|
// in order to verify the expectations.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int userId = UserHandle.getCallingUserId();
|
int userId = UserHandle.getCallingUserId();
|
||||||
ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
|
ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
|
||||||
if (ai == null) {
|
if (ai == null) {
|
||||||
@@ -9924,7 +9925,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
+ loadingPackageName + ", user=" + userId);
|
+ loadingPackageName + ", user=" + userId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId);
|
mDexManager.notifyDexLoad(ai, classLoaderContextMap, loaderIsa, userId,
|
||||||
|
Process.isIsolated(callingUid));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -86,6 +86,11 @@ public class DexManager {
|
|||||||
// However it can load verification data - thus we pick the "verify" compiler filter.
|
// However it can load verification data - thus we pick the "verify" compiler filter.
|
||||||
private static final String SYSTEM_SERVER_COMPILER_FILTER = "verify";
|
private static final String SYSTEM_SERVER_COMPILER_FILTER = "verify";
|
||||||
|
|
||||||
|
// The suffix we add to the package name when the loading happens in an isolated process.
|
||||||
|
// Note that the double dot creates and "invalid" package name which makes it clear that this
|
||||||
|
// is an artificially constructed name.
|
||||||
|
private static final String ISOLATED_PROCESS_PACKAGE_SUFFIX = "..isolated";
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
// Maps package name to code locations.
|
// Maps package name to code locations.
|
||||||
@@ -166,12 +171,14 @@ public class DexManager {
|
|||||||
* the class loader context that was used to load them.
|
* the class loader context that was used to load them.
|
||||||
* @param loaderIsa the ISA of the app loading the dex files
|
* @param loaderIsa the ISA of the app loading the dex files
|
||||||
* @param loaderUserId the user id which runs the code loading the dex files
|
* @param loaderUserId the user id which runs the code loading the dex files
|
||||||
|
* @param loaderIsIsolatedProcess whether or not the loading process is isolated.
|
||||||
*/
|
*/
|
||||||
public void notifyDexLoad(ApplicationInfo loadingAppInfo,
|
public void notifyDexLoad(ApplicationInfo loadingAppInfo,
|
||||||
Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId) {
|
Map<String, String> classLoaderContextMap, String loaderIsa, int loaderUserId,
|
||||||
|
boolean loaderIsIsolatedProcess) {
|
||||||
try {
|
try {
|
||||||
notifyDexLoadInternal(loadingAppInfo, classLoaderContextMap, loaderIsa,
|
notifyDexLoadInternal(loadingAppInfo, classLoaderContextMap, loaderIsa,
|
||||||
loaderUserId);
|
loaderUserId, loaderIsIsolatedProcess);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Slog.w(TAG, "Exception while notifying dex load for package " +
|
Slog.w(TAG, "Exception while notifying dex load for package " +
|
||||||
loadingAppInfo.packageName, e);
|
loadingAppInfo.packageName, e);
|
||||||
@@ -181,7 +188,7 @@ public class DexManager {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
/*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo,
|
/*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo,
|
||||||
Map<String, String> classLoaderContextMap, String loaderIsa,
|
Map<String, String> classLoaderContextMap, String loaderIsa,
|
||||||
int loaderUserId) {
|
int loaderUserId, boolean loaderIsIsolatedProcess) {
|
||||||
if (classLoaderContextMap == null) {
|
if (classLoaderContextMap == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -195,22 +202,36 @@ public class DexManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this load is coming from an isolated process we need to be able to prevent profile
|
||||||
|
// based optimizations. This is because isolated processes are sandboxed and can only read
|
||||||
|
// world readable files, so they need world readable optimization files. An
|
||||||
|
// example of such a package is webview.
|
||||||
|
//
|
||||||
|
// In order to prevent profile optimization we pretend that the load is coming from a
|
||||||
|
// different package, and so we assign a artificial name to the loading package making it
|
||||||
|
// clear that it comes from an isolated process. This blends well with the entire
|
||||||
|
// usedByOthers logic without needing to special handle isolated process in all dexopt
|
||||||
|
// layers.
|
||||||
|
String loadingPackageAmendedName = loadingAppInfo.packageName;
|
||||||
|
if (loaderIsIsolatedProcess) {
|
||||||
|
loadingPackageAmendedName += ISOLATED_PROCESS_PACKAGE_SUFFIX;
|
||||||
|
}
|
||||||
for (Map.Entry<String, String> mapping : classLoaderContextMap.entrySet()) {
|
for (Map.Entry<String, String> mapping : classLoaderContextMap.entrySet()) {
|
||||||
String dexPath = mapping.getKey();
|
String dexPath = mapping.getKey();
|
||||||
// Find the owning package name.
|
// Find the owning package name.
|
||||||
DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId);
|
DexSearchResult searchResult = getDexPackage(loadingAppInfo, dexPath, loaderUserId);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.i(TAG, loadingAppInfo.packageName
|
Slog.i(TAG, loadingPackageAmendedName
|
||||||
+ " loads from " + searchResult + " : " + loaderUserId + " : " + dexPath);
|
+ " loads from " + searchResult + " : " + loaderUserId + " : " + dexPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchResult.mOutcome != DEX_SEARCH_NOT_FOUND) {
|
if (searchResult.mOutcome != DEX_SEARCH_NOT_FOUND) {
|
||||||
// TODO(calin): extend isUsedByOtherApps check to detect the cases where
|
// TODO(calin): extend isUsedByOtherApps check to detect the cases where
|
||||||
// different apps share the same runtime. In that case we should not mark the dex
|
// different apps share the same runtime. In that case we should not mark the dex
|
||||||
// file as isUsedByOtherApps. Currently this is a safe approximation.
|
// file as isUsedByOtherApps. Currently this is a safe approximation.
|
||||||
boolean isUsedByOtherApps = !loadingAppInfo.packageName.equals(
|
boolean isUsedByOtherApps =
|
||||||
searchResult.mOwningPackageName);
|
!loadingPackageAmendedName.equals(searchResult.mOwningPackageName);
|
||||||
boolean primaryOrSplit = searchResult.mOutcome == DEX_SEARCH_FOUND_PRIMARY ||
|
boolean primaryOrSplit = searchResult.mOutcome == DEX_SEARCH_FOUND_PRIMARY ||
|
||||||
searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT;
|
searchResult.mOutcome == DEX_SEARCH_FOUND_SPLIT;
|
||||||
|
|
||||||
@@ -249,7 +270,7 @@ public class DexManager {
|
|||||||
// async write to disk to make sure we don't loose the data in case of a reboot.
|
// async write to disk to make sure we don't loose the data in case of a reboot.
|
||||||
if (mPackageDexUsage.record(searchResult.mOwningPackageName,
|
if (mPackageDexUsage.record(searchResult.mOwningPackageName,
|
||||||
dexPath, loaderUserId, loaderIsa, primaryOrSplit,
|
dexPath, loaderUserId, loaderIsa, primaryOrSplit,
|
||||||
loadingAppInfo.packageName, classLoaderContext, overwriteCLC)) {
|
loadingPackageAmendedName, classLoaderContext, overwriteCLC)) {
|
||||||
mPackageDexUsage.maybeWriteAsync();
|
mPackageDexUsage.maybeWriteAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -749,7 +770,7 @@ public class DexManager {
|
|||||||
dexPath, userId, isa, /*primaryOrSplit*/ false,
|
dexPath, userId, isa, /*primaryOrSplit*/ false,
|
||||||
loadingPackage,
|
loadingPackage,
|
||||||
PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT,
|
PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT,
|
||||||
/*overwriteCLC*/ false);
|
/*overwriteCLC=*/ false);
|
||||||
update |= newUpdate;
|
update |= newUpdate;
|
||||||
}
|
}
|
||||||
if (update) {
|
if (update) {
|
||||||
|
|||||||
@@ -409,6 +409,17 @@ public class DexManagerTests {
|
|||||||
assertIsUsedByOtherApps(mBarUser0, pui, false);
|
assertIsUsedByOtherApps(mBarUser0, pui, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyUsedByIsolatedProcess() {
|
||||||
|
// Bar loads its own apk but as isolatedProcess.
|
||||||
|
notifyDexLoad(mBarUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0,
|
||||||
|
/*isolatedProcess=*/ true);
|
||||||
|
|
||||||
|
// Bar is used by an isolated process and should be marked as usedByOtherApps
|
||||||
|
PackageUseInfo pui = getPackageUseInfo(mBarUser0);
|
||||||
|
assertIsUsedByOtherApps(mBarUser0, pui, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotifyPackageUpdatedCodeLocations() {
|
public void testNotifyPackageUpdatedCodeLocations() {
|
||||||
// Simulate a split update.
|
// Simulate a split update.
|
||||||
@@ -545,7 +556,7 @@ public class DexManagerTests {
|
|||||||
List<String> classLoaders =
|
List<String> classLoaders =
|
||||||
Arrays.asList(PATH_CLASS_LOADER_NAME, UNSUPPORTED_CLASS_LOADER_NAME);
|
Arrays.asList(PATH_CLASS_LOADER_NAME, UNSUPPORTED_CLASS_LOADER_NAME);
|
||||||
List<String> classPaths = Arrays.asList(classPath, classPath);
|
List<String> classPaths = Arrays.asList(classPath, classPath);
|
||||||
notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0);
|
notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0, /*isolatedProcess=*/ false);
|
||||||
|
|
||||||
assertNoUseInfo(mBarUser0);
|
assertNoUseInfo(mBarUser0);
|
||||||
|
|
||||||
@@ -664,7 +675,8 @@ public class DexManagerTests {
|
|||||||
expectedContexts[i] += contextSuffix;
|
expectedContexts[i] += contextSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0);
|
notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0,
|
||||||
|
/*isolatedProcess=*/ false);
|
||||||
|
|
||||||
PackageUseInfo pui = getPackageUseInfo(mFooUser0);
|
PackageUseInfo pui = getPackageUseInfo(mFooUser0);
|
||||||
assertIsUsedByOtherApps(mFooUser0, pui, false);
|
assertIsUsedByOtherApps(mFooUser0, pui, false);
|
||||||
@@ -838,26 +850,32 @@ public class DexManagerTests {
|
|||||||
assertEquals(codePath, isUsedByOtherApps, pui.isUsedByOtherApps(codePath));
|
assertEquals(codePath, isUsedByOtherApps, pui.isUsedByOtherApps(codePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) {
|
private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) {
|
||||||
|
notifyDexLoad(testData, dexPaths, loaderUserId, /*isolatedProcess=*/ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId,
|
||||||
|
boolean isolatedProcess) {
|
||||||
// By default, assume a single class loader in the chain.
|
// By default, assume a single class loader in the chain.
|
||||||
// This makes writing tests much easier.
|
// This makes writing tests much easier.
|
||||||
List<String> classLoaders = Arrays.asList(testData.mClassLoader);
|
List<String> classLoaders = Arrays.asList(testData.mClassLoader);
|
||||||
List<String> classPaths = dexPaths != null
|
List<String> classPaths = dexPaths != null
|
||||||
? Arrays.<String>asList(String.join(File.pathSeparator, dexPaths)) : null;
|
? Arrays.<String>asList(String.join(File.pathSeparator, dexPaths)) : null;
|
||||||
notifyDexLoad(testData, classLoaders, classPaths, loaderUserId);
|
notifyDexLoad(testData, classLoaders, classPaths, loaderUserId, isolatedProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyDexLoad(TestData testData, List<String> classLoaders,
|
private void notifyDexLoad(TestData testData, List<String> classLoaders,
|
||||||
List<String> classPaths, int loaderUserId) {
|
List<String> classPaths, int loaderUserId, boolean isolatedProcess) {
|
||||||
String[] classLoaderContexts = computeClassLoaderContexts(classLoaders, classPaths);
|
String[] classLoaderContexts = computeClassLoaderContexts(classLoaders, classPaths);
|
||||||
// We call the internal function so any exceptions thrown cause test failures.
|
// We call the internal function so any exceptions thrown cause test failures.
|
||||||
List<String> dexPaths = classPaths != null
|
List<String> dexPaths = classPaths != null
|
||||||
? Arrays.asList(classPaths.get(0).split(File.pathSeparator)) : Arrays.asList();
|
? Arrays.asList(classPaths.get(0).split(File.pathSeparator)) : Arrays.asList();
|
||||||
notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId);
|
notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId, isolatedProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyDexLoad(TestData testData, List<String> dexPaths,
|
private void notifyDexLoad(TestData testData, List<String> dexPaths,
|
||||||
String[] classLoaderContexts, int loaderUserId) {
|
String[] classLoaderContexts, int loaderUserId, boolean isolatedProcess) {
|
||||||
assertTrue(dexPaths.size() == classLoaderContexts.length);
|
assertTrue(dexPaths.size() == classLoaderContexts.length);
|
||||||
HashMap<String, String> dexPathMapping = new HashMap<>(dexPaths.size());
|
HashMap<String, String> dexPathMapping = new HashMap<>(dexPaths.size());
|
||||||
for (int i = 0; i < dexPaths.size(); i++) {
|
for (int i = 0; i < dexPaths.size(); i++) {
|
||||||
@@ -865,7 +883,7 @@ public class DexManagerTests {
|
|||||||
? classLoaderContexts[i] : PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
|
? classLoaderContexts[i] : PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
|
||||||
}
|
}
|
||||||
mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, dexPathMapping,
|
mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, dexPathMapping,
|
||||||
testData.mLoaderIsa, loaderUserId);
|
testData.mLoaderIsa, loaderUserId, isolatedProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] computeClassLoaderContexts(List<String> classLoaders,
|
private String[] computeClassLoaderContexts(List<String> classLoaders,
|
||||||
|
|||||||
Reference in New Issue
Block a user