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