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

Commit 8c706849 authored by Bill Lin's avatar Bill Lin Committed by android-build-merger
Browse files

Merge changes from topic "apex_migration" am: c29a5cf1

am: f17cec02

Change-Id: I4d8193a9f6bba48b4d167a4cdbaaf80d6280f472
parents 0c91cb29 f17cec02
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ import android.sysprop.ApexProperties;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;

import java.io.File;
@@ -216,7 +218,8 @@ abstract class ApexManager {
     * An implementation of {@link ApexManager} that should be used in case device supports updating
     * APEX packages.
     */
    private static class ApexManagerImpl extends ApexManager {
    @VisibleForTesting
    static class ApexManagerImpl extends ApexManager {
        private final IApexService mApexService;
        private final Context mContext;
        private final Object mLock = new Object();
@@ -260,7 +263,9 @@ abstract class ApexManager {
            mContext.registerReceiver(new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    populateAllPackagesCacheIfNeeded();
                    // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
                    // expensive to run it in broadcast handler thread.
                    BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
                    mContext.unregisterReceiver(this);
                }
            }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
@@ -332,8 +337,8 @@ abstract class ApexManager {
                if (!packageInfo.packageName.equals(packageName)) {
                    continue;
                }
                if ((!matchActive || isActive(packageInfo))
                        && (!matchFactory || isFactory(packageInfo))) {
                if ((matchActive && isActive(packageInfo))
                        || (matchFactory && isFactory(packageInfo))) {
                    return packageInfo;
                }
            }
+1 −1
Original line number Diff line number Diff line
@@ -4279,7 +4279,7 @@ public class PackageManagerService extends IPackageManager.Stub
                }
                return generatePackageInfo(ps, flags, userId);
            }
            if (!matchFactoryOnly && (flags & MATCH_APEX) != 0) {
            if ((flags & MATCH_APEX) != 0) {
                return mApexManager.getPackageInfo(packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
            }
        }
+311 KiB

File added.

No diff preview for this file type.

+298 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.server.pm;

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

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;

import android.apex.ApexInfo;
import android.apex.ApexSessionInfo;
import android.apex.IApexService;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.FileUtils;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;

import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.android.frameworks.servicestests.R;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ApexManagerTest {
    private static final String TEST_APEX_PKG = "com.android.apex.test";
    private static final int TEST_SESSION_ID = 99999999;
    private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777};
    private ApexManager mApexManager;
    private Context mContext;

    private IApexService mApexService = mock(IApexService.class);

    @Before
    public void setUp() throws RemoteException {
        mContext = InstrumentationRegistry.getInstrumentation().getContext();
        mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService);
    }

    @Test
    public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
        final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
                ApexManager.MATCH_ACTIVE_PACKAGE);

        assertThat(activePkgPi).isNotNull();
        assertThat(activePkgPi.packageName).contains(TEST_APEX_PKG);

        final PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
                ApexManager.MATCH_FACTORY_PACKAGE);

        assertThat(factoryPkgPi).isNull();
    }

    @Test
    public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
        PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
                ApexManager.MATCH_FACTORY_PACKAGE);

        assertThat(factoryPkgPi).isNotNull();
        assertThat(factoryPkgPi.packageName).contains(TEST_APEX_PKG);

        final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
                ApexManager.MATCH_ACTIVE_PACKAGE);

        assertThat(activePkgPi).isNull();
    }

    @Test
    public void testGetPackageInfo_setFlagsNone() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));

        assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
    }

    @Test
    public void testGetActivePackages() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));

        assertThat(mApexManager.getActivePackages()).isNotEmpty();
    }

    @Test
    public void testGetActivePackages_noneActivePackages() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));

        assertThat(mApexManager.getActivePackages()).isEmpty();
    }

    @Test
    public void testGetFactoryPackages() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));

        assertThat(mApexManager.getFactoryPackages()).isNotEmpty();
    }

    @Test
    public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));

        assertThat(mApexManager.getFactoryPackages()).isEmpty();
    }

    @Test
    public void testGetInactivePackages() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));

        assertThat(mApexManager.getInactivePackages()).isNotEmpty();
    }

    @Test
    public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));

        assertThat(mApexManager.getInactivePackages()).isEmpty();
    }

    @Test
    public void testIsApexPackage() throws RemoteException {
        when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));

        assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue();
    }

    @Test
    public void testIsApexSupported() {
        assertThat(mApexManager.isApexSupported()).isTrue();
    }

    @Test
    public void testGetStagedSessionInfo() throws RemoteException {
        when(mApexService.getStagedSessionInfo(anyInt())).thenReturn(
                getFakeStagedSessionInfo());

        mApexManager.getStagedSessionInfo(TEST_SESSION_ID);
        verify(mApexService, times(1)).getStagedSessionInfo(TEST_SESSION_ID);
    }

    @Test
    public void testGetStagedSessionInfo_unKnownStagedSessionId() throws RemoteException {
        when(mApexService.getStagedSessionInfo(anyInt())).thenReturn(
                getFakeUnknownSessionInfo());

        assertThat(mApexManager.getStagedSessionInfo(TEST_SESSION_ID)).isNull();
    }

    @Test
    public void testSubmitStagedSession_throwPackageManagerException() throws RemoteException {
        doAnswer(invocation -> {
            throw new Exception();
        }).when(mApexService).submitStagedSession(anyInt(), any(), any());

        assertThrows(PackageManagerException.class,
                () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
    }

    @Test
    public void testSubmitStagedSession_throwRunTimeException() throws RemoteException {
        doThrow(RemoteException.class).when(mApexService).submitStagedSession(anyInt(), any(),
                any());

        assertThrows(RuntimeException.class,
                () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID));
    }

    @Test
    public void testMarkStagedSessionReady_throwPackageManagerException() throws RemoteException {
        doAnswer(invocation -> {
            throw new Exception();
        }).when(mApexService).markStagedSessionReady(anyInt());

        assertThrows(PackageManagerException.class,
                () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
    }

    @Test
    public void testMarkStagedSessionReady_throwRunTimeException() throws RemoteException {
        doThrow(RemoteException.class).when(mApexService).markStagedSessionReady(anyInt());

        assertThrows(RuntimeException.class,
                () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID));
    }

    @Test
    public void testAbortActiveSession_remoteException() throws RemoteException {
        doThrow(RemoteException.class).when(mApexService).abortActiveSession();

        try {
            assertThat(mApexManager.abortActiveSession()).isFalse();
        } catch (Exception e) {
            throw new AssertionError("ApexManager should not raise Exception");
        }
    }

    @Test
    public void testMarkStagedSessionSuccessful_throwRemoteException() throws RemoteException {
        doThrow(RemoteException.class).when(mApexService).markStagedSessionSuccessful(anyInt());

        assertThrows(RuntimeException.class,
                () -> mApexManager.markStagedSessionSuccessful(TEST_SESSION_ID));
    }

    @Test
    public void testUninstallApex_throwException_returnFalse() throws RemoteException {
        doAnswer(invocation -> {
            throw new Exception();
        }).when(mApexService).unstagePackages(any());

        assertThat(mApexManager.uninstallApex(TEST_APEX_PKG)).isFalse();
    }

    private ApexInfo[] createApexInfo(boolean isActive, boolean isFactory) {
        File apexFile = copyRawResourceToFile(TEST_APEX_PKG, R.raw.apex_test);
        ApexInfo apexInfo = new ApexInfo();
        apexInfo.isActive = isActive;
        apexInfo.isFactory = isFactory;
        apexInfo.moduleName = TEST_APEX_PKG;
        apexInfo.modulePath = apexFile.getPath();
        apexInfo.versionCode = 191000070;

        return new ApexInfo[]{apexInfo};
    }

    private ApexSessionInfo getFakeStagedSessionInfo() {
        ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
        stagedSessionInfo.sessionId = TEST_SESSION_ID;
        stagedSessionInfo.isStaged = true;

        return stagedSessionInfo;
    }

    private ApexSessionInfo getFakeUnknownSessionInfo() {
        ApexSessionInfo stagedSessionInfo = new ApexSessionInfo();
        stagedSessionInfo.sessionId = TEST_SESSION_ID;
        stagedSessionInfo.isUnknown = true;

        return stagedSessionInfo;
    }

    /**
     * Copies a specified {@code resourceId} to a temp file. Returns a non-null file if the copy
     * succeeded
     */
    File copyRawResourceToFile(String baseName, int resourceId) {
        File outFile;
        try {
            outFile = File.createTempFile(baseName, ".apex");
        } catch (IOException e) {
            throw new AssertionError("CreateTempFile IOException" + e);
        }

        try (InputStream is = mContext.getResources().openRawResource(resourceId);
             FileOutputStream os = new FileOutputStream(outFile)) {
            assertThat(FileUtils.copy(is, os)).isGreaterThan(0L);
        } catch (FileNotFoundException e) {
            throw new AssertionError("File not found exception " + e);
        } catch (IOException e) {
            throw new AssertionError("IOException" + e);
        }

        return outFile;
    }
}