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

import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Handler;
import android.os.IVold;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
import android.provider.MediaStore;
import android.service.storage.ExternalStorageService;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;

import java.io.FileDescriptor;

/**
 * Controls storage sessions for users initiated by the {@link StorageManagerService}.
 * Each user on the device will be represented by a {@link StorageUserConnection}.
 */
public final class StorageSessionController {
    private static final String TAG = "StorageSessionController";

    private final Object mLock = new Object();
    private final Context mContext;
    @GuardedBy("mLock")
    private final SparseArray<StorageUserConnection> mConnections = new SparseArray<>();
    private final boolean mIsFuseEnabled;

    private volatile ComponentName mExternalStorageServiceComponent;
    private volatile String mExternalStorageServicePackageName;
    private volatile int mExternalStorageServiceAppId;
    private volatile boolean mIsResetting;

    public StorageSessionController(Context context, boolean isFuseEnabled) {
        mContext = Preconditions.checkNotNull(context);
        mIsFuseEnabled = isFuseEnabled;
    }

    /**
     * Creates and starts a storage session associated with {@code deviceFd} for {@code vol}.
     * Sessions can be started with {@link #onVolumeReady} and removed with {@link #onVolumeUnmount}
     * or {@link #onVolumeRemove}.
     *
     * Throws an {@link IllegalStateException} if a session for {@code vol} has already been created
     *
     * Does nothing if {@link #shouldHandle} is {@code false}
     *
     * Blocks until the session is started or fails
     *
     * @throws ExternalStorageServiceException if the session fails to start
     * @throws IllegalStateException if a session has already been created for {@code vol}
     */
    public void onVolumeMount(FileDescriptor deviceFd, VolumeInfo vol)
            throws ExternalStorageServiceException {
        if (!shouldHandle(vol)) {
            return;
        }

        Slog.i(TAG, "On volume mount " + vol);

        String sessionId = vol.getId();
        int userId = vol.getMountUserId();

        StorageUserConnection connection = null;
        synchronized (mLock) {
            connection = mConnections.get(userId);
            if (connection == null) {
                Slog.i(TAG, "Creating connection for user: " + userId);
                connection = new StorageUserConnection(mContext, userId, this);
                mConnections.put(userId, connection);
            }
            Slog.i(TAG, "Creating and starting session with id: " + sessionId);
            connection.startSession(sessionId, new ParcelFileDescriptor(deviceFd),
                    vol.getPath().getPath(), vol.getInternalPath().getPath());
        }
    }

    /**
     * Removes and returns the {@link StorageUserConnection} for {@code vol}.
     *
     * Does nothing if {@link #shouldHandle} is {@code false}
     *
     * @return the connection that was removed or {@code null} if nothing was removed
     */
    @Nullable
    public StorageUserConnection onVolumeRemove(VolumeInfo vol) {
        if (!shouldHandle(vol)) {
            return null;
        }

        Slog.i(TAG, "On volume remove " + vol);
        String sessionId = vol.getId();
        int userId = vol.getMountUserId();

        synchronized (mLock) {
            StorageUserConnection connection = mConnections.get(userId);
            if (connection != null) {
                Slog.i(TAG, "Removed session for vol with id: " + sessionId);
                connection.removeSession(sessionId);
                return connection;
            } else {
                Slog.w(TAG, "Session already removed for vol with id: " + sessionId);
                return null;
            }
        }
    }


    /**
     * Removes a storage session for {@code vol} and waits for exit.
     *
     * Does nothing if {@link #shouldHandle} is {@code false}
     *
     * Any errors are ignored
     *
     * Call {@link #onVolumeRemove} to remove the connection without waiting for exit
     */
    public void onVolumeUnmount(VolumeInfo vol) {
        StorageUserConnection connection = onVolumeRemove(vol);

        Slog.i(TAG, "On volume unmount " + vol);
        if (connection != null) {
            String sessionId = vol.getId();

            try {
                connection.removeSessionAndWait(sessionId);
            } catch (ExternalStorageServiceException e) {
                Slog.e(TAG, "Failed to end session for vol with id: " + sessionId, e);
            }
        }
    }

    /**
     * Restarts all sessions for {@code userId}.
     *
     * Does nothing if {@link #shouldHandle} is {@code false}
     *
     * This call blocks and waits for all sessions to be started, however any failures when starting
     * a session will be ignored.
     */
    public void onUnlockUser(int userId) throws ExternalStorageServiceException {
        Slog.i(TAG, "On user unlock " + userId);
        if (shouldHandle(null) && userId == 0) {
            initExternalStorageServiceComponent();
        }
    }

    /**
     * Called when a user is in the process is being stopped.
     *
     * Does nothing if {@link #shouldHandle} is {@code false}
     *
     * This call removes all sessions for the user that is being stopped;
     * this will make sure that we don't rebind to the service needlessly.
     */
    public void onUserStopping(int userId) throws ExternalStorageServiceException {
        if (!shouldHandle(null)) {
            return;
        }
        StorageUserConnection connection = null;
        synchronized (mLock) {
            connection = mConnections.get(userId);
        }

        if (connection != null) {
            Slog.i(TAG, "Removing all sessions for user: " + userId);
            connection.removeAllSessions();
        } else {
            Slog.w(TAG, "No connection found for user: " + userId);
        }
    }

