chromium/chrome/android/javatests/src/org/chromium/chrome/browser/ServicificationBackgroundServiceTest.java

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser;

import androidx.test.filters.LargeTest;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;

import com.google.android.gms.gcm.TaskParams;

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

import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.init.MinimalBrowserStartupUtils;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Tests background tasks can be run in minimal browser mode, i.e., without starting the full
 * browser.
 */
@RunWith(ChromeJUnit4ClassRunner.class)
public final class ServicificationBackgroundServiceTest {
    private ServicificationBackgroundService mServicificationBackgroundService;
    private RandomAccessFile mMappedSpareFile;
    private File mSpareFile;

    /**
     * The size of the persistent/shared memory to store histograms. It should be consistent with
     * the |kAllocSize| in persistent_histograms.cc.
     */
    private static final int ALLOC_SIZE = 4 << 20; // 4 MiB

    private static final String APP_CHROME_DIR = "app_chrome";
    private static final String SPARE_FILE_NAME = "BrowserMetrics-spare.pma";
    private static final String TAG = "ServicifiStartupTest";

    @Before
    public void setUp() {
        mServicificationBackgroundService =
                new ServicificationBackgroundService(/* supportsMinimalBrowser= */ true);
    }

    @After
    public void tearDown() {
        closeBrowserMetricsSpareFile();
    }

    // Creates the memory-mapped file which is used to persist histograms data before native is
    // loaded.
    private void createBrowserMetricsSpareFile() {
        File appChromeDir =
                new File(
                        ContextUtils.getApplicationContext().getApplicationInfo().dataDir,
                        APP_CHROME_DIR);
        if (!appChromeDir.exists()) appChromeDir.mkdir();

        mSpareFile = new File(appChromeDir + File.separator + SPARE_FILE_NAME);
        try {
            mSpareFile.createNewFile();
        } catch (IOException e) {
            Log.d(TAG, "Fail to create file: %s", SPARE_FILE_NAME);
            return;
        }

        try {
            mMappedSpareFile = new RandomAccessFile(mSpareFile, "rw");

            MappedByteBuffer mappedByteBuffer =
                    mMappedSpareFile
                            .getChannel()
                            .map(FileChannel.MapMode.READ_WRITE, 0, ALLOC_SIZE);

            mappedByteBuffer.put(0, (byte) 0);
            mappedByteBuffer.force();
            Assert.assertTrue(Byte.compare(mappedByteBuffer.get(0), (byte) 0) == 0);
        } catch (Exception e) {
            Log.d(TAG, "Fail to create memory-mapped file: %s", SPARE_FILE_NAME);
        }
    }

    private void closeBrowserMetricsSpareFile() {
        if (mMappedSpareFile == null) return;

        try {
            mMappedSpareFile.close();
        } catch (IOException e) {
            Log.d(TAG, "Fail to close memory-mapped file: %s", SPARE_FILE_NAME);
        }
    }

    private static void startServiceAndWaitForNative(
            ServicificationBackgroundService backgroundService) {
        backgroundService.onRunTask(new TaskParams(MinimalBrowserStartupUtils.TASK_TAG));
        backgroundService.assertLaunchBrowserCalled();
        backgroundService.waitForNativeLoaded();
    }

    @Test
    @LargeTest
    @Feature({"ServicificationStartup"})
    @CommandLineFlags.Add({
        "force-fieldtrials=*Foo/Bar",
        "enable-features=UMABackgroundSessions",
        // TODO(crbug.com/40285326): This fails with the field trial testing config.
        "disable-field-trial-config"
    })
    @Restriction({Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE}) // crbug.com/1096833
    // Verifies that the memory-mapped file for persistent histogram data exists and contains a
    // valid SystemProfile. This test isn't run on low end devices which use local memory for
    // storing histogram data.
    public void testHistogramsPersistedWithMinimalBrowserStart() {
        createBrowserMetricsSpareFile();
        Assert.assertTrue(mSpareFile.exists());

        startServiceAndWaitForNative(mServicificationBackgroundService);
        ServicificationBackgroundService.assertMinimalBrowserStarted();

        mServicificationBackgroundService.assertPersistentHistogramsOnDiskSystemProfile();
        ServicificationBackgroundService.assertMinimalBrowserStarted();
    }

    @Test
    @SmallTest
    @Feature({"ServicificationStartup"})
    public void testBackgroundSessionStart() {
        startServiceAndWaitForNative(mServicificationBackgroundService);

        mServicificationBackgroundService.assertBackgroundSessionStart();
        ServicificationBackgroundService.assertMinimalBrowserStarted();
    }

    @Test
    @MediumTest
    @Feature({"ServicificationStartup"})
    public void testFullBrowserStartsAfterMinimalBrowser() {
        startServiceAndWaitForNative(mServicificationBackgroundService);
        ServicificationBackgroundService.assertMinimalBrowserStarted();

        // Now native is loaded in minimal browser mode, lets try and load the full browser to
        // test the transition from minimal browser to full browser.
        mServicificationBackgroundService.setSupportsMinimalBrowser(false);
        startServiceAndWaitForNative(mServicificationBackgroundService);
        ServicificationBackgroundService.assertFullBrowserStarted();
    }
}