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

Commit 727aaa36 authored by Shubham Ajmera's avatar Shubham Ajmera
Browse files

Handle '&' in DexoptUtils#encodeClassLoader

For system apps, we pass '&' for CLC.
The method was treating this as a path as a result we were getting
wrong encoding for CLC.
This was causing dexopt failures for A/B OTA.

Removed the secondary dex file dexopt till we fixed it.

Bug: 65067046
Test: runtest.py -x \
  frameworks/base/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
(cherry-picked from commit 557c0549)
Change-Id: I9aa440750c811676c86d8c6d0d451077d0edf5a0
parent b338f034
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
    private final static boolean DEBUG_DEXOPT = true;

    // The synthetic library dependencies denoting "no checks."
    private final static String[] NO_LIBRARIES = new String[] { "&" };
    private final static String[] NO_LIBRARIES =
            new String[] { PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK };

    // The amount of "available" (free - low threshold) space necessary at the start of an OTA to
    // not bulk-delete unused apps' odex files.
+15 −2
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.os.ClassLoaderFactory;
import com.android.server.pm.PackageDexOptimizer;

import java.io.File;
import java.util.ArrayList;
@@ -238,10 +239,15 @@ public final class DexoptUtils {
    /**
     * Encodes a single class loader dependency starting from {@param path} and
     * {@param classLoaderName}.
     * When classpath is {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns
     * the same. This special property is used only during OTA.
     * NOTE: Keep this in sync with the dexopt expectations! Right now that is either "PCL[path]"
     * for a PathClassLoader or "DLC[path]" for a DelegateLastClassLoader.
     */
    private static String encodeClassLoader(String classpath, String classLoaderName) {
    /*package*/ static String encodeClassLoader(String classpath, String classLoaderName) {
        if (classpath.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK)) {
            return classpath;
        }
        String classLoaderDexoptEncoding = classLoaderName;
        if (ClassLoaderFactory.isPathClassLoaderName(classLoaderName)) {
            classLoaderDexoptEncoding = "PCL";
@@ -255,10 +261,17 @@ public final class DexoptUtils {

    /**
     * Links to dependencies together in a format accepted by dexopt.
     * For the special case when either of cl1 or cl2 equals
     * {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns the same. This
     * property is used only during OTA.
     * NOTE: Keep this in sync with the dexopt expectations! Right now that is a list of split
     * dependencies {@see encodeClassLoader} separated by ';'.
     */
    private static String encodeClassLoaderChain(String cl1, String cl2) {
    /*package*/ static String encodeClassLoaderChain(String cl1, String cl2) {
        if (cl1.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK) ||
                cl2.equals(PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK)) {
            return PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK;
        }
        if (cl1.isEmpty()) return cl2;
        if (cl2.isEmpty()) return cl1;
        return cl1 + ";" + cl2;
+49 −0
Original line number Diff line number Diff line
@@ -16,10 +16,14 @@

package com.android.server.pm.dex;

import com.android.server.pm.PackageDexOptimizer;

import static com.android.server.pm.PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.content.pm.ApplicationInfo;
import android.support.test.filters.SmallTest;
@@ -369,4 +373,49 @@ public class DexoptUtilsTest {
        }
        assertTrue(gotException);
    }

    @Test
    public void testEncodeClassLoader() {
        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.PathClassLoader"));
        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.DexClassLoader"));
        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoader(
                SKIP_SHARED_LIBRARY_CHECK, "dalvik.system.DelegateLastClassLoader"));
        assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz",
                "dalvik.system.PathClassLoader"));
        assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz",
                "dalvik.system.DexClassLoader"));
        assertEquals("DLC[xyz]", DexoptUtils.encodeClassLoader("xyz",
                "dalvik.system.DelegateLastClassLoader"));
        assertEquals("PCL[xyz]", DexoptUtils.encodeClassLoader("xyz", null));
        assertEquals("abc[xyz]", DexoptUtils.encodeClassLoader("xyz", "abc"));

        try {
            DexoptUtils.encodeClassLoader(null, "abc");
            fail(); // Exception should be caught.
        } catch (NullPointerException expected) {}
    }

    @Test
    public void testEncodeClassLoaderChain() {
        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain(
                SKIP_SHARED_LIBRARY_CHECK, "PCL[a]"));
        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain("PCL[a]",
                SKIP_SHARED_LIBRARY_CHECK));
        assertEquals("PCL[a];DLC[b]", DexoptUtils.encodeClassLoaderChain("PCL[a]",
                "DLC[b]"));
        assertEquals(SKIP_SHARED_LIBRARY_CHECK, DexoptUtils.encodeClassLoaderChain("PCL[a]",
                SKIP_SHARED_LIBRARY_CHECK));

        try {
            DexoptUtils.encodeClassLoaderChain("a", null);
            fail(); // exception is expected
        } catch (NullPointerException expected) {}

        try {
            DexoptUtils.encodeClassLoaderChain(null, "b");
            fail(); // exception is expected
        } catch (NullPointerException expected) {}
    }
}