AppWidgetServiceImpl.java revision 791f877473cc6b3e8e484b741012c95aba70c3b0
1/* 2 * Copyright (C) 2011 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.app.AlarmManager; 20import android.app.AppGlobals; 21import android.app.PendingIntent; 22import android.appwidget.AppWidgetManager; 23import android.appwidget.AppWidgetProviderInfo; 24import android.content.ComponentName; 25import android.content.Context; 26import android.content.Intent; 27import android.content.Intent.FilterComparison; 28import android.content.ServiceConnection; 29import android.content.pm.ActivityInfo; 30import android.content.pm.ApplicationInfo; 31import android.content.pm.IPackageManager; 32import android.content.pm.PackageInfo; 33import android.content.pm.PackageManager; 34import android.content.pm.ResolveInfo; 35import android.content.pm.ServiceInfo; 36import android.content.res.Resources; 37import android.content.res.TypedArray; 38import android.content.res.XmlResourceParser; 39import android.graphics.Point; 40import android.net.Uri; 41import android.os.Binder; 42import android.os.Bundle; 43import android.os.Environment; 44import android.os.Handler; 45import android.os.HandlerThread; 46import android.os.IBinder; 47import android.os.Looper; 48import android.os.Process; 49import android.os.RemoteException; 50import android.os.SystemClock; 51import android.os.UserHandle; 52import android.util.AtomicFile; 53import android.util.AttributeSet; 54import android.util.Log; 55import android.util.Pair; 56import android.util.Slog; 57import android.util.TypedValue; 58import android.util.Xml; 59import android.view.Display; 60import android.view.WindowManager; 61import android.widget.RemoteViews; 62 63import com.android.internal.appwidget.IAppWidgetHost; 64import com.android.internal.util.FastXmlSerializer; 65import com.android.internal.widget.IRemoteViewsAdapterConnection; 66import com.android.internal.widget.IRemoteViewsFactory; 67 68import org.xmlpull.v1.XmlPullParser; 69import org.xmlpull.v1.XmlPullParserException; 70import org.xmlpull.v1.XmlSerializer; 71 72import java.io.File; 73import java.io.FileDescriptor; 74import java.io.FileInputStream; 75import java.io.FileNotFoundException; 76import java.io.FileOutputStream; 77import java.io.IOException; 78import java.io.PrintWriter; 79import java.util.ArrayList; 80import java.util.HashMap; 81import java.util.HashSet; 82import java.util.Iterator; 83import java.util.List; 84import java.util.Locale; 85import java.util.Set; 86 87class AppWidgetServiceImpl { 88 89 private static final String TAG = "AppWidgetServiceImpl"; 90 private static final String SETTINGS_FILENAME = "appwidgets.xml"; 91 private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes 92 93 private static boolean DBG = false; 94 95 /* 96 * When identifying a Host or Provider based on the calling process, use the uid field. When 97 * identifying a Host or Provider based on a package manager broadcast, use the package given. 98 */ 99 100 static class Provider { 101 int uid; 102 AppWidgetProviderInfo info; 103 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>(); 104 PendingIntent broadcast; 105 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 106 107 int tag; // for use while saving state (the index) 108 } 109 110 static class Host { 111 int uid; 112 int hostId; 113 String packageName; 114 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>(); 115 IAppWidgetHost callbacks; 116 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 117 118 int tag; // for use while saving state (the index) 119 } 120 121 static class AppWidgetId { 122 int appWidgetId; 123 Provider provider; 124 RemoteViews views; 125 Bundle options; 126 Host host; 127 } 128 129 /** 130 * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This 131 * needs to be a static inner class since a reference to the ServiceConnection is held globally 132 * and may lead us to leak AppWidgetService instances (if there were more than one). 133 */ 134 static class ServiceConnectionProxy implements ServiceConnection { 135 private final IBinder mConnectionCb; 136 137 ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) { 138 mConnectionCb = connectionCb; 139 } 140 141 public void onServiceConnected(ComponentName name, IBinder service) { 142 final IRemoteViewsAdapterConnection cb = IRemoteViewsAdapterConnection.Stub 143 .asInterface(mConnectionCb); 144 try { 145 cb.onServiceConnected(service); 146 } catch (Exception e) { 147 e.printStackTrace(); 148 } 149 } 150 151 public void onServiceDisconnected(ComponentName name) { 152 disconnect(); 153 } 154 155 public void disconnect() { 156 final IRemoteViewsAdapterConnection cb = IRemoteViewsAdapterConnection.Stub 157 .asInterface(mConnectionCb); 158 try { 159 cb.onServiceDisconnected(); 160 } catch (Exception e) { 161 e.printStackTrace(); 162 } 163 } 164 } 165 166 // Manages active connections to RemoteViewsServices 167 private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection> mBoundRemoteViewsServices = new HashMap<Pair<Integer, FilterComparison>, ServiceConnection>(); 168 // Manages persistent references to RemoteViewsServices from different App Widgets 169 private final HashMap<FilterComparison, HashSet<Integer>> mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>(); 170 171 Context mContext; 172 Locale mLocale; 173 IPackageManager mPm; 174 AlarmManager mAlarmManager; 175 ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>(); 176 int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1; 177 final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>(); 178 ArrayList<Host> mHosts = new ArrayList<Host>(); 179 // set of package names 180 HashSet<String> mPackagesWithBindWidgetPermission = new HashSet<String>(); 181 boolean mSafeMode; 182 int mUserId; 183 boolean mStateLoaded; 184 int mMaxWidgetBitmapMemory; 185 186 private final Handler mSaveStateHandler; 187 188 // These are for debugging only -- widgets are going missing in some rare instances 189 ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>(); 190 ArrayList<Host> mDeletedHosts = new ArrayList<Host>(); 191 192 AppWidgetServiceImpl(Context context, int userId, Handler saveStateHandler) { 193 mContext = context; 194 mPm = AppGlobals.getPackageManager(); 195 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 196 mUserId = userId; 197 mSaveStateHandler = saveStateHandler; 198 computeMaximumWidgetBitmapMemory(); 199 } 200 201 void computeMaximumWidgetBitmapMemory() { 202 WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 203 Display display = wm.getDefaultDisplay(); 204 Point size = new Point(); 205 display.getRealSize(size); 206 // Cap memory usage at 1.5 times the size of the display 207 // 1.5 * 4 bytes/pixel * w * h ==> 6 * w * h 208 mMaxWidgetBitmapMemory = 6 * size.x * size.y; 209 } 210 211 public void systemReady(boolean safeMode) { 212 mSafeMode = safeMode; 213 214 synchronized (mAppWidgetIds) { 215 ensureStateLoadedLocked(); 216 } 217 } 218 219 private void log(String msg) { 220 Slog.i(TAG, "u=" + mUserId + ": " + msg); 221 } 222 223 void onConfigurationChanged() { 224 if (DBG) log("Got onConfigurationChanged()"); 225 Locale revised = Locale.getDefault(); 226 if (revised == null || mLocale == null || !(revised.equals(mLocale))) { 227 mLocale = revised; 228 229 synchronized (mAppWidgetIds) { 230 ensureStateLoadedLocked(); 231 // Note: updateProvidersForPackageLocked() may remove providers, so we must copy the 232 // list of installed providers and skip providers that we don't need to update. 233 // Also note that remove the provider does not clear the Provider component data. 234 ArrayList<Provider> installedProviders = 235 new ArrayList<Provider>(mInstalledProviders); 236 HashSet<ComponentName> removedProviders = new HashSet<ComponentName>(); 237 int N = installedProviders.size(); 238 for (int i = N - 1; i >= 0; i--) { 239 Provider p = installedProviders.get(i); 240 ComponentName cn = p.info.provider; 241 if (!removedProviders.contains(cn)) { 242 updateProvidersForPackageLocked(cn.getPackageName(), removedProviders); 243 } 244 } 245 saveStateAsync(); 246 } 247 } 248 } 249 250 void onBroadcastReceived(Intent intent) { 251 if (DBG) log("onBroadcast " + intent); 252 final String action = intent.getAction(); 253 boolean added = false; 254 boolean changed = false; 255 boolean providersModified = false; 256 String pkgList[] = null; 257 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 258 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 259 added = true; 260 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 261 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 262 added = false; 263 } else { 264 Uri uri = intent.getData(); 265 if (uri == null) { 266 return; 267 } 268 String pkgName = uri.getSchemeSpecificPart(); 269 if (pkgName == null) { 270 return; 271 } 272 pkgList = new String[] { pkgName }; 273 added = Intent.ACTION_PACKAGE_ADDED.equals(action); 274 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); 275 } 276 if (pkgList == null || pkgList.length == 0) { 277 return; 278 } 279 if (added || changed) { 280 synchronized (mAppWidgetIds) { 281 ensureStateLoadedLocked(); 282 Bundle extras = intent.getExtras(); 283 if (changed 284 || (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false))) { 285 for (String pkgName : pkgList) { 286 // The package was just upgraded 287 providersModified |= updateProvidersForPackageLocked(pkgName, null); 288 } 289 } else { 290 // The package was just added 291 for (String pkgName : pkgList) { 292 providersModified |= addProvidersForPackageLocked(pkgName); 293 } 294 } 295 saveStateAsync(); 296 } 297 } else { 298 Bundle extras = intent.getExtras(); 299 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { 300 // The package is being updated. We'll receive a PACKAGE_ADDED shortly. 301 } else { 302 synchronized (mAppWidgetIds) { 303 ensureStateLoadedLocked(); 304 for (String pkgName : pkgList) { 305 providersModified |= removeProvidersForPackageLocked(pkgName); 306 saveStateAsync(); 307 } 308 } 309 } 310 } 311 312 if (providersModified) { 313 // If the set of providers has been modified, notify each active AppWidgetHost 314 synchronized (mAppWidgetIds) { 315 ensureStateLoadedLocked(); 316 notifyHostsForProvidersChangedLocked(); 317 } 318 } 319 } 320 321 private void dumpProvider(Provider p, int index, PrintWriter pw) { 322 AppWidgetProviderInfo info = p.info; 323 pw.print(" ["); pw.print(index); pw.print("] provider "); 324 pw.print(info.provider.flattenToShortString()); 325 pw.println(':'); 326 pw.print(" min=("); pw.print(info.minWidth); 327 pw.print("x"); pw.print(info.minHeight); 328 pw.print(") minResize=("); pw.print(info.minResizeWidth); 329 pw.print("x"); pw.print(info.minResizeHeight); 330 pw.print(") updatePeriodMillis="); 331 pw.print(info.updatePeriodMillis); 332 pw.print(" resizeMode="); 333 pw.print(info.resizeMode); 334 pw.print(info.widgetCategory); 335 pw.print(" autoAdvanceViewId="); 336 pw.print(info.autoAdvanceViewId); 337 pw.print(" initialLayout=#"); 338 pw.print(Integer.toHexString(info.initialLayout)); 339 pw.print(" uid="); pw.print(p.uid); 340 pw.print(" zombie="); pw.println(p.zombie); 341 } 342 343 private void dumpHost(Host host, int index, PrintWriter pw) { 344 pw.print(" ["); pw.print(index); pw.print("] hostId="); 345 pw.print(host.hostId); pw.print(' '); 346 pw.print(host.packageName); pw.print('/'); 347 pw.print(host.uid); pw.println(':'); 348 pw.print(" callbacks="); pw.println(host.callbacks); 349 pw.print(" instances.size="); pw.print(host.instances.size()); 350 pw.print(" zombie="); pw.println(host.zombie); 351 } 352 353 private void dumpAppWidgetId(AppWidgetId id, int index, PrintWriter pw) { 354 pw.print(" ["); pw.print(index); pw.print("] id="); 355 pw.println(id.appWidgetId); 356 pw.print(" hostId="); 357 pw.print(id.host.hostId); pw.print(' '); 358 pw.print(id.host.packageName); pw.print('/'); 359 pw.println(id.host.uid); 360 if (id.provider != null) { 361 pw.print(" provider="); 362 pw.println(id.provider.info.provider.flattenToShortString()); 363 } 364 if (id.host != null) { 365 pw.print(" host.callbacks="); pw.println(id.host.callbacks); 366 } 367 if (id.views != null) { 368 pw.print(" views="); pw.println(id.views); 369 } 370 } 371 372 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 373 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 374 != PackageManager.PERMISSION_GRANTED) { 375 pw.println("Permission Denial: can't dump from from pid=" 376 + Binder.getCallingPid() 377 + ", uid=" + Binder.getCallingUid()); 378 return; 379 } 380 381 synchronized (mAppWidgetIds) { 382 int N = mInstalledProviders.size(); 383 pw.println("Providers:"); 384 for (int i=0; i<N; i++) { 385 dumpProvider(mInstalledProviders.get(i), i, pw); 386 } 387 388 N = mAppWidgetIds.size(); 389 pw.println(" "); 390 pw.println("AppWidgetIds:"); 391 for (int i=0; i<N; i++) { 392 dumpAppWidgetId(mAppWidgetIds.get(i), i, pw); 393 } 394 395 N = mHosts.size(); 396 pw.println(" "); 397 pw.println("Hosts:"); 398 for (int i=0; i<N; i++) { 399 dumpHost(mHosts.get(i), i, pw); 400 } 401 402 N = mDeletedProviders.size(); 403 pw.println(" "); 404 pw.println("Deleted Providers:"); 405 for (int i=0; i<N; i++) { 406 dumpProvider(mDeletedProviders.get(i), i, pw); 407 } 408 409 N = mDeletedHosts.size(); 410 pw.println(" "); 411 pw.println("Deleted Hosts:"); 412 for (int i=0; i<N; i++) { 413 dumpHost(mDeletedHosts.get(i), i, pw); 414 } 415 } 416 } 417 418 private void ensureStateLoadedLocked() { 419 if (!mStateLoaded) { 420 loadAppWidgetListLocked(); 421 loadStateLocked(); 422 mStateLoaded = true; 423 } 424 } 425 426 public int allocateAppWidgetId(String packageName, int hostId) { 427 int callingUid = enforceSystemOrCallingUid(packageName); 428 synchronized (mAppWidgetIds) { 429 ensureStateLoadedLocked(); 430 int appWidgetId = mNextAppWidgetId++; 431 432 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); 433 434 AppWidgetId id = new AppWidgetId(); 435 id.appWidgetId = appWidgetId; 436 id.host = host; 437 438 host.instances.add(id); 439 mAppWidgetIds.add(id); 440 441 saveStateAsync(); 442 if (DBG) log("Allocating AppWidgetId for " + packageName + " host=" + hostId 443 + " id=" + appWidgetId); 444 return appWidgetId; 445 } 446 } 447 448 public void deleteAppWidgetId(int appWidgetId) { 449 synchronized (mAppWidgetIds) { 450 ensureStateLoadedLocked(); 451 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 452 if (id != null) { 453 deleteAppWidgetLocked(id); 454 saveStateAsync(); 455 } 456 } 457 } 458 459 public void deleteHost(int hostId) { 460 synchronized (mAppWidgetIds) { 461 ensureStateLoadedLocked(); 462 int callingUid = Binder.getCallingUid(); 463 Host host = lookupHostLocked(callingUid, hostId); 464 if (host != null) { 465 deleteHostLocked(host); 466 saveStateAsync(); 467 } 468 } 469 } 470 471 public void deleteAllHosts() { 472 synchronized (mAppWidgetIds) { 473 ensureStateLoadedLocked(); 474 int callingUid = Binder.getCallingUid(); 475 final int N = mHosts.size(); 476 boolean changed = false; 477 for (int i = N - 1; i >= 0; i--) { 478 Host host = mHosts.get(i); 479 if (host.uid == callingUid) { 480 deleteHostLocked(host); 481 changed = true; 482 } 483 } 484 if (changed) { 485 saveStateAsync(); 486 } 487 } 488 } 489 490 void deleteHostLocked(Host host) { 491 final int N = host.instances.size(); 492 for (int i = N - 1; i >= 0; i--) { 493 AppWidgetId id = host.instances.get(i); 494 deleteAppWidgetLocked(id); 495 } 496 host.instances.clear(); 497 mHosts.remove(host); 498 mDeletedHosts.add(host); 499 // it's gone or going away, abruptly drop the callback connection 500 host.callbacks = null; 501 } 502 503 void deleteAppWidgetLocked(AppWidgetId id) { 504 // We first unbind all services that are bound to this id 505 unbindAppWidgetRemoteViewsServicesLocked(id); 506 507 Host host = id.host; 508 host.instances.remove(id); 509 pruneHostLocked(host); 510 511 mAppWidgetIds.remove(id); 512 513 Provider p = id.provider; 514 if (p != null) { 515 p.instances.remove(id); 516 if (!p.zombie) { 517 // send the broacast saying that this appWidgetId has been deleted 518 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); 519 intent.setComponent(p.info.provider); 520 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); 521 mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); 522 if (p.instances.size() == 0) { 523 // cancel the future updates 524 cancelBroadcasts(p); 525 526 // send the broacast saying that the provider is not in use any more 527 intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); 528 intent.setComponent(p.info.provider); 529 mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); 530 } 531 } 532 } 533 } 534 535 void cancelBroadcasts(Provider p) { 536 if (DBG) log("cancelBroadcasts for " + p); 537 if (p.broadcast != null) { 538 mAlarmManager.cancel(p.broadcast); 539 long token = Binder.clearCallingIdentity(); 540 try { 541 p.broadcast.cancel(); 542 } finally { 543 Binder.restoreCallingIdentity(token); 544 } 545 p.broadcast = null; 546 } 547 } 548 549 private void bindAppWidgetIdImpl(int appWidgetId, ComponentName provider, Bundle options) { 550 if (DBG) log("bindAppWidgetIdImpl appwid=" + appWidgetId 551 + " provider=" + provider); 552 final long ident = Binder.clearCallingIdentity(); 553 try { 554 synchronized (mAppWidgetIds) { 555 options = cloneIfLocalBinder(options); 556 ensureStateLoadedLocked(); 557 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 558 if (id == null) { 559 throw new IllegalArgumentException("bad appWidgetId"); 560 } 561 if (id.provider != null) { 562 throw new IllegalArgumentException("appWidgetId " + appWidgetId 563 + " already bound to " + id.provider.info.provider); 564 } 565 Provider p = lookupProviderLocked(provider); 566 if (p == null) { 567 throw new IllegalArgumentException("not a appwidget provider: " + provider); 568 } 569 if (p.zombie) { 570 throw new IllegalArgumentException("can't bind to a 3rd party provider in" 571 + " safe mode: " + provider); 572 } 573 574 id.provider = p; 575 if (options == null) { 576 options = new Bundle(); 577 } 578 id.options = options; 579 580 // We need to provide a default value for the widget category if it is not specified 581 if (!options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) { 582 options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 583 AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); 584 } 585 586 p.instances.add(id); 587 int instancesSize = p.instances.size(); 588 if (instancesSize == 1) { 589 // tell the provider that it's ready 590 sendEnableIntentLocked(p); 591 } 592 593 // send an update now -- We need this update now, and just for this appWidgetId. 594 // It's less critical when the next one happens, so when we schedule the next one, 595 // we add updatePeriodMillis to its start time. That time will have some slop, 596 // but that's okay. 597 sendUpdateIntentLocked(p, new int[] { appWidgetId }); 598 599 // schedule the future updates 600 registerForBroadcastsLocked(p, getAppWidgetIds(p)); 601 saveStateAsync(); 602 } 603 } finally { 604 Binder.restoreCallingIdentity(ident); 605 } 606 } 607 608 public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options) { 609 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET, 610 "bindAppWidgetId appWidgetId=" + appWidgetId + " provider=" + provider); 611 bindAppWidgetIdImpl(appWidgetId, provider, options); 612 } 613 614 public boolean bindAppWidgetIdIfAllowed( 615 String packageName, int appWidgetId, ComponentName provider, Bundle options) { 616 try { 617 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET, null); 618 } catch (SecurityException se) { 619 if (!callerHasBindAppWidgetPermission(packageName)) { 620 return false; 621 } 622 } 623 bindAppWidgetIdImpl(appWidgetId, provider, options); 624 return true; 625 } 626 627 private boolean callerHasBindAppWidgetPermission(String packageName) { 628 int callingUid = Binder.getCallingUid(); 629 try { 630 if (!UserHandle.isSameApp(callingUid, getUidForPackage(packageName))) { 631 return false; 632 } 633 } catch (Exception e) { 634 return false; 635 } 636 synchronized (mAppWidgetIds) { 637 ensureStateLoadedLocked(); 638 return mPackagesWithBindWidgetPermission.contains(packageName); 639 } 640 } 641 642 public boolean hasBindAppWidgetPermission(String packageName) { 643 mContext.enforceCallingPermission( 644 android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS, 645 "hasBindAppWidgetPermission packageName=" + packageName); 646 647 synchronized (mAppWidgetIds) { 648 ensureStateLoadedLocked(); 649 return mPackagesWithBindWidgetPermission.contains(packageName); 650 } 651 } 652 653 public void setBindAppWidgetPermission(String packageName, boolean permission) { 654 mContext.enforceCallingPermission( 655 android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS, 656 "setBindAppWidgetPermission packageName=" + packageName); 657 658 synchronized (mAppWidgetIds) { 659 ensureStateLoadedLocked(); 660 if (permission) { 661 mPackagesWithBindWidgetPermission.add(packageName); 662 } else { 663 mPackagesWithBindWidgetPermission.remove(packageName); 664 } 665 saveStateAsync(); 666 } 667 } 668 669 // Binds to a specific RemoteViewsService 670 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) { 671 synchronized (mAppWidgetIds) { 672 ensureStateLoadedLocked(); 673 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 674 if (id == null) { 675 throw new IllegalArgumentException("bad appWidgetId"); 676 } 677 final ComponentName componentName = intent.getComponent(); 678 try { 679 final ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(componentName, 680 PackageManager.GET_PERMISSIONS, mUserId); 681 if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) { 682 throw new SecurityException("Selected service does not require " 683 + android.Manifest.permission.BIND_REMOTEVIEWS + ": " + componentName); 684 } 685 } catch (RemoteException e) { 686 throw new IllegalArgumentException("Unknown component " + componentName); 687 } 688 689 // If there is already a connection made for this service intent, then disconnect from 690 // that first. (This does not allow multiple connections to the same service under 691 // the same key) 692 ServiceConnectionProxy conn = null; 693 FilterComparison fc = new FilterComparison(intent); 694 Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc); 695 if (mBoundRemoteViewsServices.containsKey(key)) { 696 conn = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key); 697 conn.disconnect(); 698 mContext.unbindService(conn); 699 mBoundRemoteViewsServices.remove(key); 700 } 701 702 int userId = UserHandle.getUserId(id.provider.uid); 703 if (userId != mUserId) { 704 Slog.w(TAG, "AppWidgetServiceImpl of user " + mUserId 705 + " binding to provider on user " + userId); 706 } 707 // Bind to the RemoteViewsService (which will trigger a callback to the 708 // RemoteViewsAdapter.onServiceConnected()) 709 final long token = Binder.clearCallingIdentity(); 710 try { 711 conn = new ServiceConnectionProxy(key, connection); 712 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId); 713 mBoundRemoteViewsServices.put(key, conn); 714 } finally { 715 Binder.restoreCallingIdentity(token); 716 } 717 718 // Add it to the mapping of RemoteViewsService to appWidgetIds so that we can determine 719 // when we can call back to the RemoteViewsService later to destroy associated 720 // factories. 721 incrementAppWidgetServiceRefCount(appWidgetId, fc); 722 } 723 } 724 725 // Unbinds from a specific RemoteViewsService 726 public void unbindRemoteViewsService(int appWidgetId, Intent intent) { 727 synchronized (mAppWidgetIds) { 728 ensureStateLoadedLocked(); 729 // Unbind from the RemoteViewsService (which will trigger a callback to the bound 730 // RemoteViewsAdapter) 731 Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, new FilterComparison( 732 intent)); 733 if (mBoundRemoteViewsServices.containsKey(key)) { 734 // We don't need to use the appWidgetId until after we are sure there is something 735 // to unbind. Note that this may mask certain issues with apps calling unbind() 736 // more than necessary. 737 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 738 if (id == null) { 739 throw new IllegalArgumentException("bad appWidgetId"); 740 } 741 742 ServiceConnectionProxy conn = (ServiceConnectionProxy) mBoundRemoteViewsServices 743 .get(key); 744 conn.disconnect(); 745 mContext.unbindService(conn); 746 mBoundRemoteViewsServices.remove(key); 747 } else { 748 Log.e("AppWidgetService", "Error (unbindRemoteViewsService): Connection not bound"); 749 } 750 } 751 } 752 753 // Unbinds from a RemoteViewsService when we delete an app widget 754 private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) { 755 int appWidgetId = id.appWidgetId; 756 // Unbind all connections to Services bound to this AppWidgetId 757 Iterator<Pair<Integer, Intent.FilterComparison>> it = mBoundRemoteViewsServices.keySet() 758 .iterator(); 759 while (it.hasNext()) { 760 final Pair<Integer, Intent.FilterComparison> key = it.next(); 761 if (key.first.intValue() == appWidgetId) { 762 final ServiceConnectionProxy conn = (ServiceConnectionProxy) mBoundRemoteViewsServices 763 .get(key); 764 conn.disconnect(); 765 mContext.unbindService(conn); 766 it.remove(); 767 } 768 } 769 770 // Check if we need to destroy any services (if no other app widgets are 771 // referencing the same service) 772 decrementAppWidgetServiceRefCount(id); 773 } 774 775 // Destroys the cached factory on the RemoteViewsService's side related to the specified intent 776 private void destroyRemoteViewsService(final Intent intent, AppWidgetId id) { 777 final ServiceConnection conn = new ServiceConnection() { 778 @Override 779 public void onServiceConnected(ComponentName name, IBinder service) { 780 final IRemoteViewsFactory cb = IRemoteViewsFactory.Stub.asInterface(service); 781 try { 782 cb.onDestroy(intent); 783 } catch (RemoteException e) { 784 e.printStackTrace(); 785 } catch (RuntimeException e) { 786 e.printStackTrace(); 787 } 788 mContext.unbindService(this); 789 } 790 791 @Override 792 public void onServiceDisconnected(android.content.ComponentName name) { 793 // Do nothing 794 } 795 }; 796 797 int userId = UserHandle.getUserId(id.provider.uid); 798 // Bind to the service and remove the static intent->factory mapping in the 799 // RemoteViewsService. 800 final long token = Binder.clearCallingIdentity(); 801 try { 802 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId); 803 } finally { 804 Binder.restoreCallingIdentity(token); 805 } 806 } 807 808 // Adds to the ref-count for a given RemoteViewsService intent 809 private void incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc) { 810 HashSet<Integer> appWidgetIds = null; 811 if (mRemoteViewsServicesAppWidgets.containsKey(fc)) { 812 appWidgetIds = mRemoteViewsServicesAppWidgets.get(fc); 813 } else { 814 appWidgetIds = new HashSet<Integer>(); 815 mRemoteViewsServicesAppWidgets.put(fc, appWidgetIds); 816 } 817 appWidgetIds.add(appWidgetId); 818 } 819 820 // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if 821 // the ref-count reaches zero. 822 private void decrementAppWidgetServiceRefCount(AppWidgetId id) { 823 Iterator<FilterComparison> it = mRemoteViewsServicesAppWidgets.keySet().iterator(); 824 while (it.hasNext()) { 825 final FilterComparison key = it.next(); 826 final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key); 827 if (ids.remove(id.appWidgetId)) { 828 // If we have removed the last app widget referencing this service, then we 829 // should destroy it and remove it from this set 830 if (ids.isEmpty()) { 831 destroyRemoteViewsService(key.getIntent(), id); 832 it.remove(); 833 } 834 } 835 } 836 } 837 838 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { 839 synchronized (mAppWidgetIds) { 840 ensureStateLoadedLocked(); 841 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 842 if (id != null && id.provider != null && !id.provider.zombie) { 843 return cloneIfLocalBinder(id.provider.info); 844 } 845 return null; 846 } 847 } 848 849 public RemoteViews getAppWidgetViews(int appWidgetId) { 850 if (DBG) log("getAppWidgetViews id=" + appWidgetId); 851 synchronized (mAppWidgetIds) { 852 ensureStateLoadedLocked(); 853 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 854 if (id != null) { 855 return cloneIfLocalBinder(id.views); 856 } 857 if (DBG) log(" couldn't find appwidgetid"); 858 return null; 859 } 860 } 861 862 public List<AppWidgetProviderInfo> getInstalledProviders() { 863 return getInstalledProviders(AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); 864 } 865 866 private List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter) { 867 synchronized (mAppWidgetIds) { 868 ensureStateLoadedLocked(); 869 final int N = mInstalledProviders.size(); 870 ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N); 871 for (int i = 0; i < N; i++) { 872 Provider p = mInstalledProviders.get(i); 873 if (!p.zombie && (p.info.widgetCategory & categoryFilter) != 0) { 874 result.add(cloneIfLocalBinder(p.info)); 875 } 876 } 877 return result; 878 } 879 } 880 881 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) { 882 if (appWidgetIds == null) { 883 return; 884 } 885 if (DBG) log("updateAppWidgetIds views: " + views); 886 int bitmapMemoryUsage = 0; 887 if (views != null) { 888 bitmapMemoryUsage = views.estimateMemoryUsage(); 889 } 890 if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) { 891 throw new IllegalArgumentException("RemoteViews for widget update exceeds maximum" + 892 " bitmap memory usage (used: " + bitmapMemoryUsage + ", max: " + 893 mMaxWidgetBitmapMemory + ") The total memory cannot exceed that required to" + 894 " fill the device's screen once."); 895 } 896 897 if (appWidgetIds.length == 0) { 898 return; 899 } 900 final int N = appWidgetIds.length; 901 902 synchronized (mAppWidgetIds) { 903 ensureStateLoadedLocked(); 904 for (int i = 0; i < N; i++) { 905 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 906 updateAppWidgetInstanceLocked(id, views); 907 } 908 } 909 } 910 911 private void saveStateAsync() { 912 mSaveStateHandler.post(mSaveStateRunnable); 913 } 914 915 private final Runnable mSaveStateRunnable = new Runnable() { 916 @Override 917 public void run() { 918 synchronized (mAppWidgetIds) { 919 ensureStateLoadedLocked(); 920 saveStateLocked(); 921 } 922 } 923 }; 924 925 public void updateAppWidgetOptions(int appWidgetId, Bundle options) { 926 synchronized (mAppWidgetIds) { 927 options = cloneIfLocalBinder(options); 928 ensureStateLoadedLocked(); 929 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 930 931 if (id == null) { 932 return; 933 } 934 935 Provider p = id.provider; 936 // Merge the options 937 id.options.putAll(options); 938 939 // send the broacast saying that this appWidgetId has been deleted 940 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED); 941 intent.setComponent(p.info.provider); 942 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); 943 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, id.options); 944 mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); 945 saveStateAsync(); 946 } 947 } 948 949 public Bundle getAppWidgetOptions(int appWidgetId) { 950 synchronized (mAppWidgetIds) { 951 ensureStateLoadedLocked(); 952 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 953 if (id != null && id.options != null) { 954 return cloneIfLocalBinder(id.options); 955 } else { 956 return Bundle.EMPTY; 957 } 958 } 959 } 960 961 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) { 962 if (appWidgetIds == null) { 963 return; 964 } 965 if (appWidgetIds.length == 0) { 966 return; 967 } 968 final int N = appWidgetIds.length; 969 970 synchronized (mAppWidgetIds) { 971 ensureStateLoadedLocked(); 972 for (int i = 0; i < N; i++) { 973 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 974 if (id == null) { 975 String message = "AppWidgetId NPE: mUserId=" + mUserId 976 + ", callingUid=" + Binder.getCallingUid() 977 + ", appWidgetIds[i]=" + appWidgetIds[i] 978 + "\n mAppWidgets:\n" + getUserWidgets(); 979 throw new NullPointerException(message); 980 } 981 if (id.views != null) { 982 // Only trigger a partial update for a widget if it has received a full update 983 updateAppWidgetInstanceLocked(id, views, true); 984 } 985 } 986 } 987 } 988 989 private String getUserWidgets() { 990 StringBuffer sb = new StringBuffer(); 991 for (AppWidgetId widget: mAppWidgetIds) { 992 sb.append(" id="); sb.append(widget.appWidgetId); 993 sb.append(", hostUid="); sb.append(widget.host.uid); 994 sb.append(", provider="); sb.append(widget.provider.info.provider.toString()); 995 sb.append("\n"); 996 } 997 sb.append("\n"); 998 return sb.toString(); 999 } 1000 1001 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) { 1002 if (appWidgetIds == null) { 1003 return; 1004 } 1005 if (appWidgetIds.length == 0) { 1006 return; 1007 } 1008 final int N = appWidgetIds.length; 1009 1010 synchronized (mAppWidgetIds) { 1011 ensureStateLoadedLocked(); 1012 for (int i = 0; i < N; i++) { 1013 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 1014 notifyAppWidgetViewDataChangedInstanceLocked(id, viewId); 1015 } 1016 } 1017 } 1018 1019 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) { 1020 synchronized (mAppWidgetIds) { 1021 ensureStateLoadedLocked(); 1022 Provider p = lookupProviderLocked(provider); 1023 if (p == null) { 1024 Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider); 1025 return; 1026 } 1027 ArrayList<AppWidgetId> instances = p.instances; 1028 final int callingUid = Binder.getCallingUid(); 1029 final int N = instances.size(); 1030 for (int i = 0; i < N; i++) { 1031 AppWidgetId id = instances.get(i); 1032 if (canAccessAppWidgetId(id, callingUid)) { 1033 updateAppWidgetInstanceLocked(id, views); 1034 } 1035 } 1036 } 1037 } 1038 1039 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) { 1040 updateAppWidgetInstanceLocked(id, views, false); 1041 } 1042 1043 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) { 1044 // allow for stale appWidgetIds and other badness 1045 // lookup also checks that the calling process can access the appWidgetId 1046 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) 1047 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { 1048 1049 if (!isPartialUpdate) { 1050 // For a full update we replace the RemoteViews completely. 1051 id.views = views; 1052 } else { 1053 // For a partial update, we merge the new RemoteViews with the old. 1054 id.views.mergeRemoteViews(views); 1055 } 1056 1057 // is anyone listening? 1058 if (id.host.callbacks != null) { 1059 try { 1060 // the lock is held, but this is a oneway call 1061 id.host.callbacks.updateAppWidget(id.appWidgetId, views); 1062 } catch (RemoteException e) { 1063 // It failed; remove the callback. No need to prune because 1064 // we know that this host is still referenced by this instance. 1065 id.host.callbacks = null; 1066 } 1067 } 1068 } 1069 } 1070 1071 void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId) { 1072 // allow for stale appWidgetIds and other badness 1073 // lookup also checks that the calling process can access the appWidgetId 1074 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) 1075 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { 1076 // is anyone listening? 1077 if (id.host.callbacks != null) { 1078 try { 1079 // the lock is held, but this is a oneway call 1080 id.host.callbacks.viewDataChanged(id.appWidgetId, viewId); 1081 } catch (RemoteException e) { 1082 // It failed; remove the callback. No need to prune because 1083 // we know that this host is still referenced by this instance. 1084 id.host.callbacks = null; 1085 } 1086 } 1087 1088 // If the host is unavailable, then we call the associated 1089 // RemoteViewsFactory.onDataSetChanged() directly 1090 if (id.host.callbacks == null) { 1091 Set<FilterComparison> keys = mRemoteViewsServicesAppWidgets.keySet(); 1092 for (FilterComparison key : keys) { 1093 if (mRemoteViewsServicesAppWidgets.get(key).contains(id.appWidgetId)) { 1094 Intent intent = key.getIntent(); 1095 1096 final ServiceConnection conn = new ServiceConnection() { 1097 @Override 1098 public void onServiceConnected(ComponentName name, IBinder service) { 1099 IRemoteViewsFactory cb = IRemoteViewsFactory.Stub 1100 .asInterface(service); 1101 try { 1102 cb.onDataSetChangedAsync(); 1103 } catch (RemoteException e) { 1104 e.printStackTrace(); 1105 } catch (RuntimeException e) { 1106 e.printStackTrace(); 1107 } 1108 mContext.unbindService(this); 1109 } 1110 1111 @Override 1112 public void onServiceDisconnected(android.content.ComponentName name) { 1113 // Do nothing 1114 } 1115 }; 1116 1117 int userId = UserHandle.getUserId(id.provider.uid); 1118 // Bind to the service and call onDataSetChanged() 1119 final long token = Binder.clearCallingIdentity(); 1120 try { 1121 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId); 1122 } finally { 1123 Binder.restoreCallingIdentity(token); 1124 } 1125 } 1126 } 1127 } 1128 } 1129 } 1130 1131 private boolean isLocalBinder() { 1132 return Process.myPid() == Binder.getCallingPid(); 1133 } 1134 1135 private RemoteViews cloneIfLocalBinder(RemoteViews rv) { 1136 if (isLocalBinder() && rv != null) { 1137 return rv.clone(); 1138 } 1139 return rv; 1140 } 1141 1142 private AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) { 1143 if (isLocalBinder() && info != null) { 1144 return info.clone(); 1145 } 1146 return info; 1147 } 1148 1149 private Bundle cloneIfLocalBinder(Bundle bundle) { 1150 // Note: this is only a shallow copy. For now this will be fine, but it could be problematic 1151 // if we start adding objects to the options. Further, it would only be an issue if keyguard 1152 // used such options. 1153 if (isLocalBinder() && bundle != null) { 1154 return (Bundle) bundle.clone(); 1155 } 1156 return bundle; 1157 } 1158 1159 public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId, 1160 List<RemoteViews> updatedViews) { 1161 int callingUid = enforceCallingUid(packageName); 1162 synchronized (mAppWidgetIds) { 1163 ensureStateLoadedLocked(); 1164 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); 1165 host.callbacks = callbacks; 1166 1167 updatedViews.clear(); 1168 1169 ArrayList<AppWidgetId> instances = host.instances; 1170 int N = instances.size(); 1171 int[] updatedIds = new int[N]; 1172 for (int i = 0; i < N; i++) { 1173 AppWidgetId id = instances.get(i); 1174 updatedIds[i] = id.appWidgetId; 1175 updatedViews.add(cloneIfLocalBinder(id.views)); 1176 } 1177 return updatedIds; 1178 } 1179 } 1180 1181 public void stopListening(int hostId) { 1182 synchronized (mAppWidgetIds) { 1183 ensureStateLoadedLocked(); 1184 Host host = lookupHostLocked(Binder.getCallingUid(), hostId); 1185 if (host != null) { 1186 host.callbacks = null; 1187 pruneHostLocked(host); 1188 } 1189 } 1190 } 1191 1192 boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) { 1193 if (id.host.uid == callingUid) { 1194 // Apps hosting the AppWidget have access to it. 1195 return true; 1196 } 1197 if (id.provider != null && id.provider.uid == callingUid) { 1198 // Apps providing the AppWidget have access to it (if the appWidgetId has been bound) 1199 return true; 1200 } 1201 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET) == PackageManager.PERMISSION_GRANTED) { 1202 // Apps that can bind have access to all appWidgetIds. 1203 return true; 1204 } 1205 // Nobody else can access it. 1206 return false; 1207 } 1208 1209 AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) { 1210 int callingUid = Binder.getCallingUid(); 1211 final int N = mAppWidgetIds.size(); 1212 for (int i = 0; i < N; i++) { 1213 AppWidgetId id = mAppWidgetIds.get(i); 1214 if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) { 1215 return id; 1216 } 1217 } 1218 return null; 1219 } 1220 1221 Provider lookupProviderLocked(ComponentName provider) { 1222 final int N = mInstalledProviders.size(); 1223 for (int i = 0; i < N; i++) { 1224 Provider p = mInstalledProviders.get(i); 1225 if (p.info.provider.equals(provider)) { 1226 return p; 1227 } 1228 } 1229 return null; 1230 } 1231 1232 Host lookupHostLocked(int uid, int hostId) { 1233 final int N = mHosts.size(); 1234 for (int i = 0; i < N; i++) { 1235 Host h = mHosts.get(i); 1236 if (h.uid == uid && h.hostId == hostId) { 1237 return h; 1238 } 1239 } 1240 return null; 1241 } 1242 1243 Host lookupOrAddHostLocked(int uid, String packageName, int hostId) { 1244 final int N = mHosts.size(); 1245 for (int i = 0; i < N; i++) { 1246 Host h = mHosts.get(i); 1247 if (h.hostId == hostId && h.packageName.equals(packageName)) { 1248 return h; 1249 } 1250 } 1251 Host host = new Host(); 1252 host.packageName = packageName; 1253 host.uid = uid; 1254 host.hostId = hostId; 1255 mHosts.add(host); 1256 return host; 1257 } 1258 1259 void pruneHostLocked(Host host) { 1260 if (host.instances.size() == 0 && host.callbacks == null) { 1261 mHosts.remove(host); 1262 } 1263 } 1264 1265 void loadAppWidgetListLocked() { 1266 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1267 try { 1268 List<ResolveInfo> broadcastReceivers = mPm.queryIntentReceivers(intent, 1269 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 1270 PackageManager.GET_META_DATA, mUserId); 1271 1272 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1273 for (int i = 0; i < N; i++) { 1274 ResolveInfo ri = broadcastReceivers.get(i); 1275 addProviderLocked(ri); 1276 } 1277 } catch (RemoteException re) { 1278 // Shouldn't happen, local call 1279 } 1280 } 1281 1282 boolean addProviderLocked(ResolveInfo ri) { 1283 if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1284 return false; 1285 } 1286 if (!ri.activityInfo.isEnabled()) { 1287 return false; 1288 } 1289 Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName, 1290 ri.activityInfo.name), ri); 1291 if (p != null) { 1292 mInstalledProviders.add(p); 1293 return true; 1294 } else { 1295 return false; 1296 } 1297 } 1298 1299 void removeProviderLocked(int index, Provider p) { 1300 int N = p.instances.size(); 1301 for (int i = 0; i < N; i++) { 1302 AppWidgetId id = p.instances.get(i); 1303 // Call back with empty RemoteViews 1304 updateAppWidgetInstanceLocked(id, null); 1305 // Stop telling the host about updates for this from now on 1306 cancelBroadcasts(p); 1307 // clear out references to this appWidgetId 1308 id.host.instances.remove(id); 1309 mAppWidgetIds.remove(id); 1310 id.provider = null; 1311 pruneHostLocked(id.host); 1312 id.host = null; 1313 } 1314 p.instances.clear(); 1315 mInstalledProviders.remove(index); 1316 mDeletedProviders.add(p); 1317 // no need to send the DISABLE broadcast, since the receiver is gone anyway 1318 cancelBroadcasts(p); 1319 } 1320 1321 void sendEnableIntentLocked(Provider p) { 1322 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); 1323 intent.setComponent(p.info.provider); 1324 mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); 1325 } 1326 1327 void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) { 1328 if (appWidgetIds != null && appWidgetIds.length > 0) { 1329 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1330 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 1331 intent.setComponent(p.info.provider); 1332 mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId)); 1333 } 1334 } 1335 1336 void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) { 1337 if (p.info.updatePeriodMillis > 0) { 1338 // if this is the first instance, set the alarm. otherwise, 1339 // rely on the fact that we've already set it and that 1340 // PendingIntent.getBroadcast will update the extras. 1341 boolean alreadyRegistered = p.broadcast != null; 1342 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1343 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 1344 intent.setComponent(p.info.provider); 1345 long token = Binder.clearCallingIdentity(); 1346 try { 1347 p.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent, 1348 PendingIntent.FLAG_UPDATE_CURRENT, new UserHandle(mUserId)); 1349 } finally { 1350 Binder.restoreCallingIdentity(token); 1351 } 1352 if (!alreadyRegistered) { 1353 long period = p.info.updatePeriodMillis; 1354 if (period < MIN_UPDATE_PERIOD) { 1355 period = MIN_UPDATE_PERIOD; 1356 } 1357 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock 1358 .elapsedRealtime() 1359 + period, period, p.broadcast); 1360 } 1361 } 1362 } 1363 1364 static int[] getAppWidgetIds(Provider p) { 1365 int instancesSize = p.instances.size(); 1366 int appWidgetIds[] = new int[instancesSize]; 1367 for (int i = 0; i < instancesSize; i++) { 1368 appWidgetIds[i] = p.instances.get(i).appWidgetId; 1369 } 1370 return appWidgetIds; 1371 } 1372 1373 public int[] getAppWidgetIds(ComponentName provider) { 1374 synchronized (mAppWidgetIds) { 1375 ensureStateLoadedLocked(); 1376 Provider p = lookupProviderLocked(provider); 1377 if (p != null && Binder.getCallingUid() == p.uid) { 1378 return getAppWidgetIds(p); 1379 } else { 1380 return new int[0]; 1381 } 1382 } 1383 } 1384 1385 static int[] getAppWidgetIds(Host h) { 1386 int instancesSize = h.instances.size(); 1387 int appWidgetIds[] = new int[instancesSize]; 1388 for (int i = 0; i < instancesSize; i++) { 1389 appWidgetIds[i] = h.instances.get(i).appWidgetId; 1390 } 1391 return appWidgetIds; 1392 } 1393 1394 public int[] getAppWidgetIdsForHost(int hostId) { 1395 synchronized (mAppWidgetIds) { 1396 ensureStateLoadedLocked(); 1397 int callingUid = Binder.getCallingUid(); 1398 Host host = lookupHostLocked(callingUid, hostId); 1399 if (host != null) { 1400 return getAppWidgetIds(host); 1401 } else { 1402 return new int[0]; 1403 } 1404 } 1405 } 1406 1407 private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) { 1408 Provider p = null; 1409 1410 ActivityInfo activityInfo = ri.activityInfo; 1411 XmlResourceParser parser = null; 1412 try { 1413 parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(), 1414 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); 1415 if (parser == null) { 1416 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER 1417 + " meta-data for " + "AppWidget provider '" + component + '\''); 1418 return null; 1419 } 1420 1421 AttributeSet attrs = Xml.asAttributeSet(parser); 1422 1423 int type; 1424 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1425 && type != XmlPullParser.START_TAG) { 1426 // drain whitespace, comments, etc. 1427 } 1428 1429 String nodeName = parser.getName(); 1430 if (!"appwidget-provider".equals(nodeName)) { 1431 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for" 1432 + " AppWidget provider '" + component + '\''); 1433 return null; 1434 } 1435 1436 p = new Provider(); 1437 AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo(); 1438 info.provider = component; 1439 p.uid = activityInfo.applicationInfo.uid; 1440 1441 Resources res = mContext.getPackageManager() 1442 .getResourcesForApplicationAsUser(activityInfo.packageName, mUserId); 1443 1444 TypedArray sa = res.obtainAttributes(attrs, 1445 com.android.internal.R.styleable.AppWidgetProviderInfo); 1446 1447 // These dimensions has to be resolved in the application's context. 1448 // We simply send back the raw complex data, which will be 1449 // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}. 1450 TypedValue value = sa 1451 .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth); 1452 info.minWidth = value != null ? value.data : 0; 1453 value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight); 1454 info.minHeight = value != null ? value.data : 0; 1455 value = sa.peekValue( 1456 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth); 1457 info.minResizeWidth = value != null ? value.data : info.minWidth; 1458 value = sa.peekValue( 1459 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight); 1460 info.minResizeHeight = value != null ? value.data : info.minHeight; 1461 info.updatePeriodMillis = sa.getInt( 1462 com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0); 1463 info.initialLayout = sa.getResourceId( 1464 com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0); 1465 info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable. 1466 AppWidgetProviderInfo_initialKeyguardLayout, 0); 1467 String className = sa 1468 .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure); 1469 if (className != null) { 1470 info.configure = new ComponentName(component.getPackageName(), className); 1471 } 1472 info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString(); 1473 info.icon = ri.getIconResource(); 1474 info.previewImage = sa.getResourceId( 1475 com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); 1476 info.autoAdvanceViewId = sa.getResourceId( 1477 com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1); 1478 info.resizeMode = sa.getInt( 1479 com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode, 1480 AppWidgetProviderInfo.RESIZE_NONE); 1481 info.widgetCategory = sa.getInt( 1482 com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory, 1483 AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); 1484 1485 sa.recycle(); 1486 } catch (Exception e) { 1487 // Ok to catch Exception here, because anything going wrong because 1488 // of what a client process passes to us should not be fatal for the 1489 // system process. 1490 Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e); 1491 return null; 1492 } finally { 1493 if (parser != null) 1494 parser.close(); 1495 } 1496 return p; 1497 } 1498 1499 int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException { 1500 PackageInfo pkgInfo = null; 1501 try { 1502 pkgInfo = mPm.getPackageInfo(packageName, 0, mUserId); 1503 } catch (RemoteException re) { 1504 // Shouldn't happen, local call 1505 } 1506 if (pkgInfo == null || pkgInfo.applicationInfo == null) { 1507 throw new PackageManager.NameNotFoundException(); 1508 } 1509 return pkgInfo.applicationInfo.uid; 1510 } 1511 1512 int enforceSystemOrCallingUid(String packageName) throws IllegalArgumentException { 1513 int callingUid = Binder.getCallingUid(); 1514 if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID || callingUid == 0) { 1515 return callingUid; 1516 } 1517 return enforceCallingUid(packageName); 1518 } 1519 1520 int enforceCallingUid(String packageName) throws IllegalArgumentException { 1521 int callingUid = Binder.getCallingUid(); 1522 int packageUid; 1523 try { 1524 packageUid = getUidForPackage(packageName); 1525 } catch (PackageManager.NameNotFoundException ex) { 1526 throw new IllegalArgumentException("packageName and uid don't match packageName=" 1527 + packageName); 1528 } 1529 if (!UserHandle.isSameApp(callingUid, packageUid)) { 1530 throw new IllegalArgumentException("packageName and uid don't match packageName=" 1531 + packageName); 1532 } 1533 return callingUid; 1534 } 1535 1536 void sendInitialBroadcasts() { 1537 synchronized (mAppWidgetIds) { 1538 ensureStateLoadedLocked(); 1539 final int N = mInstalledProviders.size(); 1540 for (int i = 0; i < N; i++) { 1541 Provider p = mInstalledProviders.get(i); 1542 if (p.instances.size() > 0) { 1543 sendEnableIntentLocked(p); 1544 int[] appWidgetIds = getAppWidgetIds(p); 1545 sendUpdateIntentLocked(p, appWidgetIds); 1546 registerForBroadcastsLocked(p, appWidgetIds); 1547 } 1548 } 1549 } 1550 } 1551 1552 // only call from initialization -- it assumes that the data structures are all empty 1553 void loadStateLocked() { 1554 AtomicFile file = savedStateFile(); 1555 try { 1556 FileInputStream stream = file.openRead(); 1557 readStateFromFileLocked(stream); 1558 1559 if (stream != null) { 1560 try { 1561 stream.close(); 1562 } catch (IOException e) { 1563 Slog.w(TAG, "Failed to close state FileInputStream " + e); 1564 } 1565 } 1566 } catch (FileNotFoundException e) { 1567 Slog.w(TAG, "Failed to read state: " + e); 1568 } 1569 } 1570 1571 void saveStateLocked() { 1572 AtomicFile file = savedStateFile(); 1573 FileOutputStream stream; 1574 try { 1575 stream = file.startWrite(); 1576 if (writeStateToFileLocked(stream)) { 1577 file.finishWrite(stream); 1578 } else { 1579 file.failWrite(stream); 1580 Slog.w(TAG, "Failed to save state, restoring backup."); 1581 } 1582 } catch (IOException e) { 1583 Slog.w(TAG, "Failed open state file for write: " + e); 1584 } 1585 } 1586 1587 boolean writeStateToFileLocked(FileOutputStream stream) { 1588 int N; 1589 1590 try { 1591 XmlSerializer out = new FastXmlSerializer(); 1592 out.setOutput(stream, "utf-8"); 1593 out.startDocument(null, true); 1594 out.startTag(null, "gs"); 1595 1596 int providerIndex = 0; 1597 N = mInstalledProviders.size(); 1598 for (int i = 0; i < N; i++) { 1599 Provider p = mInstalledProviders.get(i); 1600 if (p.instances.size() > 0) { 1601 out.startTag(null, "p"); 1602 out.attribute(null, "pkg", p.info.provider.getPackageName()); 1603 out.attribute(null, "cl", p.info.provider.getClassName()); 1604 out.endTag(null, "p"); 1605 p.tag = providerIndex; 1606 providerIndex++; 1607 } 1608 } 1609 1610 N = mHosts.size(); 1611 for (int i = 0; i < N; i++) { 1612 Host host = mHosts.get(i); 1613 out.startTag(null, "h"); 1614 out.attribute(null, "pkg", host.packageName); 1615 out.attribute(null, "id", Integer.toHexString(host.hostId)); 1616 out.endTag(null, "h"); 1617 host.tag = i; 1618 } 1619 1620 N = mAppWidgetIds.size(); 1621 for (int i = 0; i < N; i++) { 1622 AppWidgetId id = mAppWidgetIds.get(i); 1623 out.startTag(null, "g"); 1624 out.attribute(null, "id", Integer.toHexString(id.appWidgetId)); 1625 out.attribute(null, "h", Integer.toHexString(id.host.tag)); 1626 if (id.provider != null) { 1627 out.attribute(null, "p", Integer.toHexString(id.provider.tag)); 1628 } 1629 if (id.options != null) { 1630 out.attribute(null, "min_width", Integer.toHexString(id.options.getInt( 1631 AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH))); 1632 out.attribute(null, "min_height", Integer.toHexString(id.options.getInt( 1633 AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT))); 1634 out.attribute(null, "max_width", Integer.toHexString(id.options.getInt( 1635 AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH))); 1636 out.attribute(null, "max_height", Integer.toHexString(id.options.getInt( 1637 AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT))); 1638 out.attribute(null, "host_category", Integer.toHexString(id.options.getInt( 1639 AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))); 1640 } 1641 out.endTag(null, "g"); 1642 } 1643 1644 Iterator<String> it = mPackagesWithBindWidgetPermission.iterator(); 1645 while (it.hasNext()) { 1646 out.startTag(null, "b"); 1647 out.attribute(null, "packageName", it.next()); 1648 out.endTag(null, "b"); 1649 } 1650 1651 out.endTag(null, "gs"); 1652 1653 out.endDocument(); 1654 return true; 1655 } catch (IOException e) { 1656 Slog.w(TAG, "Failed to write state: " + e); 1657 return false; 1658 } 1659 } 1660 1661 @SuppressWarnings("unused") 1662 void readStateFromFileLocked(FileInputStream stream) { 1663 boolean success = false; 1664 try { 1665 XmlPullParser parser = Xml.newPullParser(); 1666 parser.setInput(stream, null); 1667 1668 int type; 1669 int providerIndex = 0; 1670 HashMap<Integer, Provider> loadedProviders = new HashMap<Integer, Provider>(); 1671 do { 1672 type = parser.next(); 1673 if (type == XmlPullParser.START_TAG) { 1674 String tag = parser.getName(); 1675 if ("p".equals(tag)) { 1676 // TODO: do we need to check that this package has the same signature 1677 // as before? 1678 String pkg = parser.getAttributeValue(null, "pkg"); 1679 String cl = parser.getAttributeValue(null, "cl"); 1680 1681 final IPackageManager packageManager = AppGlobals.getPackageManager(); 1682 try { 1683 packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0, mUserId); 1684 } catch (RemoteException e) { 1685 String[] pkgs = mContext.getPackageManager() 1686 .currentToCanonicalPackageNames(new String[] { pkg }); 1687 pkg = pkgs[0]; 1688 } 1689 1690 Provider p = lookupProviderLocked(new ComponentName(pkg, cl)); 1691 if (p == null && mSafeMode) { 1692 // if we're in safe mode, make a temporary one 1693 p = new Provider(); 1694 p.info = new AppWidgetProviderInfo(); 1695 p.info.provider = new ComponentName(pkg, cl); 1696 p.zombie = true; 1697 mInstalledProviders.add(p); 1698 } 1699 if (p != null) { 1700 // if it wasn't uninstalled or something 1701 loadedProviders.put(providerIndex, p); 1702 } 1703 providerIndex++; 1704 } else if ("h".equals(tag)) { 1705 Host host = new Host(); 1706 1707 // TODO: do we need to check that this package has the same signature 1708 // as before? 1709 host.packageName = parser.getAttributeValue(null, "pkg"); 1710 try { 1711 host.uid = getUidForPackage(host.packageName); 1712 } catch (PackageManager.NameNotFoundException ex) { 1713 host.zombie = true; 1714 } 1715 if (!host.zombie || mSafeMode) { 1716 // In safe mode, we don't discard the hosts we don't recognize 1717 // so that they're not pruned from our list. Otherwise, we do. 1718 host.hostId = Integer 1719 .parseInt(parser.getAttributeValue(null, "id"), 16); 1720 mHosts.add(host); 1721 } 1722 } else if ("b".equals(tag)) { 1723 String packageName = parser.getAttributeValue(null, "packageName"); 1724 if (packageName != null) { 1725 mPackagesWithBindWidgetPermission.add(packageName); 1726 } 1727 } else if ("g".equals(tag)) { 1728 AppWidgetId id = new AppWidgetId(); 1729 id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16); 1730 if (id.appWidgetId >= mNextAppWidgetId) { 1731 mNextAppWidgetId = id.appWidgetId + 1; 1732 } 1733 1734 Bundle options = new Bundle(); 1735 String minWidthString = parser.getAttributeValue(null, "min_width"); 1736 if (minWidthString != null) { 1737 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 1738 Integer.parseInt(minWidthString, 16)); 1739 } 1740 String minHeightString = parser.getAttributeValue(null, "min_height"); 1741 if (minHeightString != null) { 1742 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 1743 Integer.parseInt(minHeightString, 16)); 1744 } 1745 String maxWidthString = parser.getAttributeValue(null, "max_width"); 1746 if (maxWidthString != null) { 1747 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 1748 Integer.parseInt(maxWidthString, 16)); 1749 } 1750 String maxHeightString = parser.getAttributeValue(null, "max_height"); 1751 if (maxHeightString != null) { 1752 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 1753 Integer.parseInt(maxHeightString, 16)); 1754 } 1755 String categoryString = parser.getAttributeValue(null, "host_category"); 1756 if (categoryString != null) { 1757 options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 1758 Integer.parseInt(categoryString, 16)); 1759 } 1760 id.options = options; 1761 1762 String providerString = parser.getAttributeValue(null, "p"); 1763 if (providerString != null) { 1764 // there's no provider if it hasn't been bound yet. 1765 // maybe we don't have to save this, but it brings the system 1766 // to the state it was in. 1767 int pIndex = Integer.parseInt(providerString, 16); 1768 id.provider = loadedProviders.get(pIndex); 1769 if (false) { 1770 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider " 1771 + pIndex + " which is " + id.provider); 1772 } 1773 if (id.provider == null) { 1774 // This provider is gone. We just let the host figure out 1775 // that this happened when it fails to load it. 1776 continue; 1777 } 1778 } 1779 1780 int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16); 1781 id.host = mHosts.get(hIndex); 1782 if (id.host == null) { 1783 // This host is gone. 1784 continue; 1785 } 1786 1787 if (id.provider != null) { 1788 id.provider.instances.add(id); 1789 } 1790 id.host.instances.add(id); 1791 mAppWidgetIds.add(id); 1792 } 1793 } 1794 } while (type != XmlPullParser.END_DOCUMENT); 1795 success = true; 1796 } catch (NullPointerException e) { 1797 Slog.w(TAG, "failed parsing " + e); 1798 } catch (NumberFormatException e) { 1799 Slog.w(TAG, "failed parsing " + e); 1800 } catch (XmlPullParserException e) { 1801 Slog.w(TAG, "failed parsing " + e); 1802 } catch (IOException e) { 1803 Slog.w(TAG, "failed parsing " + e); 1804 } catch (IndexOutOfBoundsException e) { 1805 Slog.w(TAG, "failed parsing " + e); 1806 } 1807 1808 if (success) { 1809 // delete any hosts that didn't manage to get connected (should happen) 1810 // if it matters, they'll be reconnected. 1811 for (int i = mHosts.size() - 1; i >= 0; i--) { 1812 pruneHostLocked(mHosts.get(i)); 1813 } 1814 } else { 1815 // failed reading, clean up 1816 Slog.w(TAG, "Failed to read state, clearing widgets and hosts."); 1817 1818 mAppWidgetIds.clear(); 1819 mHosts.clear(); 1820 final int N = mInstalledProviders.size(); 1821 for (int i = 0; i < N; i++) { 1822 mInstalledProviders.get(i).instances.clear(); 1823 } 1824 } 1825 } 1826 1827 static File getSettingsFile(int userId) { 1828 return new File(Environment.getUserSystemDirectory(userId), SETTINGS_FILENAME); 1829 } 1830 1831 AtomicFile savedStateFile() { 1832 File dir = Environment.getUserSystemDirectory(mUserId); 1833 File settingsFile = getSettingsFile(mUserId); 1834 if (!settingsFile.exists() && mUserId == 0) { 1835 if (!dir.exists()) { 1836 dir.mkdirs(); 1837 } 1838 // Migrate old data 1839 File oldFile = new File("/data/system/" + SETTINGS_FILENAME); 1840 // Method doesn't throw an exception on failure. Ignore any errors 1841 // in moving the file (like non-existence) 1842 oldFile.renameTo(settingsFile); 1843 } 1844 return new AtomicFile(settingsFile); 1845 } 1846 1847 void onUserStopping() { 1848 // prune the ones we don't want to keep 1849 int N = mInstalledProviders.size(); 1850 for (int i = N - 1; i >= 0; i--) { 1851 Provider p = mInstalledProviders.get(i); 1852 cancelBroadcasts(p); 1853 } 1854 } 1855 1856 void onUserRemoved() { 1857 getSettingsFile(mUserId).delete(); 1858 } 1859 1860 boolean addProvidersForPackageLocked(String pkgName) { 1861 boolean providersAdded = false; 1862 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1863 intent.setPackage(pkgName); 1864 List<ResolveInfo> broadcastReceivers; 1865 try { 1866 broadcastReceivers = mPm.queryIntentReceivers(intent, 1867 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 1868 PackageManager.GET_META_DATA, mUserId); 1869 } catch (RemoteException re) { 1870 // Shouldn't happen, local call 1871 return false; 1872 } 1873 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1874 for (int i = 0; i < N; i++) { 1875 ResolveInfo ri = broadcastReceivers.get(i); 1876 ActivityInfo ai = ri.activityInfo; 1877 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1878 continue; 1879 } 1880 if (pkgName.equals(ai.packageName)) { 1881 addProviderLocked(ri); 1882 providersAdded = true; 1883 } 1884 } 1885 1886 return providersAdded; 1887 } 1888 1889 /** 1890 * Updates all providers with the specified package names, and records any providers that were 1891 * pruned. 1892 * 1893 * @return whether any providers were updated 1894 */ 1895 boolean updateProvidersForPackageLocked(String pkgName, Set<ComponentName> removedProviders) { 1896 boolean providersUpdated = false; 1897 HashSet<String> keep = new HashSet<String>(); 1898 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1899 intent.setPackage(pkgName); 1900 List<ResolveInfo> broadcastReceivers; 1901 try { 1902 broadcastReceivers = mPm.queryIntentReceivers(intent, 1903 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 1904 PackageManager.GET_META_DATA, mUserId); 1905 } catch (RemoteException re) { 1906 // Shouldn't happen, local call 1907 return false; 1908 } 1909 1910 // add the missing ones and collect which ones to keep 1911 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1912 for (int i = 0; i < N; i++) { 1913 ResolveInfo ri = broadcastReceivers.get(i); 1914 ActivityInfo ai = ri.activityInfo; 1915 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1916 continue; 1917 } 1918 if (pkgName.equals(ai.packageName)) { 1919 ComponentName component = new ComponentName(ai.packageName, ai.name); 1920 Provider p = lookupProviderLocked(component); 1921 if (p == null) { 1922 if (addProviderLocked(ri)) { 1923 keep.add(ai.name); 1924 providersUpdated = true; 1925 } 1926 } else { 1927 Provider parsed = parseProviderInfoXml(component, ri); 1928 if (parsed != null) { 1929 keep.add(ai.name); 1930 // Use the new AppWidgetProviderInfo. 1931 p.info = parsed.info; 1932 // If it's enabled 1933 final int M = p.instances.size(); 1934 if (M > 0) { 1935 int[] appWidgetIds = getAppWidgetIds(p); 1936 // Reschedule for the new updatePeriodMillis (don't worry about handling 1937 // it specially if updatePeriodMillis didn't change because we just sent 1938 // an update, and the next one will be updatePeriodMillis from now). 1939 cancelBroadcasts(p); 1940 registerForBroadcastsLocked(p, appWidgetIds); 1941 // If it's currently showing, call back with the new 1942 // AppWidgetProviderInfo. 1943 for (int j = 0; j < M; j++) { 1944 AppWidgetId id = p.instances.get(j); 1945 id.views = null; 1946 if (id.host != null && id.host.callbacks != null) { 1947 try { 1948 id.host.callbacks.providerChanged(id.appWidgetId, p.info); 1949 } catch (RemoteException ex) { 1950 // It failed; remove the callback. No need to prune because 1951 // we know that this host is still referenced by this 1952 // instance. 1953 id.host.callbacks = null; 1954 } 1955 } 1956 } 1957 // Now that we've told the host, push out an update. 1958 sendUpdateIntentLocked(p, appWidgetIds); 1959 providersUpdated = true; 1960 } 1961 } 1962 } 1963 } 1964 } 1965 1966 // prune the ones we don't want to keep 1967 N = mInstalledProviders.size(); 1968 for (int i = N - 1; i >= 0; i--) { 1969 Provider p = mInstalledProviders.get(i); 1970 if (pkgName.equals(p.info.provider.getPackageName()) 1971 && !keep.contains(p.info.provider.getClassName())) { 1972 if (removedProviders != null) { 1973 removedProviders.add(p.info.provider); 1974 } 1975 removeProviderLocked(i, p); 1976 providersUpdated = true; 1977 } 1978 } 1979 1980 return providersUpdated; 1981 } 1982 1983 boolean removeProvidersForPackageLocked(String pkgName) { 1984 boolean providersRemoved = false; 1985 int N = mInstalledProviders.size(); 1986 for (int i = N - 1; i >= 0; i--) { 1987 Provider p = mInstalledProviders.get(i); 1988 if (pkgName.equals(p.info.provider.getPackageName())) { 1989 removeProviderLocked(i, p); 1990 providersRemoved = true; 1991 } 1992 } 1993 1994 // Delete the hosts for this package too 1995 // 1996 // By now, we have removed any AppWidgets that were in any hosts here, 1997 // so we don't need to worry about sending DISABLE broadcasts to them. 1998 N = mHosts.size(); 1999 for (int i = N - 1; i >= 0; i--) { 2000 Host host = mHosts.get(i); 2001 if (pkgName.equals(host.packageName)) { 2002 deleteHostLocked(host); 2003 } 2004 } 2005 2006 return providersRemoved; 2007 } 2008 2009 void notifyHostsForProvidersChangedLocked() { 2010 final int N = mHosts.size(); 2011 for (int i = N - 1; i >= 0; i--) { 2012 Host host = mHosts.get(i); 2013 try { 2014 if (host.callbacks != null) { 2015 host.callbacks.providersChanged(); 2016 } 2017 } catch (RemoteException ex) { 2018 // It failed; remove the callback. No need to prune because 2019 // we know that this host is still referenced by this 2020 // instance. 2021 host.callbacks = null; 2022 } 2023 } 2024 } 2025} 2026