/*
 * 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.rollback;

import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.os.storage.StorageManager;
import android.util.IntArray;
import android.util.Log;
import android.util.SparseLongArray;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Encapsulates the logic for initiating userdata snapshots and rollbacks via installd.
 */
@VisibleForTesting
// TODO(narayan): Reason about the failure scenarios that involve one or more IPCs to installd
// failing. We need to decide what course of action to take if calls to snapshotAppData or
// restoreAppDataSnapshot fail.
public class AppDataRollbackHelper {
    private static final String TAG = "RollbackManager";

    private final Installer mInstaller;

    public AppDataRollbackHelper(Installer installer) {
        mInstaller = installer;
    }

    /**
     * Creates an app data snapshot for a specified {@code packageRollbackInfo}. Updates said {@code
     * packageRollbackInfo} with the inodes of the CE user data snapshot folders.
     */
    public void snapshotAppData(int snapshotId, PackageRollbackInfo packageRollbackInfo) {
        final int[] installedUsers = packageRollbackInfo.getInstalledUsers().toArray();
        for (int user : installedUsers) {
            final int storageFlags;
            if (isUserCredentialLocked(user)) {
                // We've encountered a user that hasn't unlocked on a FBE device, so we can't copy
                // across app user data until the user unlocks their device.
                Log.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
                storageFlags = Installer.FLAG_STORAGE_DE;
                packageRollbackInfo.addPendingBackup(user);
            } else {
                storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE;
            }

            try {
                long ceSnapshotInode = mInstaller.snapshotAppData(
                        packageRollbackInfo.getPackageName(), user, snapshotId, storageFlags);
                if ((storageFlags & Installer.FLAG_STORAGE_CE) != 0) {
                    packageRollbackInfo.putCeSnapshotInode(user, ceSnapshotInode);
                }
            } catch (InstallerException ie) {
                Log.e(TAG, "Unable to create app data snapshot for: "
                        + packageRollbackInfo.getPackageName() + ", userId: " + user, ie);
            }
        }
    }

