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

Commit 4ba65f0a authored by Kohsuke Yatoh's avatar Kohsuke Yatoh
Browse files

Revert "Add crash detection and recovery."

This partially reverts the following commits:
- commit de417e73
- commit 45c62319

Reason for revert: Caused boot time regression.

Bug: 176939176
Bug: 181536798
Test: atest FrameworksServicesTests:UpdatableFontDirTest
Test: atest UpdatableSystemFontTest
Change-Id: Ibb5505018b24caa442fcbefda57aaa674ab9441e
parent e72cce52
Loading
Loading
Loading
Loading
+0 −92
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.graphics.fonts;

import android.annotation.NonNull;
import android.util.Slog;

import java.io.File;
import java.io.IOException;

/**
 * A class to detect font-related native crash.
 *
 * <p>If a fs-verity protected file is accessed through mmap and corrupted file block is detected,
 * SIGBUG signal is generated and the process will crash. To find corrupted files and remove them,
 * we use a marker file to detect crash.
 * <ol>
 *     <li>Create a marker file before reading fs-verity protected font files.
 *     <li>Delete the marker file after reading font files successfully.
 *     <li>If the marker file is found in the next process startup, it means that the process
 *         crashed before. We will delete font files to prevent crash loop.
 * </ol>
 *
 * <p>Example usage:
 * <pre>
 *     FontCrashDetector detector = new FontCrashDetector(new File("/path/to/marker_file"));
 *     if (detector.hasCrashed()) {
 *         // Do cleanup
 *     }
 *     try (FontCrashDetector.MonitoredBlock b = detector.start()) {
 *         // Read files
 *     }
 * </pre>
 *
 * <p>This class DOES NOT detect Java exceptions. If a Java exception is thrown while monitoring
 * crash, the marker file will be deleted. Creating and deleting marker files are not lightweight.
 * Please use this class sparingly with caution.
 */
