Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 21bdaab5 authored by Pawan Wagh's avatar Pawan Wagh
Browse files

Show native library info on compat warnings

Store the native library info inside package manager and
append the library names on the warning

Test: m PageSizeCompatWarningsTest && atest -c PageSizeCompatWarningsTest
Bug: 416538966
Flag: android.content.pm.app_compat_warnings_16kb
Change-Id: If33c1922e0968faad0a9d857fbbc9772dd67be90
parent 03fb9e8f
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.window.OnBackInvokedCallback;

import com.android.internal.content.LibraryAlignmentInfo;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForBoolean;
@@ -1541,6 +1542,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
    @Retention(RetentionPolicy.SOURCE)
    public @interface PageSizeAppCompatFlags {}

    /**
     * If mPageSizeCompatFlags indicates a mismatch, this will contain detailed
     * information for each native library that was found to be unaligned.
     * @hide
     */
    public LibraryAlignmentInfo[] unalignedNativeLibraries;

    /** @hide */
    public String classLoaderName;

@@ -2121,6 +2129,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        allowCrossUidActivitySwitchFromBelow = orig.allowCrossUidActivitySwitchFromBelow;
        createTimestamp = SystemClock.uptimeMillis();
        mPageSizeAppCompatFlags = orig.mPageSizeAppCompatFlags;
        this.unalignedNativeLibraries = orig.unalignedNativeLibraries;
    }

    public String toString() {
@@ -2226,6 +2235,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        dest.writeInt(localeConfigRes);
        dest.writeInt(allowCrossUidActivitySwitchFromBelow ? 1 : 0);
        dest.writeInt(mPageSizeAppCompatFlags);
        dest.writeTypedArray(unalignedNativeLibraries, parcelableFlags);

        sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
    }