    /**
     * Restores an app data snapshot for a specified {@code packageRollbackInfo}, for a specified
     * {@code userId}.
     *
     * @return {@code true} iff. a change to the {@code packageRollbackInfo} has been made. Changes
     *         to {@code packageRollbackInfo} are restricted to the removal or addition of {@code
     *         userId} to the list of pending backups or restores.
     */
    public boolean restoreAppData(int rollbackId, PackageRollbackInfo packageRollbackInfo,
            int userId, int appId, String seInfo) {
        int storageFlags = Installer.FLAG_STORAGE_DE;

        final IntArray pendingBackups = packageRollbackInfo.getPendingBackups();
        final List<RestoreInfo> pendingRestores = packageRollbackInfo.getPendingRestores();
        boolean changedRollbackData = false;

        // If we still have a userdata backup pending for this user, it implies that the user
        // hasn't unlocked their device between the point of backup and the point of restore,
        // so the data cannot have changed. We simply skip restoring CE data in this case.
        if (pendingBackups != null && pendingBackups.indexOf(userId) != -1) {
            pendingBackups.remove(pendingBackups.indexOf(userId));
            changedRollbackData = true;
        } else {
            // There's no pending CE backup for this user, which means that we successfully
            // managed to backup data for the user, which means we seek to restore it
            if (isUserCredentialLocked(userId)) {
                // We've encountered a user that hasn't unlocked on a FBE device, so we can't
                // copy across app user data until the user unlocks their device.
                pendingRestores.add(new RestoreInfo(userId, appId, seInfo));
                changedRollbackData = true;
            } else {
                // This user has unlocked, we can proceed to restore both CE and DE data.
                storageFlags = storageFlags | Installer.FLAG_STORAGE_CE;
            }
        }

        try {
            mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), appId, seInfo,
                    userId, rollbackId, storageFlags);
        } catch (InstallerException ie) {
            Log.e(TAG, "Unable to restore app data snapshot: "
                        + packageRollbackInfo.getPackageName(), ie);
        }

        return changedRollbackData;
    }

    /**
     * Deletes an app data snapshot with a given {@code rollbackId} for a specified package
     * {@code packageName} for a given {@code user}.
     */
    public void destroyAppDataSnapshot(int rollbackId, PackageRollbackInfo packageRollbackInfo,
            int user) {
        int storageFlags = Installer.FLAG_STORAGE_DE;
        final SparseLongArray ceSnapshotInodes = packageRollbackInfo.getCeSnapshotInodes();
        long ceSnapshotInode = ceSnapshotInodes.get(user);
        if (ceSnapshotInode > 0) {
            storageFlags |= Installer.FLAG_STORAGE_CE;
        }
        try {
            mInstaller.destroyAppDataSnapshot(packageRollbackInfo.getPackageName(), user,
                    ceSnapshotInode, rollbackId, storageFlags);
            if ((storageFlags & Installer.FLAG_STORAGE_CE) != 0) {
                ceSnapshotInodes.delete(user);
            }
        } catch (InstallerException ie) {
            Log.e(TAG, "Unable to delete app data snapshot for "
                        + packageRollbackInfo.getPackageName(), ie);
        }
    }

    /**
     * Computes the list of pending backups for {@code userId} given lists of rollbacks.
     * Packages pending backup for the given user are added to {@code pendingBackupPackages} along
     * with their corresponding {@code PackageRollbackInfo}.
     *
     * @return the list of {@code RollbackData} that has pending backups. Note that some of the
     *         backups won't be performed, because they might be counteracted by pending restores.
     */
    private static List<RollbackData> computePendingBackups(int userId,
            Map<String, PackageRollbackInfo> pendingBackupPackages,
            List<RollbackData> rollbacks) {
        List<RollbackData> rd = new ArrayList<>();

        for (RollbackData data : rollbacks) {
            for (PackageRollbackInfo info : data.info.getPackages()) {
                final IntArray pendingBackupUsers = info.getPendingBackups();
                if (pendingBackupUsers != null) {
                    final int idx = pendingBackupUsers.indexOf(userId);
                    if (idx != -1) {
                        pendingBackupPackages.put(info.getPackageName(), info);
                        if (rd.indexOf(data) == -1) {
                            rd.add(data);
                        }
                    }
                }
            }
        }
        return rd;
    }

    /**
     * Computes the list of pending restores for {@code userId} given lists of rollbacks.
     * Packages pending restore are added to {@code pendingRestores} along with their corresponding
     * {@code PackageRollbackInfo}.
     *
     * @return the list of {@code RollbackData} that has pending restores. Note that some of the
     *         restores won't be performed, because they might be counteracted by pending backups.
     */
    private static List<RollbackData> computePendingRestores(int userId,
            Map<String, PackageRollbackInfo> pendingRestorePackages,
            List<RollbackData> rollbacks) {
        List<RollbackData> rd = new ArrayList<>();

        for (RollbackData data : rollbacks) {
            for (PackageRollbackInfo info : data.info.getPackages()) {
                final RestoreInfo ri = info.getRestoreInfo(userId);
                if (ri != null) {
                    pendingRestorePackages.put(info.getPackageName(), info);
                    if (rd.indexOf(data) == -1) {
                        rd.add(data);
                    }
                }
            }
        }

        return rd;
    }

    /**
     * Commits the list of pending backups and restores for a given {@code userId}. For the pending
     * backups updates corresponding {@code changedRollbackData} with a mapping from {@code userId}
     * to a inode of theirs CE user data snapshot.
     *
     * @return the set of {@code RollbackData} that have been changed and should be stored on disk.
     */
    public Set<RollbackData> commitPendingBackupAndRestoreForUser(int userId,
            List<RollbackData> rollbacks) {

        final Map<String, PackageRollbackInfo> pendingBackupPackages = new HashMap<>();
        final List<RollbackData> pendingBackups = computePendingBackups(userId,
                pendingBackupPackages, rollbacks);

        final Map<String, PackageRollbackInfo> pendingRestorePackages = new HashMap<>();
        final List<RollbackData> pendingRestores = computePendingRestores(userId,
                pendingRestorePackages, rollbacks);

        // First remove unnecessary backups, i.e. when user did not unlock their phone between the
        // request to backup data and the request to restore it.
        Iterator<Map.Entry<String, PackageRollbackInfo>> iter =
                pendingBackupPackages.entrySet().iterator();
        while (iter.hasNext()) {
            PackageRollbackInfo backupPackage = iter.next().getValue();
            PackageRollbackInfo restorePackage =
                    pendingRestorePackages.get(backupPackage.getPackageName());
            if (restorePackage != null) {
                backupPackage.removePendingBackup(userId);
                backupPackage.removePendingRestoreInfo(userId);
                iter.remove();
                pendingRestorePackages.remove(backupPackage.getPackageName());
            }
        }

        if (!pendingBackupPackages.isEmpty()) {
            for (RollbackData data : pendingBackups) {
                for (PackageRollbackInfo info : data.info.getPackages()) {
                    final IntArray pendingBackupUsers = info.getPendingBackups();
                    final int idx = pendingBackupUsers.indexOf(userId);
                    if (idx != -1) {
                        try {
                            long ceSnapshotInode = mInstaller.snapshotAppData(info.getPackageName(),
                                    userId, data.info.getRollbackId(), Installer.FLAG_STORAGE_CE);
                            info.putCeSnapshotInode(userId, ceSnapshotInode);
                            pendingBackupUsers.remove(idx);
                        } catch (InstallerException ie) {
                            Log.e(TAG,
                                    "Unable to create app data snapshot for: "
                                    + info.getPackageName() + ", userId: " + userId, ie);
                        }
                    }
                }
            }
        }

        if (!pendingRestorePackages.isEmpty()) {
            for (RollbackData data : pendingRestores) {
                for (PackageRollbackInfo info : data.info.getPackages()) {
                    final RestoreInfo ri = info.getRestoreInfo(userId);
                    if (ri != null) {
                        try {
                            mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId,
                                    ri.seInfo, userId, data.info.getRollbackId(),
                                    Installer.FLAG_STORAGE_CE);
                            info.removeRestoreInfo(ri);
                        } catch (InstallerException ie) {
                            Log.e(TAG, "Unable to restore app data snapshot for: "
                                    + info.getPackageName(), ie);
                        }
                    }
                }
            }
        }

        final Set<RollbackData> changed = new HashSet<>(pendingBackups);
        changed.addAll(pendingRestores);
        return changed;
    }

    /**
     * @return {@code true} iff. {@code userId} is locked on an FBE device.
     */
    @VisibleForTesting
    public boolean isUserCredentialLocked(int userId) {
        return StorageManager.isFileEncryptedNativeOrEmulated()
                && !StorageManager.isUserKeyUnlocked(userId);
    }
}