/* package */ final class FontCrashDetector {

    private static final String TAG = "FontCrashDetector";

    @NonNull
    private final File mMarkerFile;

    /* package */ FontCrashDetector(@NonNull File markerFile) {
        mMarkerFile = markerFile;
    }

    /* package */ boolean hasCrashed() {
        return mMarkerFile.exists();
    }

    /* package */ void clear() {
        if (!mMarkerFile.delete()) {
            Slog.e(TAG, "Could not delete marker file: " + mMarkerFile);
        }
    }

    /** Starts crash monitoring. */
    /* package */ MonitoredBlock start() {
        try {
            mMarkerFile.createNewFile();
        } catch (IOException e) {
            Slog.e(TAG, "Could not create marker file: " + mMarkerFile, e);
        }
        return new MonitoredBlock();
    }

    /** A helper class to monitor crash with try-with-resources syntax. */
    /* package */ class MonitoredBlock implements AutoCloseable {
        /** Ends crash monitoring. */
        @Override
        public void close() {
            clear();
        }
    }
}
+6 −27
Original line number Diff line number Diff line
@@ -63,7 +63,6 @@ public final class FontManagerService extends IFontManager.Stub {
    private static final String TAG = "FontManagerService";

    private static final String FONT_FILES_DIR = "/data/fonts/files";
    private static final String CRASH_MARKER_FILE = "/data/fonts/config/crash.txt";

    @Override
    public FontConfig getFontConfig() {
@@ -199,10 +198,6 @@ public final class FontManagerService extends IFontManager.Stub {

    private final Object mUpdatableFontDirLock = new Object();

    @GuardedBy("mUpdatableFontDirLock")
    @NonNull
    private final FontCrashDetector mFontCrashDetector;

    @GuardedBy("mUpdatableFontDirLock")
    @Nullable
    private final UpdatableFontDir mUpdatableFontDir;
@@ -217,7 +212,6 @@ public final class FontManagerService extends IFontManager.Stub {

    private FontManagerService(Context context) {
        mContext = context;
        mFontCrashDetector = new FontCrashDetector(new File(CRASH_MARKER_FILE));
        mUpdatableFontDir = createUpdatableFontDir();
        initialize();
    }
@@ -244,21 +238,10 @@ public final class FontManagerService extends IFontManager.Stub {
                }
                return;
            }
            if (mFontCrashDetector.hasCrashed()) {
                Slog.i(TAG, "Crash detected. Clearing font updates.");
                try {
                    mUpdatableFontDir.clearUpdates();
                } catch (SystemFontException e) {
                    Slog.e(TAG, "Failed to clear updates.", e);
                }
                mFontCrashDetector.clear();
            }
            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
            mUpdatableFontDir.loadFontFileMap();
            updateSerializedFontMap();
        }
    }
    }

    @NonNull
    public Context getContext() {
@@ -286,12 +269,10 @@ public final class FontManagerService extends IFontManager.Stub {
                        FontManager.RESULT_ERROR_VERSION_MISMATCH,
                        "The base config version is older than current.");
            }
            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
            mUpdatableFontDir.update(requests);
            updateSerializedFontMap();
        }
    }
    }

    /* package */ void clearUpdates() throws SystemFontException {
        if (mUpdatableFontDir == null) {
@@ -300,12 +281,10 @@ public final class FontManagerService extends IFontManager.Stub {
                    "The font updater is disabled.");
        }
        synchronized (mUpdatableFontDirLock) {
            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
            mUpdatableFontDir.clearUpdates();
            updateSerializedFontMap();
        }
    }
    }

    /* package */ Map<String, File> getFontFileMap() {
        if (mUpdatableFontDir == null) {
+0 −77
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.graphics.fonts;

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

import android.content.Context;
import android.os.FileUtils;
import android.platform.test.annotations.Presubmit;

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

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

import java.io.File;

@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FontCrashDetectorTest {

    private File mCacheDir;

    @SuppressWarnings("ResultOfMethodCallIgnored")
    @Before
    public void setUp() {
        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
        mCacheDir = new File(context.getCacheDir(), "UpdatableFontDirTest");
        FileUtils.deleteContentsAndDir(mCacheDir);
        mCacheDir.mkdirs();
    }

    @Test
    public void detectCrash() throws Exception {
        // Prepare a marker file.
        File file = new File(mCacheDir, "detectCrash");
        assertThat(file.createNewFile()).isTrue();

        FontCrashDetector detector = new FontCrashDetector(file);
        assertThat(detector.hasCrashed()).isTrue();

        detector.clear();
        assertThat(detector.hasCrashed()).isFalse();
        assertThat(file.exists()).isFalse();
    }

    @Test
    public void monitorCrash() {
        File file = new File(mCacheDir, "monitorCrash");
        FontCrashDetector detector = new FontCrashDetector(file);
        assertThat(detector.hasCrashed()).isFalse();

        FontCrashDetector.MonitoredBlock block = detector.start();
        assertThat(file.exists()).isTrue();

        block.close();
        assertThat(file.exists()).isFalse();
    }
}
+0 −4
Original line number Diff line number Diff line
@@ -26,13 +26,9 @@ java_test_host {
    srcs: ["src/**/*.java"],
    libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
    static_libs: [
        "block_device_writer_jar",
        "frameworks-base-hostutils",
    ],
    test_suites: ["general-tests", "vts"],
    target_required: [
        "block_device_writer_module",
    ],
    data: [
        ":NotoColorEmojiTtf",
        ":UpdatableSystemFontTestCertDer",
+0 −1
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@

    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
        <option name="cleanup" value="true" />
        <option name="push" value="block_device_writer->/data/local/tmp/block_device_writer" />
        <option name="push" value="UpdatableSystemFontTestCert.der->/data/local/tmp/UpdatableSystemFontTestCert.der" />
        <option name="push" value="NotoColorEmoji.ttf->/data/local/tmp/NotoColorEmoji.ttf" />
        <option name="push" value="UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig->/data/local/tmp/UpdatableSystemFontTestNotoColorEmoji.ttf.fsv_sig" />
Loading