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

Commit f9084eca authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Persist task snapshots to disk

So they can be used again after rebooting or when the process gets
killed, but the snapshot is still used for recents.

Also implement TaskSnapshotLoader, to restore it from disk. The
infrastructure around restoring and caching snapshots for recents
will be implemented in the next CL.

Test: runtest frameworks-services -c
com.android.server.wm.TaskSnapshotPersisterLoaderTest

Bug: 31339431
Change-Id: Iaec03c4cc92e04b6dd7e623bca755ddc92613bce
parent 7a1f1d8a
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 */

 syntax = "proto3";

 package com.android.server.wm;

 option java_package = "com.android.server.wm";
 option java_outer_classname = "WindowManagerProtos";

 message TaskSnapshotProto {
     int32 orientation = 1;
     int32 inset_left = 2;
     int32 inset_top = 3;
     int32 inset_right = 4;
     int32 inset_bottom = 5;
 }
 No newline at end of file
+2 −0
Original line number Diff line number Diff line
@@ -651,6 +651,8 @@ public class TaskPersister {
                                        "omitting from persistentTaskIds task=" + task);
                            }
                        }
                        mService.mWindowManager.removeObsoleteTaskFiles(persistentTaskIds,
                                mRecentTasks.usersWithRecentsLoadedLocked());
                    }
                    removeObsoleteFiles(persistentTaskIds);
                }
+3 −0
Original line number Diff line number Diff line
@@ -788,6 +788,9 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta
            inRecents = false;
            mService.notifyTaskPersisterLocked(this, false);
        }

        // TODO: Use window container controller once tasks are better synced between AM and WM
        mService.mWindowManager.notifyTaskRemovedFromRecents(taskId, userId);
    }

    void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
+22 −1
Original line number Diff line number Diff line
@@ -22,11 +22,13 @@ import android.annotation.Nullable;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.GraphicBuffer;
import android.os.Environment;
import android.util.ArraySet;
import android.view.WindowManagerPolicy.StartingSurface;

import com.android.internal.annotations.VisibleForTesting;

import java.io.File;
import java.io.PrintWriter;

/**
@@ -45,14 +47,21 @@ import java.io.PrintWriter;
class TaskSnapshotController {

    private final WindowManagerService mService;
    private final TaskSnapshotCache mCache = new TaskSnapshotCache();

    private final TaskSnapshotCache mCache = new TaskSnapshotCache();
    private final TaskSnapshotPersister mPersister = new TaskSnapshotPersister(
            Environment::getDataSystemCeDirectory);
    private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister);
    private final ArraySet<Task> mTmpTasks = new ArraySet<>();

    TaskSnapshotController(WindowManagerService service) {
        mService = service;
    }

    void systemReady() {
        mPersister.start();
    }

    void onTransitionStarting() {
        if (!ENABLE_TASK_SNAPSHOTS) {
            return;
@@ -69,6 +78,7 @@ class TaskSnapshotController {
            final TaskSnapshot snapshot = snapshotTask(task);
            if (snapshot != null) {
                mCache.putSnapshot(task, snapshot);
                mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
                if (task.getController() != null) {
                    task.getController().reportSnapshotChanged(snapshot);
                }
@@ -141,6 +151,17 @@ class TaskSnapshotController {
        mCache.cleanCache(wtoken);
    }

    void notifyTaskRemovedFromRecents(int taskId, int userId) {
        mPersister.onTaskRemovedFromRecents(taskId, userId);
    }

    /**
     * See {@link TaskSnapshotPersister#removeObsoleteFiles}
     */
    void removeObsoleteTaskFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) {
        mPersister.removeObsoleteFiles(persistentTaskIds, runningUserIds);
    }

    void dump(PrintWriter pw, String prefix) {
        mCache.dump(pw, prefix);
    }
+93 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.wm;

import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;

import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.util.Slog;

import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

/**
 * Loads a persisted {@link TaskSnapshot} from disk.
 * <p>
 * Do not hold the window manager lock when accessing this class.
 * <p>
 * Test class: {@link TaskSnapshotPersisterLoaderTest}
 */
class TaskSnapshotLoader {

    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotLoader" : TAG_WM;

    private final TaskSnapshotPersister mPersister;

    TaskSnapshotLoader(TaskSnapshotPersister persister) {
        mPersister = persister;
    }

    /**
     * Loads a task from the disk.
     * <p>
     * Do not hold the window manager lock when calling this method, as we directly read data from
     * disk here, which might be slow.
     *
     * @param taskId The id of the task to load.
     * @param userId The id of the user the task belonged to.
     * @return The loaded {@link TaskSnapshot} or {@code null} if it couldn't be loaded.
     */
    TaskSnapshot loadTask(int taskId, int userId) {
        final File protoFile = mPersister.getProtoFile(taskId, userId);
        final File bitmapFile = mPersister.getBitmapFile(taskId, userId);
        if (!protoFile.exists() || !bitmapFile.exists()) {
            return null;
        }
        try {
            final byte[] bytes = Files.readAllBytes(protoFile.toPath());
            final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes);
            final Options options = new Options();
            options.inPreferredConfig = Config.HARDWARE;
            final Bitmap bitmap = BitmapFactory.decodeFile(bitmapFile.getPath(), options);
            if (bitmap == null) {
                Slog.w(TAG, "Failed to load bitmap: " + bitmapFile.getPath());
                return null;
            }
            final GraphicBuffer buffer = bitmap.createGraphicBufferHandle();
            if (buffer == null) {
                Slog.w(TAG, "Failed to retrieve gralloc buffer for bitmap: "
                        + bitmapFile.getPath());
                return null;
            }
            return new TaskSnapshot(buffer, proto.orientation,
                    new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom));
        } catch (IOException e) {
            Slog.w(TAG, "Unable to load task snapshot data for taskId=" + taskId);
            return null;
        }
    }
}
Loading