package com.lody.virtual.server.pm;

import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.os.Build;
import android.os.Parcel;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.util.LogPrinter;

import com.lody.virtual.client.core.VirtualCore;
import com.lody.virtual.client.env.Constants;
import com.lody.virtual.client.fixer.ComponentFixer;
import com.lody.virtual.helper.compat.ObjectsCompat;
import com.lody.virtual.helper.compat.PackageParserCompat;
import com.lody.virtual.helper.proto.AppSetting;
import com.lody.virtual.helper.proto.ReceiverInfo;
import com.lody.virtual.helper.proto.VParceledListSlice;
import com.lody.virtual.helper.utils.ComponentUtils;
import com.lody.virtual.os.VUserHandle;
import com.lody.virtual.server.IPackageManager;

import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author Lody
 *
 */
public class VPackageManagerService extends IPackageManager.Stub {

	static final String TAG = "PackageManager";

	private static final boolean DEBUG_SHOW_INFO = false;
	private static final AtomicReference<VPackageManagerService> gService = new AtomicReference<>();
	static final Comparator<ResolveInfo> mResolvePrioritySorter = new Comparator<ResolveInfo>() {
		public int compare(ResolveInfo r1, ResolveInfo r2) {
			int v1 = r1.priority;
			int v2 = r2.priority;
			if (v1 != v2) {
				return (v1 > v2) ? -1 : 1;
			}
			v1 = r1.preferredOrder;
			v2 = r2.preferredOrder;
			if (v1 != v2) {
				return (v1 > v2) ? -1 : 1;
			}
			if (r1.isDefault != r2.isDefault) {
				return r1.isDefault ? -1 : 1;
			}
			v1 = r1.match;
			v2 = r2.match;
			if (v1 != v2) {
				return (v1 > v2) ? -1 : 1;
			}
			return 0;
		}
	};
	private static final Comparator<ProviderInfo> mProviderInitOrderSorter = new Comparator<ProviderInfo>() {
		public int compare(ProviderInfo p1, ProviderInfo p2) {
			final int v1 = p1.initOrder;
			final int v2 = p2.initOrder;
			return (v1 > v2) ? -1 : ((v1 < v2) ? 1 : 0);
		}
	};

	final ActivityIntentResolver mActivities = new ActivityIntentResolver();
	final ServiceIntentResolver mServices = new ServiceIntentResolver();
	final ActivityIntentResolver mReceivers = new ActivityIntentResolver();
	final ProviderIntentResolver mProviders = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ?  new ProviderIntentResolver() : null;

	final HashMap<ComponentName, PackageParser.Provider> mProvidersByComponent = new HashMap<>();

	final HashMap<String, PackageParser.Permission> mPermissions = new HashMap<>();
	final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups = new HashMap<>();
	final HashMap<String, PackageParser.Provider> mProvidersByAuthority = new HashMap<>();

	private final Map<String, PackageParser.Package> mPackages = PackageCache.sPackageCaches;



	public static void systemReady() {
		VPackageManagerService instance = new VPackageManagerService();
		new VUserManagerService(VirtualCore.get().getContext(), instance, new char[0], instance.mPackages);
		gService.set(instance);
	}

	public static VPackageManagerService get() {
		return gService.get();
	}