    /**
     * Resets all sessions for all users and waits for exit. This may kill the
     * {@link ExternalStorageservice} for a user if necessary to ensure all state has been reset.
     *
     * Does nothing if {@link #shouldHandle} is {@code false}
     **/
    public void onReset(IVold vold, Handler handler) {
        if (!shouldHandle(null)) {
            return;
        }

        SparseArray<StorageUserConnection> connections = new SparseArray();
        synchronized (mLock) {
            mIsResetting = true;
            Slog.i(TAG, "Started resetting external storage service...");
            for (int i = 0; i < mConnections.size(); i++) {
                connections.put(mConnections.keyAt(i), mConnections.valueAt(i));
            }
        }

        for (int i = 0; i < connections.size(); i++) {
            StorageUserConnection connection = connections.valueAt(i);
            for (String sessionId : connection.getAllSessionIds()) {
                try {
                    Slog.i(TAG, "Unmounting " + sessionId);
                    vold.unmount(sessionId);
                    Slog.i(TAG, "Unmounted " + sessionId);
                } catch (ServiceSpecificException | RemoteException e) {
                    // TODO(b/140025078): Hard reset vold?
                    Slog.e(TAG, "Failed to unmount volume: " + sessionId, e);
                }

                try {
                    Slog.i(TAG, "Exiting " + sessionId);
                    connection.removeSessionAndWait(sessionId);
                    Slog.i(TAG, "Exited " + sessionId);
                } catch (IllegalStateException | ExternalStorageServiceException e) {
                    Slog.e(TAG, "Failed to exit session: " + sessionId
                            + ". Killing MediaProvider...", e);
                    // If we failed to confirm the session exited, it is risky to proceed
                    // We kill the ExternalStorageService as a last resort
                    killExternalStorageService(connections.keyAt(i));
                    break;
                }
            }
            connection.close();
        }

        handler.removeCallbacksAndMessages(null);
        synchronized (mLock) {
            mConnections.clear();
            mIsResetting = false;
            Slog.i(TAG, "Finished resetting external storage service");
        }
    }

    private void initExternalStorageServiceComponent() throws ExternalStorageServiceException {
        Slog.i(TAG, "Initialialising...");
        ProviderInfo provider = mContext.getPackageManager().resolveContentProvider(
                MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                | PackageManager.MATCH_SYSTEM_ONLY);
        if (provider == null) {
            throw new ExternalStorageServiceException("No valid MediaStore provider found");
        }

        mExternalStorageServicePackageName = provider.applicationInfo.packageName;
        mExternalStorageServiceAppId = UserHandle.getAppId(provider.applicationInfo.uid);

        Intent intent = new Intent(ExternalStorageService.SERVICE_INTERFACE);
        intent.setPackage(mExternalStorageServicePackageName);
        ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
            throw new ExternalStorageServiceException(
                    "No valid ExternalStorageService component found");
        }

        ServiceInfo serviceInfo = resolveInfo.serviceInfo;
        ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
        if (!Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE
                .equals(serviceInfo.permission)) {
            throw new ExternalStorageServiceException(name.flattenToShortString()
                    + " does not require permission "
                    + Manifest.permission.BIND_EXTERNAL_STORAGE_SERVICE);
        }

        mExternalStorageServiceComponent = name;
    }

    /** Returns the {@link ExternalStorageService} component name. */
    @Nullable
    public ComponentName getExternalStorageServiceComponentName() {
        return mExternalStorageServiceComponent;
    }

    private void killExternalStorageService(int userId) {
        IActivityManager am = ActivityManager.getService();
        try {
            am.killApplication(mExternalStorageServicePackageName, mExternalStorageServiceAppId,
                    userId, "storage_session_controller reset");
        } catch (RemoteException e) {
            Slog.i(TAG, "Failed to kill the ExtenalStorageService for user " + userId);
        }
    }

    /**
     * Throws an {@link IllegalStateException} if {@code path} is not ready to be accessed by
     * {@code userId}.
     */
    // TODO(b/144332951): This is not used because it is racy. Right after checking a path
    // we can call into vold with that path and the FUSE daemon can go down. Improve or remove
    public void checkPathReadyForUser(int userId, String path) {
        if (!mIsFuseEnabled) {
            return;
        }

        if (mIsResetting) {
            throw new IllegalStateException("Connection resetting for user " + userId
                    + " with path " + path);
        }

        StorageUserConnection connection = null;
        synchronized (mLock) {
            connection = mConnections.get(userId);
        }

        if (connection == null) {
            throw new IllegalStateException("Connection not ready for user " + userId
                    + " with path " + path);
        }
        connection.checkPathReady(path);
    }

    /**
     * Returns {@code true} if {@code vol} is an emulated or public volume,
     * {@code false} otherwise
     **/
    public static boolean isEmulatedOrPublic(VolumeInfo vol) {
        return vol.type == VolumeInfo.TYPE_EMULATED || vol.type == VolumeInfo.TYPE_PUBLIC;
    }

    /** Exception thrown when communication with the {@link ExternalStorageService} fails. */
    public static class ExternalStorageServiceException extends Exception {
        public ExternalStorageServiceException(Throwable cause) {
            super(cause);
        }

        public ExternalStorageServiceException(String message) {
            super(message);
        }

        public ExternalStorageServiceException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    private boolean shouldHandle(@Nullable VolumeInfo vol) {
        return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol));
    }
}
