Merge "Allow a shared library to be positioned after the application on the classpath" am: 3120b13f56 am: 6e2646eacd

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1852914

Change-Id: I6b68af9a6f028103453e4cb6e014e852ef8838d1
This commit is contained in:
Brad Stenning
2021-10-27 21:43:17 +00:00
committed by Automerger Merge Worker
28 changed files with 741 additions and 29 deletions

View File

@@ -48,18 +48,19 @@ public class ApplicationLoaders {
ClassLoader parent, String classLoaderName) { ClassLoader parent, String classLoaderName) {
return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
librarySearchPath, libraryPermittedPath, parent, classLoaderName, librarySearchPath, libraryPermittedPath, parent, classLoaderName,
null, null); null, null, null);
} }
ClassLoader getClassLoaderWithSharedLibraries( ClassLoader getClassLoaderWithSharedLibraries(
String zip, int targetSdkVersion, boolean isBundled, String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath, String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String classLoaderName, ClassLoader parent, String classLoaderName,
List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) { List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries,
List<ClassLoader> sharedLibrariesLoadedAfterApp) {
// For normal usage the cache key used is the same as the zip path. // For normal usage the cache key used is the same as the zip path.
return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries, libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries,
nativeSharedLibraries); nativeSharedLibraries, sharedLibrariesLoadedAfterApp);
} }
/** /**
@@ -71,7 +72,8 @@ public class ApplicationLoaders {
*/ */
ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion, ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion,
boolean isBundled, String librarySearchPath, String libraryPermittedPath, boolean isBundled, String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) { ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries,
List<ClassLoader> sharedLibrariesAfter) {
ClassLoader loader = getCachedNonBootclasspathSystemLib(zip, parent, classLoaderName, ClassLoader loader = getCachedNonBootclasspathSystemLib(zip, parent, classLoaderName,
sharedLibraries); sharedLibraries);
if (loader != null) { if (loader != null) {
@@ -86,14 +88,15 @@ public class ApplicationLoaders {
nativeSharedLibraries.add("ALL"); nativeSharedLibraries.add("ALL");
return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries, librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries,
nativeSharedLibraries); nativeSharedLibraries, sharedLibrariesAfter);
} }
private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath, String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String cacheKey, ClassLoader parent, String cacheKey,
String classLoaderName, List<ClassLoader> sharedLibraries, String classLoaderName, List<ClassLoader> sharedLibraries,
List<String> nativeSharedLibraries) { List<String> nativeSharedLibraries,
List<ClassLoader> sharedLibrariesLoadedAfterApp) {
/* /*
* This is the parent we use if they pass "null" in. In theory * This is the parent we use if they pass "null" in. In theory
* this should be the "system" class loader; in practice we * this should be the "system" class loader; in practice we
@@ -123,7 +126,7 @@ public class ApplicationLoaders {
ClassLoader classloader = ClassLoaderFactory.createClassLoader( ClassLoader classloader = ClassLoaderFactory.createClassLoader(
zip, librarySearchPath, libraryPermittedPath, parent, zip, librarySearchPath, libraryPermittedPath, parent,
targetSdkVersion, isBundled, classLoaderName, sharedLibraries, targetSdkVersion, isBundled, classLoaderName, sharedLibraries,
nativeSharedLibraries); nativeSharedLibraries, sharedLibrariesLoadedAfterApp);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -140,7 +143,8 @@ public class ApplicationLoaders {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip); Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
ClassLoader loader = ClassLoaderFactory.createClassLoader( ClassLoader loader = ClassLoaderFactory.createClassLoader(
zip, null, parent, classLoaderName, sharedLibraries); zip, null, parent, classLoaderName, sharedLibraries,
null /*sharedLibrariesLoadedAfterApp*/);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return loader; return loader;
} }
@@ -196,7 +200,7 @@ public class ApplicationLoaders {
ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/, ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/,
null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/, null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/,
null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/, null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/,
null /* nativeSharedLibraries */); null /* nativeSharedLibraries */, null /*sharedLibrariesLoadedAfterApp*/);
if (classLoader == null) { if (classLoader == null) {
// bad configuration or break in classloading code // bad configuration or break in classloading code
@@ -267,7 +271,8 @@ public class ApplicationLoaders {
// stub's APK path, when the actual package path is the donor APK. // stub's APK path, when the actual package path is the donor APK.
return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null,
cacheKey, null /* classLoaderName */, null /* sharedLibraries */, cacheKey, null /* classLoaderName */, null /* sharedLibraries */,
null /* nativeSharedLibraries */); null /* nativeSharedLibraries */,
null /*sharedLibrariesLoadedAfterApp*/);
} }
/** /**

View File

@@ -54,10 +54,12 @@ import android.text.TextUtils;
import android.util.AndroidRuntimeException; import android.util.AndroidRuntimeException;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.DisplayAdjustments; import android.view.DisplayAdjustments;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils; import com.android.internal.util.ArrayUtils;
@@ -76,6 +78,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -700,7 +703,7 @@ public final class LoadedApk {
ClassLoader createSharedLibraryLoader(SharedLibraryInfo sharedLibrary, ClassLoader createSharedLibraryLoader(SharedLibraryInfo sharedLibrary,
boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) { boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
List<String> paths = sharedLibrary.getAllCodePaths(); List<String> paths = sharedLibrary.getAllCodePaths();
List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders( Pair<List<ClassLoader>, List<ClassLoader>> sharedLibraries = createSharedLibrariesLoaders(
sharedLibrary.getDependencies(), isBundledApp, librarySearchPath, sharedLibrary.getDependencies(), isBundledApp, librarySearchPath,
libraryPermittedPath); libraryPermittedPath);
final String jars = (paths.size() == 1) ? paths.get(0) : final String jars = (paths.size() == 1) ? paths.get(0) :
@@ -711,15 +714,31 @@ public final class LoadedApk {
return ApplicationLoaders.getDefault().getSharedLibraryClassLoaderWithSharedLibraries(jars, return ApplicationLoaders.getDefault().getSharedLibraryClassLoaderWithSharedLibraries(jars,
mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, /* parent */ null, libraryPermittedPath, /* parent */ null,
/* classLoaderName */ null, sharedLibraries); /* classLoaderName */ null, sharedLibraries.first, sharedLibraries.second);
} }
private List<ClassLoader> createSharedLibrariesLoaders(List<SharedLibraryInfo> sharedLibraries, /**
*
* @return a {@link Pair} of List<ClassLoader> where the first is for standard shared libraries
* and the second is list for shared libraries that code should be loaded after the dex
*/
private Pair<List<ClassLoader>, List<ClassLoader>> createSharedLibrariesLoaders(
List<SharedLibraryInfo> sharedLibraries,
boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) { boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
if (sharedLibraries == null) { if (sharedLibraries == null || sharedLibraries.isEmpty()) {
return null; return new Pair<>(null, null);
} }
// if configured to do so, shared libs are split into 2 collections: those that are
// on the class path before the applications code, which is standard, and those
// specified to be loaded after the applications code.
HashSet<String> libsToLoadAfter = new HashSet<>();
Resources systemR = Resources.getSystem();
Collections.addAll(libsToLoadAfter, systemR.getStringArray(
R.array.config_sharedLibrariesLoadedAfterApp));
List<ClassLoader> loaders = new ArrayList<>(); List<ClassLoader> loaders = new ArrayList<>();
List<ClassLoader> after = new ArrayList<>();
for (SharedLibraryInfo info : sharedLibraries) { for (SharedLibraryInfo info : sharedLibraries) {
if (info.isNative()) { if (info.isNative()) {
// Native shared lib doesn't contribute to the native lib search path. Its name is // Native shared lib doesn't contribute to the native lib search path. Its name is
@@ -727,10 +746,19 @@ public final class LoadedApk {
// default linker namespace. // default linker namespace.
continue; continue;
} }
if (libsToLoadAfter.contains(info.getName())) {
if (DEBUG) {
Slog.v(ActivityThread.TAG,
info.getName() + " will be loaded after application code");
}
after.add(createSharedLibraryLoader(
info, isBundledApp, librarySearchPath, libraryPermittedPath));
} else {
loaders.add(createSharedLibraryLoader( loaders.add(createSharedLibraryLoader(
info, isBundledApp, librarySearchPath, libraryPermittedPath)); info, isBundledApp, librarySearchPath, libraryPermittedPath));
} }
return loaders; }
return new Pair<>(loaders, after);
} }
private StrictMode.ThreadPolicy allowThreadDiskReads() { private StrictMode.ThreadPolicy allowThreadDiskReads() {
@@ -955,9 +983,9 @@ public final class LoadedApk {
// as this is early and necessary. // as this is early and necessary.
StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads(); StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders( Pair<List<ClassLoader>, List<ClassLoader>> sharedLibraries =
mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath, createSharedLibrariesLoaders(mApplicationInfo.sharedLibraryInfos, isBundledApp,
libraryPermittedPath); librarySearchPath, libraryPermittedPath);
List<String> nativeSharedLibraries = new ArrayList<>(); List<String> nativeSharedLibraries = new ArrayList<>();
if (mApplicationInfo.sharedLibraryInfos != null) { if (mApplicationInfo.sharedLibraryInfos != null) {
@@ -971,7 +999,8 @@ public final class LoadedApk {
mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries( mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader, libraryPermittedPath, mBaseClassLoader,
mApplicationInfo.classLoaderName, sharedLibraries, nativeSharedLibraries); mApplicationInfo.classLoaderName, sharedLibraries.first, nativeSharedLibraries,
sharedLibraries.second);
mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader); mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
setThreadPolicy(oldPolicy); setThreadPolicy(oldPolicy);

View File

@@ -80,15 +80,20 @@ public class ClassLoaderFactory {
*/ */
public static ClassLoader createClassLoader(String dexPath, public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, ClassLoader parent, String classloaderName, String librarySearchPath, ClassLoader parent, String classloaderName,
List<ClassLoader> sharedLibraries) { List<ClassLoader> sharedLibraries, List<ClassLoader> sharedLibrariesLoadedAfter) {
ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null) ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
? null ? null
: sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]); : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
ClassLoader[] arrayOfSharedLibrariesLoadedAfterApp = (sharedLibrariesLoadedAfter == null)
? null
: sharedLibrariesLoadedAfter.toArray(
new ClassLoader[sharedLibrariesLoadedAfter.size()]);
if (isPathClassLoaderName(classloaderName)) { if (isPathClassLoaderName(classloaderName)) {
return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries); return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries,
arrayOfSharedLibrariesLoadedAfterApp);
} else if (isDelegateLastClassLoaderName(classloaderName)) { } else if (isDelegateLastClassLoaderName(classloaderName)) {
return new DelegateLastClassLoader(dexPath, librarySearchPath, parent, return new DelegateLastClassLoader(dexPath, librarySearchPath, parent,
arrayOfSharedLibraries); arrayOfSharedLibraries, arrayOfSharedLibrariesLoadedAfterApp);
} }
throw new AssertionError("Invalid classLoaderName: " + classloaderName); throw new AssertionError("Invalid classLoaderName: " + classloaderName);
@@ -102,20 +107,20 @@ public class ClassLoaderFactory {
String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) { int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) {
return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath, return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath,
parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null); parent, targetSdkVersion, isNamespaceShared, classLoaderName, null, null, null);
} }
/** /**
* Create a ClassLoader and initialize a linker-namespace for it. * Create a ClassLoader and initialize a linker-namespace for it.
*/ */
public static ClassLoader createClassLoader(String dexPath, public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
int targetSdkVersion, boolean isNamespaceShared, String classLoaderName, int targetSdkVersion, boolean isNamespaceShared, String classLoaderName,
List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries) { List<ClassLoader> sharedLibraries, List<String> nativeSharedLibraries,
List<ClassLoader> sharedLibrariesAfter) {
final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent, final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,
classLoaderName, sharedLibraries); classLoaderName, sharedLibraries, sharedLibrariesAfter);
String sonameList = ""; String sonameList = "";
if (nativeSharedLibraries != null) { if (nativeSharedLibraries != null) {

View File

@@ -5054,6 +5054,11 @@
to 0, the seconds hand will be disabled. --> to 0, the seconds hand will be disabled. -->
<integer name="config_defaultAnalogClockSecondsHandFps">1</integer> <integer name="config_defaultAnalogClockSecondsHandFps">1</integer>
<!-- List of shared library packages that should be loaded by the classloader after the
code and resources provided by applications. This value will be set by the manufacturer -->
<string-array name="config_sharedLibrariesLoadedAfterApp" translatable="false">
</string-array>
<!-- the number of the max cached processes in the system. --> <!-- the number of the max cached processes in the system. -->
<integer name="config_customizedMaxCachedProcesses">32</integer> <integer name="config_customizedMaxCachedProcesses">32</integer>
</resources> </resources>

View File

@@ -4427,5 +4427,9 @@
<java-symbol type="bool" name="config_volumeShowRemoteSessions" /> <java-symbol type="bool" name="config_volumeShowRemoteSessions" />
<!-- List of shared library packages that should be loaded by the classloader after the
code and resources provided by applications. -->
<java-symbol type="array" name="config_sharedLibrariesLoadedAfterApp" />
<java-symbol type="integer" name="config_customizedMaxCachedProcesses" /> <java-symbol type="integer" name="config_customizedMaxCachedProcesses" />
</resources> </resources>

View File

@@ -0,0 +1,37 @@
// Copyright (C) 2021 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
java_test_host {
name: "SharedLibraryLoadingTests",
libs: [
"tradefed",
"junit",
],
test_suites: ["general-tests"],
data: [
":SharedLibraryLoadingTests_StandardSharedLibrary",
":SharedLibraryLoadingTests_SharedLibraryLoadedAfter",
":SharedLibraryLoadingTests_SharedLibraryClientTests",
":SharedLibraryLoadingTests_Overlay",
],
}

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<configuration description="Host-driven test module config for SharedLibraryHostTests">
<option name="test-tag" value="SharedLibraryLoadingTests" />
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="false" />
<option name="remount-system" value="true" />
<option name="push"
value="SharedLibraryLoadingTests_StandardSharedLibrary.apk->/product/app/SharedLibraryLoadingTests_StandardSharedLibrary.apk" />
<option name="push"
value="SharedLibraryLoadingTests_SharedLibraryLoadedAfter.apk->/product/app/SharedLibraryLoadingTests_SharedLibraryLoadedAfter.apk" />
<option name="push"
value="SharedLibraryLoadingTests_Overlay.apk->/product/overlay/SharedLibraryLoadingTests_Overlay.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="SharedLibraryLoadingTests_SharedLibraryClientTests.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.sharedlibloadingtest.client" />
</test>
</configuration>

View File

@@ -0,0 +1,2 @@
stenning@google.com

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2021 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_test_helper_app {
name: "SharedLibraryLoadingTests_Overlay",
platform_apis: true,
certificate: "platform",
aaptflags: ["--no-resource-removal"],
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.sharedlibloadingtest.overlay">
<application android:hasCode="false" />
<overlay android:targetPackage="android"
android:isStatic="true"
android:priority="1"/>
</manifest>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2020 Google Inc.
*
* 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.
*/
-->
<resources>
<string-array name="config_sharedLibrariesLoadedAfterApp" translatable="false">
<item>com.android.sharedlibloadingtest.shared_library_after</item>
</string-array>
</resources>

View File

@@ -0,0 +1,35 @@
// Copyright (C) 2021 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 {
default_applicable_licenses: ["Android-Apache-2.0"],
}
android_test_helper_app {
name: "SharedLibraryLoadingTests_SharedLibraryClientTests",
srcs: ["**/*.java"],
resource_dirs: ["res"],
libs: [
"SharedLibraryLoadingTests_StandardSharedLibrary",
"SharedLibraryLoadingTests_SharedLibraryLoadedAfter",
"android.test.base",
],
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
"androidx.test.core",
"testng",
],
platform_apis: true,
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.sharedlibloadingtest.client">
<application>
<uses-library android:name="android.test.runner" />
<uses-library android:name="com.android.sharedlibloadingtest.shared_library"/>
<uses-library android:name="com.android.sharedlibloadingtest.shared_library_after"/>
</application>
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.sharedlibloadingtest.client" />
</manifest>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<resources>
<string name="identical_resource_key">client value</string>
</resources>

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2021 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.sharedlibloadingtest;
public class ClientClass {
@Override
public String toString() {
return "Client Code";
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2021 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.sharedlibloadingtest;
public class DuplicateClassA {
@Override
public String toString() {
return "Client's Version";
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2021 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.sharedlibloadingtest;
public class DuplicateClassB {
@Override
public String toString() {
return "Client's Version B";
}
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2021 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.sharedlibloadingtest.client;
import static org.testng.Assert.assertEquals;
import android.content.Context;
import android.content.res.Resources;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.internal.util.Preconditions;
import com.android.sharedlibloadingtest.ClientClass;
import com.android.sharedlibloadingtest.DuplicateClassA;
import com.android.sharedlibloadingtest.DuplicateClassB;
import com.android.sharedlibloadingtest.SharedClassAfter;
import com.android.sharedlibloadingtest.StdSharedClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Collections;
import java.util.HashSet;
@RunWith(AndroidJUnit4.class)
public class SharedLibraryLoadingOrderTest {
@Test
public void testLoadingOfStdShareLibsShouldBeFirst() {
Preconditions.checkArgument(!getLibsLoadedAfter()
.contains("com.android.sharedlibloadingtest.shared_library"));
DuplicateClassA clazz = new DuplicateClassA();
assertEquals(clazz.toString(), "Standard Shared Lib's Version");
StdSharedClass stdSharedClass = new StdSharedClass();
assertEquals(stdSharedClass.toString(), "Nothing Special Lib");
ClientClass clientCode = new ClientClass();
assertEquals(clientCode.toString(), "Client Code");
}
@Test
public void testLoadingOfShareLibsIsAfter() {
Preconditions.checkArgument(getLibsLoadedAfter()
.contains("com.android.sharedlibloadingtest.shared_library_after"));
DuplicateClassB clazz = new DuplicateClassB();
assertEquals(clazz.toString(), "Client's Version B");
SharedClassAfter stdSharedClass = new SharedClassAfter();
assertEquals(stdSharedClass.toString(), "Also Nothing Special");
ClientClass clientCode = new ClientClass();
assertEquals(clientCode.toString(), "Client Code");
}
@Test
public void testLoadingOfResource() {
// aapt compiler gives each lib their own namespace so this test just confirming
// the resources can be loaded from the same context object
Context context = ApplicationProvider.getApplicationContext();
String clientString = context.getResources().getString(R.string.identical_resource_key);
assertEquals(clientString, "client value");
assertEquals(StdSharedClass.getResString(context), "std lib value");
assertEquals(SharedClassAfter.getResString(context), "loaded after value");
}
private HashSet<String> getLibsLoadedAfter() {
Resources systemR = Resources.getSystem();
HashSet<String> libsToLoadAfter = new HashSet<>();
Collections.addAll(libsToLoadAfter, systemR.getStringArray(
com.android.internal.R.array.config_sharedLibrariesLoadedAfterApp));
return libsToLoadAfter;
}
}

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2021 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_test_helper_app {
name: "SharedLibraryLoadingTests_SharedLibraryLoadedAfter",
srcs: ["**/*.java"],
resource_dirs: ["res"],
sdk_version: "current",
aaptflags: ["--shared-lib"],
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.sharedlibloadingtest.shared_library_after">
<application>
<library android:name="com.android.sharedlibloadingtest.shared_library_after" />
</application>
</manifest>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<resources>
<string name="identical_resource_key">loaded after value</string>
</resources>

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2021 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.sharedlibloadingtest;
public class DuplicateClassB {
@Override
public String toString() {
return "Loaded After Shared Lib's Version";
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021 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.sharedlibloadingtest;
import android.content.Context;
import com.android.sharedlibloadingtest.shared_library_after.R;
public class SharedClassAfter {
@Override
public String toString() {
return "Also Nothing Special";
}
public static String getResString(Context context) {
return context.getResources().getString(R.string.identical_resource_key);
}
}

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2021 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 {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_base_license"],
}
android_test_helper_app {
name: "SharedLibraryLoadingTests_StandardSharedLibrary",
srcs: ["**/*.java"],
resource_dirs: ["res"],
sdk_version: "current",
aaptflags: ["--shared-lib"],
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.sharedlibloadingtest.shared_library">
<application>
<library android:name="com.android.sharedlibloadingtest.shared_library" />
</application>
</manifest>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<resources>
<string name="identical_resource_key">std lib value</string>
</resources>

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2021 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.sharedlibloadingtest;
public class DuplicateClassA {
@Override
public String toString() {
return "Standard Shared Lib's Version";
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021 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.sharedlibloadingtest;
import android.content.Context;
import com.android.sharedlibloadingtest.shared_library.R;
public class StdSharedClass {
@Override
public String toString() {
return "Nothing Special Lib";
}
public static String getResString(Context context) {
return context.getResources().getString(R.string.identical_resource_key);
}
}