Merge "Allow a shared library to be positioned after the application on the classpath"

This commit is contained in:
Brad Stenning
2021-10-27 21:06:17 +00:00
committed by Gerrit Code Review
28 changed files with 741 additions and 29 deletions

View File

@@ -48,18 +48,19 @@ public class ApplicationLoaders {
ClassLoader parent, String classLoaderName) {
return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
librarySearchPath, libraryPermittedPath, parent, classLoaderName,
null, null);
null, null, null);
}
ClassLoader getClassLoaderWithSharedLibraries(
String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath,
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.
return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries,
nativeSharedLibraries);
nativeSharedLibraries, sharedLibrariesLoadedAfterApp);
}
/**
@@ -71,7 +72,8 @@ public class ApplicationLoaders {
*/
ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion,
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,
sharedLibraries);
if (loader != null) {
@@ -86,14 +88,15 @@ public class ApplicationLoaders {
nativeSharedLibraries.add("ALL");
return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries,
nativeSharedLibraries);
nativeSharedLibraries, sharedLibrariesAfter);
}
private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String cacheKey,
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 should be the "system" class loader; in practice we
@@ -123,7 +126,7 @@ public class ApplicationLoaders {
ClassLoader classloader = ClassLoaderFactory.createClassLoader(
zip, librarySearchPath, libraryPermittedPath, parent,
targetSdkVersion, isBundled, classLoaderName, sharedLibraries,
nativeSharedLibraries);
nativeSharedLibraries, sharedLibrariesLoadedAfterApp);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -140,7 +143,8 @@ public class ApplicationLoaders {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
ClassLoader loader = ClassLoaderFactory.createClassLoader(
zip, null, parent, classLoaderName, sharedLibraries);
zip, null, parent, classLoaderName, sharedLibraries,
null /*sharedLibrariesLoadedAfterApp*/);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return loader;
}
@@ -196,7 +200,7 @@ public class ApplicationLoaders {
ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/,
null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/,
null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/,
null /* nativeSharedLibraries */);
null /* nativeSharedLibraries */, null /*sharedLibrariesLoadedAfterApp*/);
if (classLoader == null) {
// 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.
return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null,
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.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.DisplayAdjustments;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
@@ -76,6 +78,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
@@ -700,7 +703,7 @@ public final class LoadedApk {
ClassLoader createSharedLibraryLoader(SharedLibraryInfo sharedLibrary,
boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
List<String> paths = sharedLibrary.getAllCodePaths();
List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
Pair<List<ClassLoader>, List<ClassLoader>> sharedLibraries = createSharedLibrariesLoaders(
sharedLibrary.getDependencies(), isBundledApp, librarySearchPath,
libraryPermittedPath);
final String jars = (paths.size() == 1) ? paths.get(0) :
@@ -711,15 +714,31 @@ public final class LoadedApk {
return ApplicationLoaders.getDefault().getSharedLibraryClassLoaderWithSharedLibraries(jars,
mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
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) {
if (sharedLibraries == null) {
return null;
if (sharedLibraries == null || sharedLibraries.isEmpty()) {
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> after = new ArrayList<>();
for (SharedLibraryInfo info : sharedLibraries) {
if (info.isNative()) {
// 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.
continue;
}
loaders.add(createSharedLibraryLoader(
info, isBundledApp, librarySearchPath, libraryPermittedPath));
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(
info, isBundledApp, librarySearchPath, libraryPermittedPath));
}
}
return loaders;
return new Pair<>(loaders, after);
}
private StrictMode.ThreadPolicy allowThreadDiskReads() {
@@ -955,9 +983,9 @@ public final class LoadedApk {
// as this is early and necessary.
StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath,
libraryPermittedPath);
Pair<List<ClassLoader>, List<ClassLoader>> sharedLibraries =
createSharedLibrariesLoaders(mApplicationInfo.sharedLibraryInfos, isBundledApp,
librarySearchPath, libraryPermittedPath);
List<String> nativeSharedLibraries = new ArrayList<>();
if (mApplicationInfo.sharedLibraryInfos != null) {
@@ -971,7 +999,8 @@ public final class LoadedApk {
mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader,
mApplicationInfo.classLoaderName, sharedLibraries, nativeSharedLibraries);
mApplicationInfo.classLoaderName, sharedLibraries.first, nativeSharedLibraries,
sharedLibraries.second);
mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
setThreadPolicy(oldPolicy);

View File

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

View File

@@ -5047,6 +5047,11 @@
to 0, the seconds hand will be disabled. -->
<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. -->
<integer name="config_customizedMaxCachedProcesses">32</integer>
</resources>

View File

@@ -4425,5 +4425,9 @@
<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" />
</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);
}
}