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

Commit 5a9aaf69 authored by Felka Chang's avatar Felka Chang
Browse files

Fix 0x10000 resource not found exception

An application "consumer" needs a static library "provider" that
needs another static library "recursive". The recursive static library
will change its code path to another path although Install Process
uses the same apk to install twice.

The "recursive" library directory change its installation
directories. And, the old installation directory has been removed.
The remove operation reveals an error that resources use the
old recursive static library apk path.

Root cause: "consumer" reference "recursive" indirectly. PackageSetting
of "consumer"  doesn't notify the changes when its library files are
updated as a different list.

Solution: It calls PackageSetting.onChanged() when the parameter
usesLibraryFiles is different from
PackageSetting.getUsesLibraryFiles().

Fixes: 201750896

Test: TP="FrameworksServicesTests"; \
    atest ${TP}:com.android.server.pm.PackageManagerSettingsTests
Test: atest \
    CtsOsHostTestCases:android.os.cts.StaticSharedLibsHostTests
Change-Id: Ia8ab7a67ca2d5729d8b4c0f9e53a7deaa760f914
parent 387615bf
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -5226,7 +5226,8 @@ public class PackageManagerService extends IPackageManager.Stub
                addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib,
                addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib,
                        changingLibSetting);
                        changingLibSetting);
            }
            }
            pkgSetting.getPkgState().setUsesLibraryFiles(new ArrayList<>(usesLibraryFiles));
            pkgSetting.setPkgStateLibraryFiles(usesLibraryFiles);

            // let's make sure we mark all static shared libraries as installed for the same users
            // let's make sure we mark all static shared libraries as installed for the same users
            // that its dependent packages are installed for.
            // that its dependent packages are installed for.
            int[] installedUsers = new int[allUsers.length];
            int[] installedUsers = new int[allUsers.length];
