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