diff options
Diffstat (limited to 'services/java/com/android/server/ServiceWatcher.java')
-rw-r--r-- | services/java/com/android/server/ServiceWatcher.java | 382 |
1 files changed, 0 insertions, 382 deletions
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java deleted file mode 100644 index 5c7bfab..0000000 --- a/services/java/com/android/server/ServiceWatcher.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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.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 com.android.internal.content.PackageMonitor; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; - -/** - * 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 Object mLock = new Object(); - - // all fields below synchronized on mLock - private IBinder mBinder; // connected service - private String mPackageName; // current best package - private int mVersion = Integer.MIN_VALUE; // current best version - /** - * Whether the currently-connected service is multiuser-aware. This can change at run-time - * when switching from one version of a service to another. - */ - private boolean mIsMultiuser = false; - - 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.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); - } - - public boolean start() { - synchronized (mLock) { - if (!bindBestPackageLocked(mServicePackageName)) return false; - } - - // listen for user change - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_USER_SWITCHED); - mContext.registerReceiverAsUser(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_USER_SWITCHED.equals(action)) { - switchUser(); - } - } - }, 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. - * Only checks the named package, or checks all packages if it - * is null. - * Return true if a new package was found to bind to. - */ - private boolean bindBestPackageLocked(String justCheckThisPackage) { - Intent intent = new Intent(mAction); - if (justCheckThisPackage != null) { - intent.setPackage(justCheckThisPackage); - } - List<ResolveInfo> rInfos = mPm.queryIntentServicesAsUser(intent, - PackageManager.GET_META_DATA, UserHandle.USER_OWNER); - int bestVersion = Integer.MIN_VALUE; - String bestPackage = null; - boolean bestIsMultiuser = false; - if (rInfos != null) { - for (ResolveInfo rInfo : rInfos) { - String packageName = rInfo.serviceInfo.packageName; - - // check signature - try { - PackageInfo pInfo; - pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); - 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 > mVersion) { - bestVersion = version; - bestPackage = packageName; - bestIsMultiuser = isMultiuser; - } - } - - if (D) { - Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction, - (justCheckThisPackage == null ? "" - : "(" + justCheckThisPackage + ") "), rInfos.size(), - (bestPackage == null ? "no new best package" - : "new best package: " + bestPackage))); - } - } else { - if (D) Log.d(mTag, "Unable to query intent services for action: " + mAction); - } - if (bestPackage != null) { - bindToPackageLocked(bestPackage, bestVersion, bestIsMultiuser); - return true; - } - return false; - } - - private void unbindLocked() { - String pkg; - pkg = mPackageName; - mPackageName = null; - mVersion = Integer.MIN_VALUE; - mIsMultiuser = false; - if (pkg != null) { - if (D) Log.d(mTag, "unbinding " + pkg); - mContext.unbindService(this); - } - } - - private void bindToPackageLocked(String packageName, int version, boolean isMultiuser) { - unbindLocked(); - Intent intent = new Intent(mAction); - intent.setPackage(packageName); - mPackageName = packageName; - mVersion = version; - mIsMultiuser = isMultiuser; - if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ") (" - + (isMultiuser ? "multi" : "single") + "-user)"); - mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND - | Context.BIND_NOT_VISIBLE, mIsMultiuser ? UserHandle.OWNER : UserHandle.CURRENT); - } - - 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) { - if (packageName.equals(mPackageName)) { - // package updated, make sure to rebind - unbindLocked(); - } - // Need to check all packages because this method is also called when a - // system app is uninstalled and the stock version in reinstalled. - bindBestPackageLocked(null); - } - } - - @Override - public void onPackageAdded(String packageName, int uid) { - synchronized (mLock) { - if (packageName.equals(mPackageName)) { - // package updated, make sure to rebind - unbindLocked(); - } - // check the new package is case it is better - bindBestPackageLocked(null); - } - } - - @Override - public void onPackageRemoved(String packageName, int uid) { - synchronized (mLock) { - if (packageName.equals(mPackageName)) { - unbindLocked(); - // the currently bound package was removed, - // need to search for a new package - bindBestPackageLocked(null); - } - } - } - - @Override - public boolean onPackageChanged(String packageName, int uid, String[] components) { - synchronized (mLock) { - if (packageName.equals(mPackageName)) { - // service enabled or disabled, make sure to rebind - unbindLocked(); - } - // the service might be disabled, need to search for a new - // package - bindBestPackageLocked(null); - } - return super.onPackageChanged(packageName, uid, components); - } - }; - - @Override - public void onServiceConnected(ComponentName name, IBinder binder) { - synchronized (mLock) { - String packageName = name.getPackageName(); - if (packageName.equals(mPackageName)) { - if (D) Log.d(mTag, packageName + " connected"); - mBinder = binder; - if (mHandler !=null && mNewServiceWork != null) { - mHandler.post(mNewServiceWork); - } - } else { - Log.w(mTag, "unexpected onServiceConnected: " + packageName); - } - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - synchronized (mLock) { - String packageName = name.getPackageName(); - if (D) Log.d(mTag, packageName + " disconnected"); - - if (packageName.equals(mPackageName)) { - mBinder = null; - } - } - } - - public String getBestPackageName() { - synchronized (mLock) { - return mPackageName; - } - } - - public int getBestVersion() { - synchronized (mLock) { - return mVersion; - } - } - - public IBinder getBinder() { - synchronized (mLock) { - return mBinder; - } - } - - public void switchUser() { - synchronized (mLock) { - if (!mIsMultiuser) { - unbindLocked(); - bindBestPackageLocked(mServicePackageName); - } - } - } -} |