@@ -2327,6 +2337,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        localeConfigRes = source.readInt();
        allowCrossUidActivitySwitchFromBelow = source.readInt() != 0;
        mPageSizeAppCompatFlags = source.readInt();
        unalignedNativeLibraries = source.createTypedArray(LibraryAlignmentInfo.CREATOR);

        mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source);
        if (mKnownActivityEmbeddingCerts.isEmpty()) {
+22 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025, 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.internal.content;

parcelable LibraryAlignmentInfo {
    String libraryName;
    int errorCode;
}
+32 −11
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
@@ -188,7 +190,7 @@ public class NativeLibraryHelper {
            String abiToCopy, boolean extractNativeLibs, boolean debuggable,
            boolean pageSizeCompatDisabled);

    private static native int nativeCheckAlignment(
    private static native AlignmentResult nativeCheckAlignment(
            long handle,
            String sharedLibraryPath,
            String abi,
@@ -455,11 +457,9 @@ public class NativeLibraryHelper {
     * @param handle APK file to scan for native libraries
     * @param libraryRoot directory for libraries
     * @param abiOverride abiOverride for package
     * @return {@link Modes from ApplicationInfo.PageSizeAppCompat} if successful or error code
     *     which suggests undefined mode
     * @return {@link AlignmentResult} if successful or null
     */
    @ApplicationInfo.PageSizeAppCompatFlags
    public static int checkAlignmentForCompatMode(
    public static AlignmentResult checkAlignmentForCompatMode(
            Handle handle,
            String libraryRoot,
            boolean nativeLibraryRootRequiresIsa,
@@ -467,7 +467,7 @@ public class NativeLibraryHelper {
        // Keep the code below in sync with copyNativeBinariesForSupportedAbi
        int abi = findSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
        if (abi < 0) {
            return ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
            return null;
        }

        final String supportedAbi = Build.SUPPORTED_64_BIT_ABIS[abi];
@@ -478,20 +478,26 @@ public class NativeLibraryHelper {
        }

        int mode = ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
        List<LibraryAlignmentInfo> unalignedLibraries = new ArrayList<LibraryAlignmentInfo>();

        for (long apkHandle : handle.apkHandles) {
            int res =
            AlignmentResult res =
                    nativeCheckAlignment(
                            apkHandle,
                            subDir,
                            Build.SUPPORTED_64_BIT_ABIS[abi],
                            handle.extractNativeLibs,
                            handle.debuggable);
            if (res == ApplicationInfo.PAGE_SIZE_APP_COMPAT_FLAG_ERROR) {
                return res;
            if (res == null) {
                return null;
            }
            mode |= res;
            mode |= res.flags;
            if (res.unalignedLibraries != null) {
                Collections.addAll(unalignedLibraries, res.unalignedLibraries);
            }
        return mode;
        }

        return new AlignmentResult(mode, unalignedLibraries.toArray(new LibraryAlignmentInfo[0]));
    }

    public static long sumNativeBinariesWithOverride(Handle handle, String abiOverride)
@@ -611,4 +617,19 @@ public class NativeLibraryHelper {
        }
        return false;
    }

    /**
     * A container to hold the complete result of a native library alignment check.
     */
    public static class AlignmentResult {
        @ApplicationInfo.PageSizeAppCompatFlags
        public final int flags;
        public final LibraryAlignmentInfo[] unalignedLibraries;

        public AlignmentResult(@ApplicationInfo.PageSizeAppCompatFlags int flags,
                LibraryAlignmentInfo[] unalignedLibraries) {
            this.flags = flags;
            this.unalignedLibraries = unalignedLibraries;
        }
    }
}
+77 −10
Original line number Diff line number Diff line
@@ -62,6 +62,18 @@ enum install_status_t {
    NO_NATIVE_LIBRARIES = -114
};

struct {
    jclass clazz;
    jmethodID constructor;
    jfieldID libraryName;
    jfieldID errorCode;
} gLibraryAlignmentInfo;

struct {
    jclass clazz;
    jmethodID constructor;
} gAlignmentResult;

// These code should match with PageSizeAppCompatFlags inside ApplicationInfo.java
constexpr int PAGE_SIZE_APP_COMPAT_FLAG_ERROR = -1;
constexpr int PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED = 0;
@@ -748,22 +760,20 @@ static jint checkAlignment(JNIEnv* env, jstring javaNativeLibPath, jboolean extr
    return mode;
}

// TODO(b/371049373): This function is copy of iterateOverNativeFiles with different way of handling
// and combining return values for all ELF and APKs. Find a way to consolidate two functions.
static jint com_android_internal_content_NativeLibraryHelper_checkApkAlignment(
static jobject com_android_internal_content_NativeLibraryHelper_checkApkAlignment(
        JNIEnv* env, jclass clazz, jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
        jboolean extractNativeLibs, jboolean debuggable) {
    int mode = PAGE_SIZE_APP_COMPAT_FLAG_UNDEFINED;
    ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
    if (zipFile == nullptr) {
        ALOGE("zipfile handle is null");
        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
        return nullptr;
    }

    auto result = NativeLibrariesIterator::create(zipFile);
    if (!result.ok()) {
        ALOGE("Can't iterate over native libs for file:%s", zipFile->getZipFileName());
        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
        return nullptr;
    }
    std::unique_ptr<NativeLibrariesIterator> it(std::move(result.value()));

@@ -771,14 +781,20 @@ static jint com_android_internal_content_NativeLibraryHelper_checkApkAlignment(
    if (cpuAbi.c_str() == nullptr) {
        ALOGE("cpuAbi is nullptr");
        // This would've thrown, so this return code isn't observable by Java.
        return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
        return nullptr;
    }

    struct LibInfo {
        std::string name;
        int errorCode;
    };
    std::vector<LibInfo> unalignedLibsInfo;

    while (true) {
        auto next = it->next();
        if (!next.ok()) {
            ALOGE("next iterator not found Error:%d", next.error());
            return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
            return nullptr;
        }
        auto entry = next.value();
        if (entry == nullptr) {
@@ -799,13 +815,46 @@ static jint com_android_internal_content_NativeLibraryHelper_checkApkAlignment(
            if (ret == PAGE_SIZE_APP_COMPAT_FLAG_ERROR) {
                ALOGE("Alignment check returned for zipfile: %s, entry:%s",
                      zipFile->getZipFileName(), lastSlash + 1);
                return PAGE_SIZE_APP_COMPAT_FLAG_ERROR;
                return nullptr;
            }
            mode |= ret;
            unalignedLibsInfo.push_back({fileName, ret});
        }
    }

    return mode;
    // Create and Populate the Java Object Array for LibraryAlignmentInfo
    ScopedLocalRef<jobjectArray> unalignedInfoObjects(env, nullptr);
    if (!unalignedLibsInfo.empty()) {
        unalignedInfoObjects.reset(env->NewObjectArray(unalignedLibsInfo.size(),
                                                       gLibraryAlignmentInfo.clazz, nullptr));
        if (unalignedInfoObjects.get() == nullptr) {
            ALOGE("Failed to allocate libinfo array for zipfile: %s", zipFile->getZipFileName());
            return nullptr;
        }

        for (size_t index = 0; index < unalignedLibsInfo.size(); ++index) {
            ScopedLocalRef<jobject> libInfo(env,
                                            env->NewObject(gLibraryAlignmentInfo.clazz,
                                                           gLibraryAlignmentInfo.constructor));

            ScopedLocalRef<jstring> libName(env,
                                            env->NewStringUTF(
                                                    unalignedLibsInfo[index].name.c_str()));
            jint errorCode = unalignedLibsInfo[index].errorCode;

            env->SetObjectField(libInfo.get(), gLibraryAlignmentInfo.libraryName, libName.get());
            env->SetIntField(libInfo.get(), gLibraryAlignmentInfo.errorCode, errorCode);
            env->SetObjectArrayElement(unalignedInfoObjects.get(), index, libInfo.get());
        }
    }

    // Create the final result object.
    ScopedLocalRef<jobject> finalResultObj(env,
                                           env->NewObject(gAlignmentResult.clazz,
                                                          gAlignmentResult.constructor, mode,
                                                          unalignedInfoObjects.get()));

    return finalResultObj.release();
}

static void
@@ -828,12 +877,30 @@ static const JNINativeMethod gMethods[] = {
         (void*)com_android_internal_content_NativeLibraryHelper_findSupportedAbi},
        {"hasRenderscriptBitcode", "(J)I",
         (void*)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode},
        {"nativeCheckAlignment", "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
        {"nativeCheckAlignment",
         "(JLjava/lang/String;Ljava/lang/String;ZZ)Lcom/android/internal/content/"
         "NativeLibraryHelper$AlignmentResult;",
         (void*)com_android_internal_content_NativeLibraryHelper_checkApkAlignment},
};

int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env)
{
    jclass libInfoClass = FindClassOrDie(env, "com/android/internal/content/LibraryAlignmentInfo");
    gLibraryAlignmentInfo.clazz = MakeGlobalRefOrDie(env, libInfoClass);
    gLibraryAlignmentInfo.constructor =
            GetMethodIDOrDie(env, gLibraryAlignmentInfo.clazz, "<init>", "()V");
    gLibraryAlignmentInfo.libraryName =
            GetFieldIDOrDie(env, gLibraryAlignmentInfo.clazz, "libraryName", "Ljava/lang/String;");
    gLibraryAlignmentInfo.errorCode =
            GetFieldIDOrDie(env, gLibraryAlignmentInfo.clazz, "errorCode", "I");

    jclass alignmentResultClass =
            FindClassOrDie(env, "com/android/internal/content/NativeLibraryHelper$AlignmentResult");
    gAlignmentResult.clazz = MakeGlobalRefOrDie(env, alignmentResultClass);
    gAlignmentResult.constructor =
            GetMethodIDOrDie(env, gAlignmentResult.clazz, "<init>",
                             "(I[Lcom/android/internal/content/LibraryAlignmentInfo;)V");

    return RegisterMethodsOrDie(env,
            "com/android/internal/content/NativeLibraryHelper", gMethods, NELEM(gMethods));
}
+22 −3
Original line number Diff line number Diff line
@@ -218,23 +218,42 @@
    <!-- Message displayed in dialog when APK is not 16 KB aligned on 4 KB device. [CHAR LIMIT=NONE] -->
    <string name="page_size_compat_apk_warning_4kb">This warning is showing because this is a debuggable app which is currently being tested.
        If you are not the developer, please report this to the developer and ask for a non-debuggable app.
        &lt;br&gt;&lt;br&gt;
        This app isn\’t 16 KB compatible. APK alignment check failed.
        Please follow the steps on &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt; </string>
        Please follow the steps on &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;
        &lt;br&gt;&lt;br&gt;
        Following libraries are not properly aligned:
        &lt;br&gt;&lt;br&gt;
    </string>
    <!-- Message displayed in dialog when ELF is not 16 KB aligned on 4 KB device. [CHAR LIMIT=NONE] -->
    <string name="page_size_compat_elf_warning_4kb">This warning is showing because this is a debuggable app which is currently being tested.
        If you are not the developer, please report this to the developer and ask for a non-debuggable app.
        &lt;br&gt;&lt;br&gt;
        This app isn\’t 16 KB compatible. ELF alignment check failed.
        Please follow the steps on &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;</string>
        Please follow the steps on &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;
        &lt;br&gt;&lt;br&gt;
        Following libraries are not properly aligned:
        &lt;br&gt;&lt;br&gt;
    </string>
    <!-- Message displayed in dialog when APK and ELF are not 16 KB aligned on 4 KB device. [CHAR LIMIT=NONE] -->
    <string name="page_size_compat_apk_and_elf_warning_4kb">This warning is showing because this is a debuggable app which is currently being tested.
        If you are not the developer, please report this to the developer and ask for a non-debuggable app.
        &lt;br&gt;&lt;br&gt;
        This app isn\’t 16 KB compatible. APK and ELF alignment checks failed.
        Please follow the steps on &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;</string>
        Please follow the steps on &lt;a href=\"https://developer.android.com/16kb-page-size\"&gt;https://developer.android.com/16kb-page-size&lt;/a&gt;.
        &lt;br&gt;&lt;br&gt;
        Following libraries are not properly aligned:
        &lt;br&gt;&lt;br&gt;
    </string>
    <!--Confirmation text for page size mismatch dialog to never show-->
    <string name="page_size_compat_never_show"> Don\'t Show Again</string>
    <string name="page_size_compat_elf_not_aligned">&amp;#8226; %1$s : LOAD segment not aligned</string>
    <string name="page_size_compat_apk_not_aligned">&amp;#8226; %1$s : Uncompressed library not aligned</string>
    <string name="page_size_compat_apk_and_elf_not_aligned">&amp;#8226; %1$s : LOAD segment and uncompressed library are not aligned</string>
    <string name="page_size_compat_unknown">&amp;#8226; %1$s : Unknown error</string>
    <!-- Displayed to tell the user that caller ID is not provisioned for their SIM. -->
    <string name="serviceNotProvisioned">Service not provisioned.</string>
Loading