	private static boolean isSystemApp(ApplicationInfo info) {
		return info != null && (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
	}

	public void analyzePackageLocked(PackageParser.Package pkg) {
		int N = pkg.activities.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Activity a = pkg.activities.get(i);
			if (a.info.processName == null) {
				a.info.processName = a.info.packageName;
			}
			mActivities.addActivity(a, "activity");
		}
		N = pkg.services.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Service a = pkg.services.get(i);
			if (a.info.processName == null) {
				a.info.processName = a.info.packageName;
			}
			mServices.addService(a);
		}
		N = pkg.receivers.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Activity a = pkg.receivers.get(i);
			if (a.info.processName == null) {
				a.info.processName = a.info.packageName;
			}
			mReceivers.addActivity(a, "receiver");
		}

		N = pkg.providers.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Provider p = pkg.providers.get(i);
			if (p.info.processName == null) {
				p.info.processName = p.info.packageName;
			}
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
				mProviders.addProvider(p);
			}
			String names[] = p.info.authority.split(";");
			for (String name : names) {
				if (!mProvidersByAuthority.containsKey(name)) {
					mProvidersByAuthority.put(name, p);
				}
			}
			mProvidersByComponent.put(p.getComponentName(), p);
		}

		N = pkg.permissions.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Permission permission = pkg.permissions.get(i);
			mPermissions.put(permission.className, permission);
		}
		N = pkg.permissionGroups.size();
		for (int i = 0; i < N; i++) {
			PackageParser.PermissionGroup group = pkg.permissionGroups.get(i);
			mPermissionGroups.put(group.className, group);
		}
	}

	public void deletePackageLocked(String packageName) {
		PackageParser.Package pkg = mPackages.get(packageName);
		if (pkg == null) {
			return;
		}
		int N = pkg.activities.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Activity a = pkg.activities.get(i);
			mActivities.removeActivity(a, "activity");
		}
		N = pkg.services.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Service a = pkg.services.get(i);
			mServices.removeService(a);
		}
		N = pkg.receivers.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Activity a = pkg.receivers.get(i);
			mReceivers.removeActivity(a, "receiver");
		}

		N = pkg.providers.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Provider p = pkg.providers.get(i);
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
				mProviders.removeProvider(p);
			}
			String names[] = p.info.authority.split(";");
			for (String name : names) {
				mProvidersByAuthority.remove(name);
			}
			mProvidersByComponent.remove(p.getComponentName());
		}

		N = pkg.permissions.size();
		for (int i = 0; i < N; i++) {
			PackageParser.Permission permission = pkg.permissions.get(i);
			mPermissions.remove(permission.className);
		}
		N = pkg.permissionGroups.size();
		for (int i = 0; i < N; i++) {
			PackageParser.PermissionGroup group = pkg.permissionGroups.get(i);
			mPermissionGroups.remove(group.className);
		}
	}

	@Override
	public List<String> getSharedLibraries(String pkgName) {
		synchronized (mPackages) {
			PackageParser.Package p = mPackages.get(pkgName);
			if (p != null) {
				return p.usesLibraries;
			}
			return null;
		}
	}

	@Override
	public int checkPermission(String permName, String pkgName, int userId) {
		if ("android.permission.INTERACT_ACROSS_USERS".equals(permName)
				|| "android.permission.INTERACT_ACROSS_USERS_FULL".equals(permName)) {
			return PackageManager.PERMISSION_DENIED;
		}
		return VirtualCore.get().getPackageManager().checkPermission(permName, VirtualCore.get().getHostPkg());
	}

	@Override
	public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
		synchronized (mPackages) {
			PackageParser.Package pkg = mPackages.get(packageName);
			if (pkg != null) {
				AppSetting setting = (AppSetting) pkg.mExtras;
				if ((flags & PackageManager.GET_SIGNATURES) != 0 && pkg.mSignatures == null) {
					if (pkg.mAppMetaData != null && pkg.mAppMetaData.containsKey(Constants.FEATURE_FAKE_SIGNATURE)) {
						String sig = pkg.mAppMetaData.getString("fake-signature");
						if (sig != null) {
							pkg.mSignatures = new Signature[] {new Signature(sig)};
						}
					} else {
						PackageParserCompat.collectCertificates(setting.parser, pkg, PackageParser.PARSE_IS_SYSTEM);
					}
				}
				PackageInfo packageInfo = PackageParserCompat.generatePackageInfo(pkg, flags,
						getFirstInstallTime(pkg), getLastInstallTime(pkg));
				if (packageInfo != null) {
					ComponentFixer.fixApplicationInfo(setting, packageInfo.applicationInfo, userId);
					return packageInfo;
				}
			}
		}
		return null;
	}

	private long getLastInstallTime(PackageParser.Package p) {
		AppSetting setting = (AppSetting) p.mExtras;
		return new File(setting.apkPath).lastModified();
	}

	private long getFirstInstallTime(PackageParser.Package p) {
		AppSetting setting = (AppSetting) p.mExtras;
		return new File(setting.apkPath).lastModified();
	}

	public void checkUserId(int userId) {
		if (!VUserManagerService.get().exists(userId)) {
			throw new SecurityException("The userId: " + userId + " is not exist.");
		}
	}

	@Override
	public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
		checkUserId(userId);
		synchronized (mPackages) {
			PackageParser.Activity a = mActivities.mActivities.get(component);
			if (a != null) {
				ActivityInfo activityInfo = PackageParserCompat.generateActivityInfo(a, flags);
				PackageParser.Package p = mPackages.get(activityInfo.packageName);
				AppSetting settings = (AppSetting) p.mExtras;
				ComponentFixer.fixComponentInfo(settings, activityInfo, userId);
				return activityInfo;
			}
		}
		return null;
	}

	@Override
	public boolean activitySupportsIntent(ComponentName component, Intent intent, String resolvedType) {
		synchronized (mPackages) {
			PackageParser.Activity a = mActivities.mActivities.get(component);
			if (a == null) {
				return false;
			}
			for (int i = 0; i < a.intents.size(); i++) {
				if (a.intents.get(i).match(intent.getAction(), resolvedType, intent.getScheme(), intent.getData(),
						intent.getCategories(), TAG) >= 0) {
					return true;
				}
			}
			return false;
		}
	}

	@Override
	public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
		checkUserId(userId);
		synchronized (mPackages) {
			PackageParser.Activity a = mReceivers.mActivities.get(component);
			if (a != null) {
				ActivityInfo receiverInfo = PackageParserCompat.generateActivityInfo(a, flags);
				PackageParser.Package p = mPackages.get(receiverInfo.packageName);
				AppSetting settings = (AppSetting) p.mExtras;
				ComponentFixer.fixComponentInfo(settings, receiverInfo, userId);
				return receiverInfo;
			}
		}
		return null;
	}

	@Override
	public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
		checkUserId(userId);
		synchronized (mPackages) {
			PackageParser.Service s = mServices.mServices.get(component);
			if (s != null) {
				ServiceInfo serviceInfo = PackageParserCompat.generateServiceInfo(s, flags);
				PackageParser.Package p = mPackages.get(serviceInfo.packageName);
				AppSetting settings = (AppSetting) p.mExtras;
				ComponentFixer.fixComponentInfo(settings, serviceInfo, userId);
				return serviceInfo;
			}
		}
		return null;
	}

	@Override
	public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
		checkUserId(userId);
		synchronized (mPackages) {
			PackageParser.Provider p = mProvidersByComponent.get(component);
			if (p != null) {
				ProviderInfo providerInfo = PackageParserCompat.generateProviderInfo(p, flags);
				PackageParser.Package pkg = mPackages.get(providerInfo.packageName);
				AppSetting settings = (AppSetting) pkg.mExtras;
				ComponentFixer.fixComponentInfo(settings, providerInfo, userId);
				return providerInfo;
			}
		}
		return null;
	}

	@Override
	public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) {
		checkUserId(userId);
		List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, 0);
		return chooseBestActivity(intent, resolvedType, flags, query);
	}

	private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query) {
		if (query != null) {
			final int N = query.size();
			if (N == 1) {
				return query.get(0);
			} else if (N > 1) {
				// If there is more than one activity with the same priority,
				// then let the user decide between them.
				ResolveInfo r0 = query.get(0);
				ResolveInfo r1 = query.get(1);
				// If the first activity has a higher priority, or a different
				// default, then it is always desireable to pick it.
				if (r0.priority != r1.priority || r0.preferredOrder != r1.preferredOrder
						|| r0.isDefault != r1.isDefault) {
					return query.get(0);
				}
				return query.get(0);
				// If we have saved a preference for a preferred activity for
				// this Intent, use that.

				// TODO
				// ResolveInfo ri = findPreferredActivity(intent, resolvedType,
				// flags, query, r0.priority);
				// if (ri != null) {
				// return ri;
				// }
				// return mResolveInfo;
			}
		}
		return null;
	}

	@Override
	public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) {
		checkUserId(userId);
		ComponentName comp = intent.getComponent();
		if (comp == null) {
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
				if (intent.getSelector() != null) {
					intent = intent.getSelector();
					comp = intent.getComponent();
				}
			}
		}
		if (comp != null) {
			final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
			final ActivityInfo ai = getActivityInfo(comp, flags, userId);
			if (ai != null) {
				final ResolveInfo ri = new ResolveInfo();
				ri.activityInfo = ai;
				list.add(ri);
			}
			return list;
		}

		// reader
		synchronized (mPackages) {
			final String pkgName = intent.getPackage();
			if (pkgName == null) {
				return mActivities.queryIntent(intent, resolvedType, flags);
			}
			final PackageParser.Package pkg = mPackages.get(pkgName);
			if (pkg != null) {
				return mActivities.queryIntentForPackage(intent, resolvedType, flags, pkg.activities);
			}
			return new ArrayList<ResolveInfo>();
		}
	}

	@Override
	public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) {
		ComponentName comp = intent.getComponent();
		if (comp == null) {
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
				if (intent.getSelector() != null) {
					intent = intent.getSelector();
					comp = intent.getComponent();
				}
			}
		}
		if (comp != null) {
			List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
			ActivityInfo ai = getReceiverInfo(comp, flags, userId);
			if (ai != null) {
				ResolveInfo ri = new ResolveInfo();
				ri.activityInfo = ai;
				list.add(ri);
			}
			return list;
		}

		// reader
		synchronized (mPackages) {
			String pkgName = intent.getPackage();
			if (pkgName == null) {
				return mReceivers.queryIntent(intent, resolvedType, flags);
			}
			final PackageParser.Package pkg = mPackages.get(pkgName);
			if (pkg != null) {
				return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers);
			}
			return null;
		}
	}

	@Override
	public List<ReceiverInfo> queryReceivers(String processName, int uid, int flags) {
		int userId = VUserHandle.getUserId(uid);
		checkUserId(userId);
		ArrayList<ReceiverInfo> finalList = new ArrayList<>(3);
		synchronized (mPackages) {
			for (PackageParser.Activity a : mReceivers.mActivities.values()) {
				if (a.info.processName.equals(processName)) {
					ActivityInfo receiverInfo = PackageParserCompat.generateActivityInfo(a, flags);
					if (receiverInfo != null) {
						AppSetting settings = (AppSetting) mPackages.get(receiverInfo.packageName).mExtras;
						ComponentFixer.fixComponentInfo(settings, receiverInfo, userId);
						ComponentName component = ComponentUtils.toComponentName(receiverInfo);
						IntentFilter[] filters = null;
						if (a.intents != null) {
							filters = a.intents.toArray(new IntentFilter[a.intents.size()]);
						}
						finalList.add(new ReceiverInfo(component, filters, receiverInfo.permission));
					}
				}
			}
		}
		return finalList;
	}

	@Override
	public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
		List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
		if (query != null) {
			if (query.size() >= 1) {
				// If there is more than one service with the same priority,
				// just arbitrarily pick the first one.
				return query.get(0);
			}
		}
		return null;
	}

	@Override
	public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags, int userId) {
		checkUserId(userId);
		ComponentName comp = intent.getComponent();
		if (comp == null) {
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
				if (intent.getSelector() != null) {
					intent = intent.getSelector();
					comp = intent.getComponent();
				}
			}
		}
		if (comp != null) {
			final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
			final ServiceInfo si = getServiceInfo(comp, flags, userId);
			if (si != null) {
				final ResolveInfo ri = new ResolveInfo();
				ri.serviceInfo = si;
				list.add(ri);
			}
			return list;
		}

		// reader
		synchronized (mPackages) {
			String pkgName = intent.getPackage();
			if (pkgName == null) {
				return mServices.queryIntent(intent, resolvedType, flags);
			}
			final PackageParser.Package pkg = mPackages.get(pkgName);
			if (pkg != null) {
				return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services);
			}
			return null;
		}
	}

	@TargetApi(Build.VERSION_CODES.KITKAT)
	@Override
	public List<ResolveInfo> queryIntentContentProviders(Intent intent, String resolvedType, int flags, int userId) {
		checkUserId(userId);
		ComponentName comp = intent.getComponent();
		if (comp == null) {
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
				if (intent.getSelector() != null) {
					intent = intent.getSelector();
					comp = intent.getComponent();
				}
			}
		}
		if (comp != null) {
			final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
			final ProviderInfo pi = getProviderInfo(comp, flags, userId);
			if (pi != null) {
				final ResolveInfo ri = new ResolveInfo();
				ri.providerInfo = pi;
				list.add(ri);
			}
			return list;
		}
		// reader
		synchronized (mPackages) {
			String pkgName = intent.getPackage();
			if (pkgName == null) {
				return mProviders.queryIntent(intent, resolvedType, flags);
			}
			final PackageParser.Package pkg = mPackages.get(pkgName);
			if (pkg != null) {
				return mProviders.queryIntentForPackage(intent, resolvedType, flags, pkg.providers);
			}
			return null;
		}
	}

	@Override
	public VParceledListSlice<ProviderInfo> queryContentProviders(String processName, int vuid, int flags) {
		int userId = VUserHandle.getUserId(vuid);
		checkUserId(userId);
		ArrayList<ProviderInfo> finalList = new ArrayList<>(3);
		// reader
		synchronized (mPackages) {
			for (PackageParser.Provider p : mProvidersByComponent.values()) {
				AppSetting setting = (AppSetting) p.owner.mExtras;
				if (processName == null || setting.appId == VUserHandle.getAppId(vuid) && p.info.processName.equals(processName)) {
					ProviderInfo providerInfo = PackageParserCompat.generateProviderInfo(p, flags);
					ComponentFixer.fixApplicationInfo(setting, providerInfo.applicationInfo, userId);
					finalList.add(providerInfo);
				}
			}
		}
		if (!finalList.isEmpty()) {
			Collections.sort(finalList, mProviderInitOrderSorter);
		}
		return new VParceledListSlice<>(finalList);
	}

	@Override
	public VParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
		checkUserId(userId);
		ArrayList<PackageInfo> pkgList = new ArrayList<>(mPackages.size());
		synchronized (mPackages) {
			for (PackageParser.Package pkg : mPackages.values()) {
				String packageName = pkg.packageName;
				pkgList.add(getPackageInfo(packageName, flags, userId));
			}
		}
		return new VParceledListSlice<>(pkgList);
	}

	@Override
	public VParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
		checkUserId(userId);
		ArrayList<ApplicationInfo> list = new ArrayList<>(mPackages.size());
		synchronized (mPackages) {
			for (PackageParser.Package pkg : mPackages.values()) {
				list.add(getApplicationInfo(pkg.packageName, flags, userId));
			}
		}
		return new VParceledListSlice<>(list);
	}

	@Override
	public PermissionInfo getPermissionInfo(String name, int flags) {
		synchronized (mPackages) {
			PackageParser.Permission p = mPermissions.get(name);
			if (p != null) {
				return new PermissionInfo(p.info);
			}
		}
		return null;
	}

	@Override
	public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
		synchronized (mPackages) {
			return null;
		}
	}

	@Override
	public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
		synchronized (mPackages) {
			PackageParser.PermissionGroup p = mPermissionGroups.get(name);
			if (p != null) {
				return new PermissionGroupInfo(p.info);
			}
		}
		return null;
	}

	@Override
	public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
		synchronized (mPackages) {
			final int N = mPermissionGroups.size();
			ArrayList<PermissionGroupInfo> out = new ArrayList<>(N);
			for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) {
				out.add(new PermissionGroupInfo(pg.info));
			}
			return out;
		}
	}

	@Override
	public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
		checkUserId(userId);
		synchronized (mPackages) {
			final PackageParser.Provider provider = mProvidersByAuthority.get(name);
			if (provider != null) {
				ProviderInfo providerInfo = PackageParserCompat.generateProviderInfo(provider, flags);
				PackageParser.Package p = mPackages.get(providerInfo.packageName);
				AppSetting settings = (AppSetting) p.mExtras;
				ComponentFixer.fixComponentInfo(settings, providerInfo, userId);
				return providerInfo;
			}
		}
		return null;
	}

	@Override
	public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
		checkUserId(userId);
		synchronized (mPackages) {
			PackageParser.Package pkg = mPackages.get(packageName);
			if (pkg != null) {
				ApplicationInfo applicationInfo = PackageParserCompat.generateApplicationInfo(pkg, flags);
				AppSetting settings = (AppSetting) pkg.mExtras;
				ComponentFixer.fixApplicationInfo(settings, applicationInfo, userId);
				return applicationInfo;
			}
		}
		return null;
	}

	@Override
	public String[] getPackagesForUid(int uid) {
		int userId = VUserHandle.getUserId(uid);
		checkUserId(userId);
		synchronized (this) {
			List<String> pkgList = new ArrayList<>(2);
			for (PackageParser.Package p : mPackages.values()) {
				AppSetting settings = (AppSetting) p.mExtras;
				if (VUserHandle.getUid(userId, settings.appId) == uid) {
					pkgList.add(p.packageName);
				}
			}
			return pkgList.toArray(new String[pkgList.size()]);
		}
	}

	@Override
	public int getPackageUid(String packageName, int userId) {
		checkUserId(userId);
		synchronized (mPackages) {
			PackageParser.Package p = mPackages.get(packageName);
			if (p != null) {
				AppSetting settings = (AppSetting) p.mExtras;
				return VUserHandle.getUid(userId, settings.appId);
			}
			return -1;
		}
	}


	@Override
	public List<String> querySharedPackages(String packageName) {
		synchronized (mPackages) {
			PackageParser.Package p = mPackages.get(packageName);
			if (p == null || p.mSharedUserId == null) {
				// noinspection unchecked
				return Collections.EMPTY_LIST;
			}
			ArrayList<String> list = new ArrayList<>();
			for (PackageParser.Package one : mPackages.values()) {
				if (TextUtils.equals(one.mSharedUserId, p.mSharedUserId)) {
					list.add(one.packageName);
				}
			}
			return list;
		}
	}
	@Override
	public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
		try {
			return super.onTransact(code, data, reply, flags);
		} catch (Throwable e) {
			e.printStackTrace();
			throw e;
		}
	}

	public void createNewUserLILPw(int userId, File userPath) {

	}

	public void cleanUpUserLILPw(int userHandle) {

	}

	final class ActivityIntentResolver extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
		// Keys are String (activity class name), values are Activity.
		private final HashMap<ComponentName, PackageParser.Activity> mActivities = new HashMap<>();
		private int mFlags;

		public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
			mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
			return super.queryIntent(intent, resolvedType, defaultOnly);
		}

		public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) {
			mFlags = flags;
			return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0);
		}

		public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags,
				ArrayList<PackageParser.Activity> packageActivities) {
			if (packageActivities == null) {
				return null;
			}
			mFlags = flags;
			final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
			final int N = packageActivities.size();
			ArrayList<PackageParser.ActivityIntentInfo[]> listCut = new ArrayList<PackageParser.ActivityIntentInfo[]>(
					N);

			ArrayList<PackageParser.ActivityIntentInfo> intentFilters;
			for (int i = 0; i < N; ++i) {
				intentFilters = packageActivities.get(i).intents;
				if (intentFilters != null && intentFilters.size() > 0) {
					PackageParser.ActivityIntentInfo[] array = new PackageParser.ActivityIntentInfo[intentFilters
							.size()];
					intentFilters.toArray(array);
					listCut.add(array);
				}
			}
			return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
		}

		public final void addActivity(PackageParser.Activity a, String type) {
			final boolean systemApp = isSystemApp(a.info.applicationInfo);
			mActivities.put(a.getComponentName(), a);
			if (DEBUG_SHOW_INFO)
				Log.v(TAG, "  " + type + " "
						+ (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
			if (DEBUG_SHOW_INFO)
				Log.v(TAG, "    Class=" + a.info.name);
			final int NI = a.intents.size();
			for (int j = 0; j < NI; j++) {
				PackageParser.ActivityIntentInfo intent = a.intents.get(j);
				if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
					intent.setPriority(0);
					Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity " + a.className
							+ " with priority > 0, forcing to 0");
				}
				if (DEBUG_SHOW_INFO) {
					Log.v(TAG, "    IntentFilter:");
					intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
				}
				addFilter(intent);
			}
		}

		public final void removeActivity(PackageParser.Activity a, String type) {
			mActivities.remove(a.getComponentName());
			if (DEBUG_SHOW_INFO) {
				Log.v(TAG, "  " + type + " "
						+ (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel : a.info.name) + ":");
				Log.v(TAG, "    Class=" + a.info.name);
			}
			final int NI = a.intents.size();
			for (int j = 0; j < NI; j++) {
				PackageParser.ActivityIntentInfo intent = a.intents.get(j);
				if (DEBUG_SHOW_INFO) {
					Log.v(TAG, "    IntentFilter:");
					intent.dump(new LogPrinter(Log.VERBOSE, TAG), "      ");
				}
				removeFilter(intent);
			}
		}

		@Override
		protected boolean allowFilterResult(PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) {
			ActivityInfo filterAi = filter.activity.info;
			for (int i = dest.size() - 1; i >= 0; i--) {
				ActivityInfo destAi = dest.get(i).activityInfo;
				if (destAi.name == filterAi.name && destAi.packageName == filterAi.packageName) {
					return false;
				}
			}
			return true;
		}

		@Override
		protected PackageParser.ActivityIntentInfo[] newArray(int size) {
			return new PackageParser.ActivityIntentInfo[size];
		}

		@Override
		protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter) {
			return false;
		}

		@Override
		protected boolean isPackageForFilter(String packageName, PackageParser.ActivityIntentInfo info) {
			return packageName.equals(info.activity.owner.packageName);
		}

		@Override
		protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, int match) {
			final PackageParser.Activity activity = info.activity;
			ActivityInfo ai = PackageParserCompat.generateActivityInfo(activity, mFlags);
			if (ai == null) {
				return null;
			}
			final ResolveInfo res = new ResolveInfo();
			res.activityInfo = ai;
			if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
				res.filter = info;
			}
			res.priority = info.getPriority();
			res.preferredOrder = activity.owner.mPreferredOrder;
			// System.out.println("Result: " + res.activityInfo.className +
			// " = " + res.priority);
			res.match = match;
			res.isDefault = info.hasDefault;
			res.labelRes = info.labelRes;
			res.nonLocalizedLabel = info.nonLocalizedLabel;
			res.icon = info.icon;
			return res;
		}

		@Override
		protected void sortResults(List<ResolveInfo> results) {
			Collections.sort(results, mResolvePrioritySorter);
		}

		@Override
		protected void dumpFilter(PrintWriter out, String prefix, PackageParser.ActivityIntentInfo filter) {

		}

		@Override
		protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) {
			return filter.activity;
		}

		protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {

		}
	}

	private final class ServiceIntentResolver extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> {
		// Keys are String (activity class name), values are Activity.
		private final HashMap<ComponentName, PackageParser.Service> mServices = new HashMap<>();
		private int mFlags;

		public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
			mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0;
			return super.queryIntent(intent, resolvedType, defaultOnly);
		}

		public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) {
			mFlags = flags;
			return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0);
		}

		public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags,
				ArrayList<PackageParser.Service> packageServices) {
			if (packageServices == null) {
				return null;
			}
			mFlags = flags;
			final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0;
			final int N = packageServices.size();
			ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<PackageParser.ServiceIntentInfo[]>(N);

			ArrayList<PackageParser.ServiceIntentInfo> intentFilters;
			for (int i = 0; i < N; ++i) {
				intentFilters = packageServices.get(i).intents;
				if (intentFilters != null && intentFilters.size() > 0) {
					PackageParser.ServiceIntentInfo[] array = new PackageParser.ServiceIntentInfo[intentFilters.size()];
					intentFilters.toArray(array);
					listCut.add(array);
				}
			}
			return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut);
		}

		public final void addService(PackageParser.Service s) {
			mServices.put(s.getComponentName(), s);
			if (DEBUG_SHOW_INFO) {
				Log.v(TAG, "  " + (s.info.nonLocalizedLabel != null ? s.info.nonLocalizedLabel : s.info.name) + ":");
				Log.v(TAG, "    Class=" + s.info.name);
			}
			final int NI = s.intents.size();
			int j;
			for (j = 0; j < NI; j++) {
				PackageParser.ServiceIntentInfo intent = s.intents.get(j);
				addFilter(intent);
			}
		}

		public final void removeService(PackageParser.Service s) {
			mServices.remove(s.getComponentName());
			if (DEBUG_SHOW_INFO) {
				Log.v(TAG, "  " + (s.info.nonLocalizedLabel != null ? s.info.nonLocalizedLabel : s.info.name) + ":");
				Log.v(TAG, "    Class=" + s.info.name);
			}
			final int NI = s.intents.size();
			int j;
			for (j = 0; j < NI; j++) {
				PackageParser.ServiceIntentInfo intent = s.intents.get(j);
				removeFilter(intent);
			}
		}

		@Override
		protected boolean allowFilterResult(PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) {
			ServiceInfo filterSi = filter.service.info;
			for (int i = dest.size() - 1; i >= 0; i--) {
				ServiceInfo destAi = dest.get(i).serviceInfo;
				if (ObjectsCompat.equals(destAi.name, filterSi.name)
						&& ObjectsCompat.equals(destAi.packageName, filterSi.packageName)) {
					return false;
				}
			}
			return true;
		}

		@Override
		protected PackageParser.ServiceIntentInfo[] newArray(int size) {
			return new PackageParser.ServiceIntentInfo[size];
		}

		@Override
		protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter) {
			return false;
		}

		@Override
		protected boolean isPackageForFilter(String packageName, PackageParser.ServiceIntentInfo info) {
			return packageName.equals(info.service.owner.packageName);
		}

		@Override
		protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, int match) {
			final PackageParser.Service service = filter.service;
			ServiceInfo si = PackageParserCompat.generateServiceInfo(service, mFlags);
			if (si == null) {
				return null;
			}
			final ResolveInfo res = new ResolveInfo();
			res.serviceInfo = si;
			if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) {
				res.filter = filter;
			}
			res.priority = filter.getPriority();
			res.preferredOrder = service.owner.mPreferredOrder;
			res.match = match;
			res.isDefault = filter.hasDefault;
			res.labelRes = filter.labelRes;
			res.nonLocalizedLabel = filter.nonLocalizedLabel;
			res.icon = filter.icon;
			return res;
		}

		@Override
		protected void sortResults(List<ResolveInfo> results) {
			Collections.sort(results, mResolvePrioritySorter);
		}

		@Override
		protected void dumpFilter(PrintWriter out, String prefix, PackageParser.ServiceIntentInfo filter) {

		}

		@Override
		protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) {
			return filter.service;
		}

		protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) {

		}
	}

}