/*
 * Copyright (C) 2014 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.telecom;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.telecom.Log;
import android.text.TextUtils;
import android.util.ArraySet;

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

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Abstract class to perform the work of binding and unbinding to the specified service interface.
 * Subclasses supply the service intent and component name and this class will invoke protected
 * methods when the class is bound, unbound, or upon failure.
 */
public abstract class ServiceBinder {

    /**
     * Callback to notify after a binding succeeds or fails.
     */
    interface BindCallback {
        void onSuccess();
        void onFailure();
    }

    /**
     * Listener for bind events on ServiceBinder.
     */
    interface Listener<ServiceBinderClass extends ServiceBinder> {
        void onUnbind(ServiceBinderClass serviceBinder);
    }

    /**
     * Helper class to perform on-demand binding.
     */
    final class Binder2 {
        /**
         * Performs an asynchronous bind to the service (only if not already bound) and executes the
         * specified callback.
         *
         * @param callback The callback to notify of the binding's success or failure.
         * @param call The call for which we are being bound.
         */
        void bind(BindCallback callback, Call call) {
            Log.d(ServiceBinder.this, "bind()");

            // Reset any abort request if we're asked to bind again.
            clearAbort();

            synchronized (mCallbacks) {
                if (!mCallbacks.isEmpty()) {
                    // Binding already in progress, append to the list of callbacks and bail out.
                    mCallbacks.add(callback);
                    return;
                }
                mCallbacks.add(callback);
            }

            if (mServiceConnection == null) {
                Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
                ServiceConnection connection = new ServiceBinderConnection(call);

                Log.addEvent(call, LogUtils.Events.BIND_CS, mComponentName);
                final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
                final boolean isBound;
                if (mUserHandle != null) {
                    isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
                            mUserHandle);
                } else {
                    isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
                }
                if (!isBound) {
                    handleFailedConnection();
                    return;
                }
            } else {
                Log.d(ServiceBinder.this, "Service is already bound.");
                Preconditions.checkNotNull(mBinder);
                handleSuccessfulConnection();
            }
        }
    }

    private class ServiceDeathRecipient implements IBinder.DeathRecipient {

        private ComponentName mComponentName;

        ServiceDeathRecipient(ComponentName name) {
            mComponentName = name;
        }

        @Override
        public void binderDied() {
            try {
                synchronized (mLock) {
                    Log.startSession("SDR.bD",
                            Log.getPackageAbbreviation(mComponentName));
                    Log.i(this, "binderDied: ConnectionService %s died.", mComponentName);
                    logServiceDisconnected("binderDied");
                    handleDisconnect();
                }
            } finally {
                Log.endSession();
            }
        }
    }

    private final class ServiceBinderConnection implements ServiceConnection {
        /**
         * The initial call for which the service was bound.
         */
        private Call mCall;

        ServiceBinderConnection(Call call) {
            mCall = call;
        }

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder binder) {
            try {
                Log.startSession("SBC.oSC", Log.getPackageAbbreviation(componentName));
                synchronized (mLock) {
                    Log.i(this, "Service bound %s", componentName);

                    Log.addEvent(mCall, LogUtils.Events.CS_BOUND, componentName);
                    mCall = null;

                    // Unbind request was queued so unbind immediately.
                    if (mIsBindingAborted) {
                        clearAbort();
                        logServiceDisconnected("onServiceConnected");
                        mContext.unbindService(this);
                        handleFailedConnection();
                        return;
                    }
                    if (binder != null) {
                        mServiceDeathRecipient = new ServiceDeathRecipient(componentName);
                        try {
                            binder.linkToDeath(mServiceDeathRecipient, 0);
                            mServiceConnection = this;
                            setBinder(binder);
                            handleSuccessfulConnection();
                        } catch (RemoteException e) {
                            Log.w(this, "onServiceConnected: %s died.");
                            if (mServiceDeathRecipient != null) {
                                mServiceDeathRecipient.binderDied();
                            }
                        }
                    }
                }
            } finally {
                Log.endSession();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            try {
                Log.startSession("SBC.oSD", Log.getPackageAbbreviation(componentName));
                synchronized (mLock) {
                    logServiceDisconnected("onServiceDisconnected");
                    handleDisconnect();
                }
            } finally {
                Log.endSession();
            }
        }
    }

    private void handleDisconnect() {
        mServiceConnection = null;
        clearAbort();

        handleServiceDisconnected();
    }

    /** The application context. */
    private final Context mContext;

    /** The Telecom lock object. */
    protected final TelecomSystem.SyncRoot mLock;

    /** The intent action to use when binding through {@link Context#bindService}. */
    private final String mServiceAction;

    /** The component name of the service to bind to. */
    protected final ComponentName mComponentName;

    /**
     * Abbreviated form of the package name from {@link #mComponentName}; used for session logging.
     */
    protected final String mPackageAbbreviation;

    /** The set of callbacks waiting for notification of the binding's success or failure. */
    private final Set<BindCallback> mCallbacks = new ArraySet<>();

    /** Used to bind and unbind from the service. */
    private ServiceConnection mServiceConnection;

    /** Used to handle death of the service. */
    private ServiceDeathRecipient mServiceDeathRecipient;

    /** {@link UserHandle} to use for binding, to support work profiles and multi-user. */
    private UserHandle mUserHandle;

    /** The binder provided by {@link ServiceConnection#onServiceConnected} */
    private IBinder mBinder;

    private int mAssociatedCallCount = 0;

    /**
     * Indicates that an unbind request was made when the service was not yet bound. If the service
     * successfully connects when this is true, it should be unbound immediately.
     */
    private boolean mIsBindingAborted;

    /**
     * Set of currently registered listeners.
     * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
     * load factor before resizing, 1 means we only expect a single thread to
     * access the map so make only a single shard
     */
    private final Set<Listener> mListeners = Collections.newSetFromMap(
            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));

    /**
     * Persists the specified parameters and initializes the new instance.
     *
     * @param serviceAction The intent-action used with {@link Context#bindService}.
     * @param componentName The component name of the service with which to bind.
     * @param context The context.
     * @param userHandle The {@link UserHandle} to use for binding.
     */
    protected ServiceBinder(String serviceAction, ComponentName componentName, Context context,
            TelecomSystem.SyncRoot lock, UserHandle userHandle) {
        Preconditions.checkState(!TextUtils.isEmpty(serviceAction));
        Preconditions.checkNotNull(componentName);

        mContext = context;
        mLock = lock;
        mServiceAction = serviceAction;
        mComponentName = componentName;
        mPackageAbbreviation = Log.getPackageAbbreviation(componentName);
        mUserHandle = userHandle;
    }

    final UserHandle getUserHandle() {
        return mUserHandle;
    }

    final void incrementAssociatedCallCount() {
        mAssociatedCallCount++;
        Log.v(this, "Call count increment %d, %s", mAssociatedCallCount,
                mComponentName.flattenToShortString());
    }

    final void decrementAssociatedCallCount() {
        decrementAssociatedCallCount(false /*isSuppressingUnbind*/);
    }

    final void decrementAssociatedCallCount(boolean isSuppressingUnbind) {
        if (mAssociatedCallCount > 0) {
            mAssociatedCallCount--;
            Log.v(this, "Call count decrement %d, %s", mAssociatedCallCount,
                    mComponentName.flattenToShortString());

            if (!isSuppressingUnbind && mAssociatedCallCount == 0) {
                unbind();
            }
        } else {
            Log.wtf(this, "%s: ignoring a request to decrement mAssociatedCallCount below zero",
                    mComponentName.getClassName());
        }
    }

    final int getAssociatedCallCount() {
        return mAssociatedCallCount;
    }

    /**
     * Unbinds from the service if already bound, no-op otherwise.
     */
    final void unbind() {
        if (mServiceConnection == null) {
            // We're not yet bound, so queue up an abort request.
            mIsBindingAborted = true;
        } else {
            logServiceDisconnected("unbind");
            unlinkDeathRecipient();
            mContext.unbindService(mServiceConnection);
            mServiceConnection = null;
            setBinder(null);
        }
    }

    public final ComponentName getComponentName() {
        return mComponentName;
    }

    @VisibleForTesting
    public boolean isServiceValid(String actionName) {
        if (mBinder == null) {
            Log.w(this, "%s invoked while service is unbound", actionName);
            return false;
        }

        return true;
    }

    final void addListener(Listener listener) {
        mListeners.add(listener);
    }

    final void removeListener(Listener listener) {
        if (listener != null) {
            mListeners.remove(listener);
        }
    }

    /**
     * Logs a standard message upon service disconnection. This method exists because there is no
     * single method called whenever the service unbinds and we want to log the same string in all
     * instances where that occurs.  (Context.unbindService() does not cause onServiceDisconnected
     * to execute).
     *
     * @param sourceTag Tag to disambiguate
     */
    private void logServiceDisconnected(String sourceTag) {
        Log.i(this, "Service unbound %s, from %s.", mComponentName, sourceTag);
    }

    /**
     * Notifies all the outstanding callbacks that the service is successfully bound. The list of
     * outstanding callbacks is cleared afterwards.
     */
    private void handleSuccessfulConnection() {
        // Make a copy so that we don't have a deadlock inside one of the callbacks.
        Set<BindCallback> callbacksCopy = new ArraySet<>();
        synchronized (mCallbacks) {
            callbacksCopy.addAll(mCallbacks);
            mCallbacks.clear();
        }

        for (BindCallback callback : callbacksCopy) {
            callback.onSuccess();
        }
    }

    /**
     * Notifies all the outstanding callbacks that the service failed to bind. The list of
     * outstanding callbacks is cleared afterwards.
     */
    private void handleFailedConnection() {
        // Make a copy so that we don't have a deadlock inside one of the callbacks.
        Set<BindCallback> callbacksCopy = new ArraySet<>();
        synchronized (mCallbacks) {
            callbacksCopy.addAll(mCallbacks);
            mCallbacks.clear();
        }

        for (BindCallback callback : callbacksCopy) {
            callback.onFailure();
        }
    }

    /**
     * Handles a service disconnection.
     */
    private void handleServiceDisconnected() {
        unlinkDeathRecipient();
        setBinder(null);
    }

    /**
     * Handles un-linking the death recipient from the service's binder.
     */
    private void unlinkDeathRecipient() {
        if (mServiceDeathRecipient != null && mBinder != null) {
            boolean unlinked = mBinder.unlinkToDeath(mServiceDeathRecipient, 0);
            if (!unlinked) {
                Log.i(this, "unlinkDeathRecipient: failed to unlink %s", mComponentName);
            }
            mServiceDeathRecipient = null;
        } else {
            Log.w(this, "unlinkDeathRecipient: death recipient is null.");
        }
    }

    private void clearAbort() {
        mIsBindingAborted = false;
    }

    /**
     * Sets the (private) binder and updates the child class.
     *
     * @param binder The new binder value.
     */
    private void setBinder(IBinder binder) {
        if (mBinder != binder) {
            if (binder == null) {
                removeServiceInterface();
                mBinder = null;
                for (Listener l : mListeners) {
                    l.onUnbind(this);
                }
            } else {
                mBinder = binder;
                setServiceInterface(binder);
            }
        }
    }

    /**
     * Sets the service interface after the service is bound.
     *
     * @param binder The new binder interface that is being set.
     */
    protected abstract void setServiceInterface(IBinder binder);

    /**
     * Removes the service interface before the service is unbound.
     */
    protected abstract void removeServiceInterface();
}
