ServiceWatcher.java revision 20de160ca32a8f2936a80ffd70551a22e2371d25
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server; 18 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.Intent; 22import android.content.ServiceConnection; 23import android.content.pm.PackageInfo; 24import android.content.pm.PackageManager; 25import android.content.pm.PackageManager.NameNotFoundException; 26import android.content.pm.ResolveInfo; 27import android.content.pm.Signature; 28import android.os.Handler; 29import android.os.IBinder; 30import android.util.Log; 31 32import com.android.internal.content.PackageMonitor; 33 34import java.util.ArrayList; 35import java.util.Arrays; 36import java.util.HashSet; 37import java.util.List; 38 39/** 40 * Find the best Service, and bind to it. 41 * Handles run-time package changes. 42 */ 43public class ServiceWatcher implements ServiceConnection { 44 private static final boolean D = false; 45 private static final String EXTRA_VERSION = "version"; 46 47 private final String mTag; 48 private final Context mContext; 49 private final PackageManager mPm; 50 private final List<HashSet<Signature>> mSignatureSets; 51 private final String mAction; 52 private final Runnable mNewServiceWork; 53 private final Handler mHandler; 54 55 private Object mLock = new Object(); 56 57 // all fields below synchronized on mLock 58 private IBinder mBinder; // connected service 59 private String mPackageName; // current best package 60 private int mVersion; // current best version 61 62 public ServiceWatcher(Context context, String logTag, String action, 63 List<String> initialPackageNames, Runnable newServiceWork, Handler handler) { 64 mContext = context; 65 mTag = logTag; 66 mAction = action; 67 mPm = mContext.getPackageManager(); 68 mNewServiceWork = newServiceWork; 69 mHandler = handler; 70 71 mSignatureSets = new ArrayList<HashSet<Signature>>(); 72 for (int i=0; i < initialPackageNames.size(); i++) { 73 String pkg = initialPackageNames.get(i); 74 HashSet<Signature> set = new HashSet<Signature>(); 75 try { 76 Signature[] sigs = 77 mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures; 78 set.addAll(Arrays.asList(sigs)); 79 mSignatureSets.add(set); 80 } catch (NameNotFoundException e) { 81 Log.w(logTag, pkg + " not found"); 82 } 83 } 84 85 } 86 87 public boolean start() { 88 if (!bindBestPackage(null)) return false; 89 90 mPackageMonitor.register(mContext, null, true); 91 return true; 92 } 93 94 /** 95 * Searches and binds to the best package, or do nothing 96 * if the best package is already bound. 97 * Only checks the named package, or checks all packages if it 98 * is null. 99 * Return true if a new package was found to bind to. 100 */ 101 private boolean bindBestPackage(String justCheckThisPackage) { 102 Intent intent = new Intent(mAction); 103 if (justCheckThisPackage != null) { 104 intent.setPackage(justCheckThisPackage); 105 } 106 List<ResolveInfo> rInfos = mPm.queryIntentServices(new Intent(mAction), 107 PackageManager.GET_META_DATA); 108 int bestVersion = Integer.MIN_VALUE; 109 String bestPackage = null; 110 for (ResolveInfo rInfo : rInfos) { 111 String packageName = rInfo.serviceInfo.packageName; 112 113 // check signature 114 try { 115 PackageInfo pInfo; 116 pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); 117 if (!isSignatureMatch(pInfo.signatures)) { 118 Log.w(mTag, packageName + " resolves service " + mAction + 119 ", but has wrong signature, ignoring"); 120 continue; 121 } 122 } catch (NameNotFoundException e) { 123 Log.wtf(mTag, e); 124 continue; 125 } 126 127 // check version 128 int version = 0; 129 if (rInfo.serviceInfo.metaData != null) { 130 version = rInfo.serviceInfo.metaData.getInt(EXTRA_VERSION, 0); 131 } 132 if (version > mVersion) { 133 bestVersion = version; 134 bestPackage = packageName; 135 } 136 } 137 138 if (D) Log.d(mTag, String.format("bindBestPackage %s found %d, %s", 139 (justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "), 140 rInfos.size(), 141 (bestPackage == null ? "no new best package" : "new best packge: " + bestPackage))); 142 143 if (bestPackage != null) { 144 bindToPackage(bestPackage, bestVersion); 145 return true; 146 } 147 return false; 148 } 149 150 private void unbind() { 151 String pkg; 152 synchronized (mLock) { 153 pkg = mPackageName; 154 mPackageName = null; 155 mVersion = Integer.MIN_VALUE; 156 } 157 if (pkg != null) { 158 if (D) Log.d(mTag, "unbinding " + pkg); 159 mContext.unbindService(this); 160 } 161 } 162 163 private void bindToPackage(String packageName, int version) { 164 unbind(); 165 Intent intent = new Intent(mAction); 166 intent.setPackage(packageName); 167 synchronized (mLock) { 168 mPackageName = packageName; 169 mVersion = version; 170 } 171 if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ")"); 172 mContext.bindService(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND 173 | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE); 174 } 175 176 private boolean isSignatureMatch(Signature[] signatures) { 177 if (signatures == null) return false; 178 179 // build hashset of input to test against 180 HashSet<Signature> inputSet = new HashSet<Signature>(); 181 for (Signature s : signatures) { 182 inputSet.add(s); 183 } 184 185 // test input against each of the signature sets 186 for (HashSet<Signature> referenceSet : mSignatureSets) { 187 if (referenceSet.equals(inputSet)) { 188 return true; 189 } 190 } 191 return false; 192 } 193 194 private final PackageMonitor mPackageMonitor = new PackageMonitor() { 195 /** 196 * Called when package has been reinstalled 197 */ 198 @Override 199 public void onPackageUpdateFinished(String packageName, int uid) { 200 if (packageName.equals(mPackageName)) { 201 // package updated, make sure to rebind 202 unbind(); 203 } 204 // check the updated package in case it is better 205 bindBestPackage(packageName); 206 } 207 208 @Override 209 public void onPackageAdded(String packageName, int uid) { 210 if (packageName.equals(mPackageName)) { 211 // package updated, make sure to rebind 212 unbind(); 213 } 214 // check the new package is case it is better 215 bindBestPackage(packageName); 216 } 217 218 @Override 219 public void onPackageRemoved(String packageName, int uid) { 220 if (packageName.equals(mPackageName)) { 221 unbind(); 222 // the currently bound package was removed, 223 // need to search for a new package 224 bindBestPackage(null); 225 } 226 } 227 }; 228 229 @Override 230 public void onServiceConnected(ComponentName name, IBinder binder) { 231 synchronized (mLock) { 232 String packageName = name.getPackageName(); 233 if (packageName.equals(mPackageName)) { 234 if (D) Log.d(mTag, packageName + " connected"); 235 mBinder = binder; 236 if (mHandler !=null && mNewServiceWork != null) { 237 mHandler.post(mNewServiceWork); 238 } 239 } else { 240 Log.w(mTag, "unexpected onServiceConnected: " + packageName); 241 } 242 } 243 } 244 245 @Override 246 public void onServiceDisconnected(ComponentName name) { 247 synchronized (mLock) { 248 String packageName = name.getPackageName(); 249 if (D) Log.d(mTag, packageName + " disconnected"); 250 251 if (packageName.equals(mPackageName)) { 252 mBinder = null; 253 } 254 } 255 } 256 257 public String getBestPackageName() { 258 synchronized (mLock) { 259 return mPackageName; 260 } 261 } 262 263 public int getBestVersion() { 264 synchronized (mLock) { 265 return mVersion; 266 } 267 } 268 269 public IBinder getBinder() { 270 synchronized (mLock) { 271 return mBinder; 272 } 273 } 274} 275