+16 −0
Original line number Original line Diff line number Diff line
@@ -443,6 +443,22 @@ public class PackageSetting extends SettingBase implements PackageState {
        return this;
        return this;
    }
    }


    /**
     * Notify {@link #onChanged()}  if the parameter {@code usesLibraryFiles} is different from
     * {@link #getUsesLibraryFiles()}.
     * @param usesLibraryFiles the new uses library files
     * @return {@code this}
     */
    public PackageSetting setPkgStateLibraryFiles(@NonNull Collection<String> usesLibraryFiles) {
        final Collection<String> oldUsesLibraryFiles = getUsesLibraryFiles();
        if (oldUsesLibraryFiles.size() != usesLibraryFiles.size()
                || !oldUsesLibraryFiles.containsAll(usesLibraryFiles)) {
            pkgState.setUsesLibraryFiles(new ArrayList<>(usesLibraryFiles));
            onChanged();
        }
        return this;
    }

    public PackageSetting setPrimaryCpuAbi(String primaryCpuAbiString) {
    public PackageSetting setPrimaryCpuAbi(String primaryCpuAbiString) {
        this.mPrimaryCpuAbi = primaryCpuAbiString;
        this.mPrimaryCpuAbi = primaryCpuAbiString;
        onChanged();
        onChanged();
+93 −1
Original line number Original line Diff line number Diff line
@@ -29,9 +29,9 @@ import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.when;
@@ -63,8 +63,10 @@ import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableTester;
import com.android.server.utils.WatchableTester;
import com.android.server.utils.WatchedArrayMap;
import com.android.server.utils.WatchedArrayMap;
import com.android.server.utils.Watcher;


import com.google.common.truth.Truth;
import com.google.common.truth.Truth;


@@ -83,6 +85,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.List;
import java.util.List;
import java.util.UUID;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;


@RunWith(AndroidJUnit4.class)
@RunWith(AndroidJUnit4.class)
@SmallTest
@SmallTest
@@ -874,6 +877,95 @@ public class PackageManagerSettingsTests {
                false /*notLaunched*/, false /*stopped*/, true /*installed*/);
                false /*notLaunched*/, false /*stopped*/, true /*installed*/);
    }
    }


    @Test
    public void testSetPkgStateLibraryFiles_addNewFiles() {
        final PackageSetting packageSetting = createPackageSetting("com.foo");
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        packageSetting.registerObserver(new Watcher() {
            @Override
            public void onChange(Watchable what) {
                countDownLatch.countDown();
            }
        });

        final List<String> newUsesLibraryFiles = new ArrayList<>();
        newUsesLibraryFiles.add("code/path/A.apk");
        newUsesLibraryFiles.add("code/path/B.apk");
        packageSetting.setPkgStateLibraryFiles(newUsesLibraryFiles);

        assertThat(countDownLatch.getCount(), is(0L));
    }

    @Test
    public void testSetPkgStateLibraryFiles_removeOneExistingFile() {
        final PackageSetting packageSetting = createPackageSetting("com.foo");
        final List<String> oldUsesLibraryFiles = new ArrayList<>();
        oldUsesLibraryFiles.add("code/path/A.apk");
        oldUsesLibraryFiles.add("code/path/B.apk");
        oldUsesLibraryFiles.add("code/path/C.apk");
        packageSetting.setPkgStateLibraryFiles(oldUsesLibraryFiles);
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        packageSetting.registerObserver(new Watcher() {
            @Override
            public void onChange(Watchable what) {
                countDownLatch.countDown();
            }
        });

        final List<String> newUsesLibraryFiles = new ArrayList<>();
        oldUsesLibraryFiles.add("code/path/A.apk");
        oldUsesLibraryFiles.add("code/path/B.apk");
        packageSetting.setPkgStateLibraryFiles(newUsesLibraryFiles);

        assertThat(countDownLatch.getCount(), is(0L));
    }

    @Test
    public void testSetPkgStateLibraryFiles_changeOneOfFile() {
        final PackageSetting packageSetting = createPackageSetting("com.foo");
        final List<String> oldUsesLibraryFiles = new ArrayList<>();
        oldUsesLibraryFiles.add("code/path/A.apk");
        oldUsesLibraryFiles.add("code/path/B.apk");
        packageSetting.setPkgStateLibraryFiles(oldUsesLibraryFiles);
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        packageSetting.registerObserver(new Watcher() {
            @Override
            public void onChange(Watchable what) {
                countDownLatch.countDown();
            }
        });

        final List<String> newUsesLibraryFiles = new ArrayList<>();
        newUsesLibraryFiles.add("code/path/A.apk");
        newUsesLibraryFiles.add("code/path/B-1.apk");
        packageSetting.setPkgStateLibraryFiles(newUsesLibraryFiles);

        assertThat(countDownLatch.getCount(), is(0L));
    }

    @Test
    public void testSetPkgStateLibraryFiles_nothingChanged() {
        final PackageSetting packageSetting = createPackageSetting("com.foo");
        final List<String> oldUsesLibraryFiles = new ArrayList<>();
        oldUsesLibraryFiles.add("code/path/A.apk");
        oldUsesLibraryFiles.add("code/path/B.apk");
        packageSetting.setPkgStateLibraryFiles(oldUsesLibraryFiles);
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        packageSetting.registerObserver(new Watcher() {
            @Override
            public void onChange(Watchable what) {
                countDownLatch.countDown();
            }
        });

        final List<String> newUsesLibraryFiles = new ArrayList<>();
        newUsesLibraryFiles.add("code/path/A.apk");
        newUsesLibraryFiles.add("code/path/B.apk");
        packageSetting.setPkgStateLibraryFiles(newUsesLibraryFiles);

        assertThat(countDownLatch.getCount(), is(1L));
    }

    private <T> void assertArrayEquals(T[] a, T[] b) {
    private <T> void assertArrayEquals(T[] a, T[] b) {
        assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b),
        assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b),
                Arrays.equals(a, b));
                Arrays.equals(a, b));