From 50dc99ce1bfb49eb9b5dc152a190aa259fdfa573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Gregorczyk?= Date: Wed, 20 Mar 2024 13:04:08 -0700 Subject: [PATCH] Fix library loads after split installation Summary: Whether we need to call `System.load` or `System.loadLibrary` depends on the context. * `System.load` rejects paths starting with `/mnt/asec`, but [accepts paths starting with `/data`](https://cs.android.com/android/platform/superproject/main/+/main:art/libnativeloader/library_namespaces.cpp;l=78?q=%22%2Fdata:%2F%22). We can never use it to load libs from the base.apk via full path if the app is installed on sd-card * `System.loadLibrary` considers outdated paths after a split apk is installed. It can never be used to load libraries after `/data/app` subdir is moved * Similar concerns apply to implicit loading - implicit dependencies are resolved on the linker namespace level and that one is not updated after `/data/app` subdir is moved * Apps installed to sd-card are killed during split installation even when --dont-kill flag is used. In that scenario we shouldn't need to bother with recovery. This commit implements loading strategy that satisfies constraints listed above: * `DirectSplitSoSourceWithImplicitLoads` is an SoSource supporting implicit loads and loading libs by name via `System.loadLibrary`. It works with apps installed to both internal storage and sdcard, provided that non splits were installed without killing the app. * `DirectSplitSoSourceWithStrictPathControl` is an SoSource that does not support implicit loads and loads libs by full path via `System.load`. It works independently from split installation. * `DirectSplitSoSourceWithImplicitLoads.recover` returns `DirectSplitSoSourceWithStrictPathControl` pointing othe same split. Base apk change can only be detected when the app is installed to the internal storage, this will not cause problems with sd-cards and will allow apps installed to /data/app to continue working after splits are installed. Reviewed By: adicatana Differential Revision: D54950872 fbshipit-source-id: 0100792da730fcce37055f88dc3e3951b9aa7fe0 --- .../soloader/DirectSplitSoSource.java | 33 +++++-------- .../DirectSplitSoSourceWithImplicitLoads.java | 48 +++++++++++++++++++ ...ectSplitSoSourceWithStrictPathControl.java | 40 ++++++++++++++++ java/com/facebook/soloader/SoLoader.java | 2 +- 4 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 java/com/facebook/soloader/DirectSplitSoSourceWithImplicitLoads.java create mode 100644 java/com/facebook/soloader/DirectSplitSoSourceWithStrictPathControl.java diff --git a/java/com/facebook/soloader/DirectSplitSoSource.java b/java/com/facebook/soloader/DirectSplitSoSource.java index 4165e71..2dd9380 100644 --- a/java/com/facebook/soloader/DirectSplitSoSource.java +++ b/java/com/facebook/soloader/DirectSplitSoSource.java @@ -16,7 +16,6 @@ package com.facebook.soloader; -import android.annotation.SuppressLint; import android.os.Build; import android.os.StrictMode; import java.io.File; @@ -26,11 +25,11 @@ import java.util.Set; import javax.annotation.Nullable; -public class DirectSplitSoSource extends SoSource { - private final String mSplitName; +public abstract class DirectSplitSoSource extends SoSource { + protected final String mSplitName; - private @Nullable Manifest mManifest = null; - private @Nullable Set mLibs = null; + protected @Nullable Manifest mManifest = null; + protected @Nullable Set mLibs = null; public DirectSplitSoSource(String splitName) { mSplitName = splitName; @@ -42,6 +41,13 @@ public DirectSplitSoSource(String splitName, Manifest manifest) { mLibs = new HashSet(manifest.libs); } + public DirectSplitSoSource( + String splitName, @Nullable Manifest manifest, @Nullable Set libs) { + mSplitName = splitName; + mManifest = manifest; + mLibs = libs; + } + Manifest getManifest() { if (mManifest == null) { throw new IllegalStateException("prepare not called"); @@ -66,21 +72,13 @@ public int loadLibrary(String soName, int loadFlags, StrictMode.ThreadPolicy thr } if (mLibs.contains(soName)) { - if ((loadFlags & LOAD_FLAG_ALLOW_IMPLICIT_PROVISION) != 0) { - return LOAD_RESULT_IMPLICITLY_PROVIDED; - } - - callSystemLoadLibrary(soName.substring(3, soName.length() - 3)); - return LOAD_RESULT_LOADED; + return loadLibraryImpl(soName, loadFlags); } return LOAD_RESULT_NOT_FOUND; } - @SuppressLint("MissingSoLoaderLibrary") - void callSystemLoadLibrary(String name) { - System.loadLibrary(name); - } + protected abstract int loadLibraryImpl(String soName, int loadFlags); @Override @Nullable @@ -156,9 +154,4 @@ public String[] getSoSourceAbis() { } return new String[] {mManifest.arch}; } - - @Override - public String getName() { - return "DirectSplitSoSource"; - } } diff --git a/java/com/facebook/soloader/DirectSplitSoSourceWithImplicitLoads.java b/java/com/facebook/soloader/DirectSplitSoSourceWithImplicitLoads.java new file mode 100644 index 0000000..391e401 --- /dev/null +++ b/java/com/facebook/soloader/DirectSplitSoSourceWithImplicitLoads.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * 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.facebook.soloader; + +import android.annotation.SuppressLint; +import android.content.Context; + +public class DirectSplitSoSourceWithImplicitLoads extends DirectSplitSoSource + implements RecoverableSoSource { + public DirectSplitSoSourceWithImplicitLoads(String splitName) { + super(splitName); + } + + @Override + @SuppressLint("MissingSoLoaderLibrary") + protected int loadLibraryImpl(String soName, int loadFlags) { + if ((loadFlags & LOAD_FLAG_ALLOW_IMPLICIT_PROVISION) != 0) { + return LOAD_RESULT_IMPLICITLY_PROVIDED; + } + + System.loadLibrary(soName.substring(3, soName.length() - 3)); + return LOAD_RESULT_LOADED; + } + + @Override + public String getName() { + return "DirectSplitSoSourceWithImplicitLoads"; + } + + @Override + public SoSource recover(Context context) { + return new DirectSplitSoSourceWithStrictPathControl(mSplitName, mManifest, mLibs); + } +} diff --git a/java/com/facebook/soloader/DirectSplitSoSourceWithStrictPathControl.java b/java/com/facebook/soloader/DirectSplitSoSourceWithStrictPathControl.java new file mode 100644 index 0000000..4e112d4 --- /dev/null +++ b/java/com/facebook/soloader/DirectSplitSoSourceWithStrictPathControl.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * 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.facebook.soloader; + +import android.annotation.SuppressLint; +import java.util.Set; +import javax.annotation.Nullable; + +public class DirectSplitSoSourceWithStrictPathControl extends DirectSplitSoSource { + public DirectSplitSoSourceWithStrictPathControl( + String splitName, @Nullable Manifest manifest, @Nullable Set libs) { + super(splitName, manifest, libs); + } + + @Override + @SuppressLint("MissingSoLoaderLibrary") + protected int loadLibraryImpl(String soName, int loadFlags) { + System.load(getLibraryPath(soName)); + return LOAD_RESULT_LOADED; + } + + @Override + public String getName() { + return "DirectSplitSoSourceWithStrictPathControl"; + } +} diff --git a/java/com/facebook/soloader/SoLoader.java b/java/com/facebook/soloader/SoLoader.java index 20954d4..bb9382e 100644 --- a/java/com/facebook/soloader/SoLoader.java +++ b/java/com/facebook/soloader/SoLoader.java @@ -353,7 +353,7 @@ private static void initSoSources(Context context, int flags) throws IOException addSystemLoadWrapperSoSource(context, soSources); } else if (isEnabledBaseApkSplitSource) { addSystemLibSoSource(soSources); - soSources.add(0, new DirectSplitSoSource("base")); + soSources.add(0, new DirectSplitSoSourceWithImplicitLoads("base")); } else { addSystemLibSoSource(soSources);