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

Commit a6a23f09 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Show native library info on compat warnings" into main

parents d91f6257 21bdaab5
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