/*
 * Copyright (C) 2012 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;

import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.res.Resources;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;

/**
 * Find the best Service, and bind to it.
 * Handles run-time package changes.
 */
public class ServiceWatcher implements ServiceConnection {
    private static final boolean D = false;
    public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
    public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";

    private final String mTag;
    private final Context mContext;
    private final PackageManager mPm;
    private final List<HashSet<Signature>> mSignatureSets;
    private final String mAction;

    /**
     * If mServicePackageName is not null, only this package will be searched for the service that
     * implements mAction. When null, all packages in the system that matches one of the signature
     * in mSignatureSets are searched.
     */
    private final String mServicePackageName;
    private final Runnable mNewServiceWork;
    private final Handler mHandler;

    private final Object mLock = new Object();

    @GuardedBy("mLock")
    private int mCurrentUserId = UserHandle.USER_SYSTEM;

    @GuardedBy("mLock")
    private IBinder mBoundService;
    @GuardedBy("mLock")
    private ComponentName mBoundComponent;
    @GuardedBy("mLock")
    private String mBoundPackageName;
    @GuardedBy("mLock")
    private int mBoundVersion = Integer.MIN_VALUE;
    @GuardedBy("mLock")
    private int mBoundUserId = UserHandle.USER_NULL;

    public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
            List<String> initialPackageNames) {
        PackageManager pm = context.getPackageManager();
        ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
        for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
            String pkg = initialPackageNames.get(i);
            try {
                HashSet<Signature> set = new HashSet<Signature>();
                Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.MATCH_SYSTEM_ONLY
                        | PackageManager.GET_SIGNATURES).signatures;
                set.addAll(Arrays.asList(sigs));
                sigSets.add(set);
            } catch (NameNotFoundException e) {
                Log.w("ServiceWatcher", pkg + " not found");
            }
        }
        return sigSets;
    }

    public ServiceWatcher(Context context, String logTag, String action,
            int overlaySwitchResId, int defaultServicePackageNameResId,
            int initialPackageNamesResId, Runnable newServiceWork,
            Handler handler) {
        mContext = context;
        mTag = logTag;
        mAction = action;
        mPm = mContext.getPackageManager();
        mNewServiceWork = newServiceWork;
        mHandler = handler;
        Resources resources = context.getResources();

        // Whether to enable service overlay.
        boolean enableOverlay = resources.getBoolean(overlaySwitchResId);
        ArrayList<String> initialPackageNames = new ArrayList<String>();
        if (enableOverlay) {
            // A list of package names used to create the signatures.
            String[] pkgs = resources.getStringArray(initialPackageNamesResId);
            if (pkgs != null) initialPackageNames.addAll(Arrays.asList(pkgs));
            mServicePackageName = null;
            if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs));
        } else {
            // The default package name that is searched for service implementation when overlay is
            // disabled.
            String servicePackageName = resources.getString(defaultServicePackageNameResId);
            if (servicePackageName != null) initialPackageNames.add(servicePackageName);
            mServicePackageName = servicePackageName;
            if (D) Log.d(mTag, "Overlay disabled, default package=" + servicePackageName);
        }
        mSignatureSets = getSignatureSets(context, initialPackageNames);
    }

    /**
     * Start this watcher, including binding to the current best match and
     * re-binding to any better matches down the road.
     * <p>
     * Note that if there are no matching encryption-aware services, we may not
     * bind to a real service until after the current user is unlocked.
     */
    public boolean start() {
        synchronized (mLock) {
            bindBestPackageLocked(mServicePackageName, false);
        }

        // listen for user change
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
        mContext.registerReceiverAsUser(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                final String action = intent.getAction();
                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                        UserHandle.USER_NULL);
                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                    switchUser(userId);
                } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
                    unlockUser(userId);
                }
            }
        }, UserHandle.ALL, intentFilter, null, mHandler);

        // listen for relevant package changes if service overlay is enabled.
        if (mServicePackageName == null) {
            mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
        }

        return true;
    }

    /**
     * Searches and binds to the best package, or do nothing if the best package
     * is already bound, unless force rebinding is requested.
     *
     * @param justCheckThisPackage Only consider this package, or consider all
     *            packages if it is {@code null}.
     * @param forceRebind Force a rebinding to the best package if it's already
     *            bound.
     * @return {@code true} if a valid package was found to bind to.
     */
    private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
        Intent intent = new Intent(mAction);
        if (justCheckThisPackage != null) {
            intent.setPackage(justCheckThisPackage);
        }
        final List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent,
                PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                mCurrentUserId);
        int bestVersion = Integer.MIN_VALUE;
        ComponentName bestComponent = null;
        boolean bestIsMultiuser = false;
        if (rInfos != null) {
            for (ResolveInfo rInfo : rInfos) {
                final ComponentName component = rInfo.serviceInfo.getComponentName();
                final String packageName = component.getPackageName();

                // check signature
                try {
                    PackageInfo pInfo;
                    pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES
                            | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
                    if (!isSignatureMatch(pInfo.signatures)) {
                        Log.w(mTag, packageName + " resolves service " + mAction
                                + ", but has wrong signature, ignoring");
                        continue;
                    }
                } catch (NameNotFoundException e) {
                    Log.wtf(mTag, e);
                    continue;
                }

                // check metadata
                int version = Integer.MIN_VALUE;
                boolean isMultiuser = false;
                if (rInfo.serviceInfo.metaData != null) {
                    version = rInfo.serviceInfo.metaData.getInt(
                            EXTRA_SERVICE_VERSION, Integer.MIN_VALUE);
                    isMultiuser = rInfo.serviceInfo.metaData.getBoolean(EXTRA_SERVICE_IS_MULTIUSER);
                }

                if (version > bestVersion) {
                    bestVersion = version;
                    bestComponent = component;
                    bestIsMultiuser = isMultiuser;
                }
            }

            if (D) {
                Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
                        (justCheckThisPackage == null ? ""
                                : "(" + justCheckThisPackage + ") "), rInfos.size(),
                        (bestComponent == null ? "no new best component"
                                : "new best component: " + bestComponent)));
            }
        } else {
            if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction);
        }

        if (bestComponent == null) {
            Slog.w(mTag, "Odd, no component found for service " + mAction);
            unbindLocked();
            return false;
        }

        final int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId;
        final boolean alreadyBound = Objects.equals(bestComponent, mBoundComponent)
                && bestVersion == mBoundVersion && userId == mBoundUserId;
        if (forceRebind || !alreadyBound) {
            unbindLocked();
            bindToPackageLocked(bestComponent, bestVersion, userId);
        }
        return true;
    }

    private void unbindLocked() {
        ComponentName component;
        component = mBoundComponent;
        mBoundComponent = null;
        mBoundPackageName = null;
        mBoundVersion = Integer.MIN_VALUE;
        mBoundUserId = UserHandle.USER_NULL;
        if (component != null) {
            if (D) Log.d(mTag, "unbinding " + component);
            mContext.unbindService(this);
        }
    }

    private void bindToPackageLocked(ComponentName component, int version, int userId) {
        Intent intent = new Intent(mAction);
        intent.setComponent(component);
        mBoundComponent = component;
        mBoundPackageName = component.getPackageName();
        mBoundVersion = version;
        mBoundUserId = userId;
        if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")");
        mContext.bindServiceAsUser(intent, this,
                Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE,
                new UserHandle(userId));
    }

    public static boolean isSignatureMatch(Signature[] signatures,
            List<HashSet<Signature>> sigSets) {
        if (signatures == null) return false;

        // build hashset of input to test against
        HashSet<Signature> inputSet = new HashSet<Signature>();
        for (Signature s : signatures) {
            inputSet.add(s);
        }

        // test input against each of the signature sets
        for (HashSet<Signature> referenceSet : sigSets) {
            if (referenceSet.equals(inputSet)) {
                return true;
            }
        }
        return false;
    }

    private boolean isSignatureMatch(Signature[] signatures) {
        return isSignatureMatch(signatures, mSignatureSets);
    }

    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
        /**
         * Called when package has been reinstalled
         */
        @Override
        public void onPackageUpdateFinished(String packageName, int uid) {
            synchronized (mLock) {
                final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
                bindBestPackageLocked(null, forceRebind);
            }
        }

        @Override
        public void onPackageAdded(String packageName, int uid) {
            synchronized (mLock) {
                final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
                bindBestPackageLocked(null, forceRebind);
            }
        }

        @Override
        public void onPackageRemoved(String packageName, int uid) {
            synchronized (mLock) {
                final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
                bindBestPackageLocked(null, forceRebind);
            }
        }

        @Override
        public boolean onPackageChanged(String packageName, int uid, String[] components) {
            synchronized (mLock) {
                final boolean forceRebind = Objects.equals(packageName, mBoundPackageName);
                bindBestPackageLocked(null, forceRebind);
            }
            return super.onPackageChanged(packageName, uid, components);
        }
    };

    @Override
    public void onServiceConnected(ComponentName component, IBinder binder) {
        synchronized (mLock) {
            if (component.equals(mBoundComponent)) {
                if (D) Log.d(mTag, component + " connected");
                mBoundService = binder;
                if (mHandler !=null && mNewServiceWork != null) {
                    mHandler.post(mNewServiceWork);
                }
            } else {
                Log.w(mTag, "unexpected onServiceConnected: " + component);
            }
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName component) {
        synchronized (mLock) {
            if (D) Log.d(mTag, component + " disconnected");

            if (component.equals(mBoundComponent)) {
                mBoundService = null;
            }
        }
    }

    public @Nullable String getBestPackageName() {
        synchronized (mLock) {
            return mBoundPackageName;
        }
    }

    public int getBestVersion() {
        synchronized (mLock) {
            return mBoundVersion;
        }
    }

    public @Nullable IBinder getBinder() {
        synchronized (mLock) {
            return mBoundService;
        }
    }

    public void switchUser(int userId) {
        synchronized (mLock) {
            mCurrentUserId = userId;
            bindBestPackageLocked(mServicePackageName, false);
        }
    }

    public void unlockUser(int userId) {
        synchronized (mLock) {
            if (userId == mCurrentUserId) {
                bindBestPackageLocked(mServicePackageName, false);
            }
        }
    }
}
