1 /* 2 * Copyright (C) 2007 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.PendingIntent; 21 import android.appwidget.AppWidgetManager; 22 import android.appwidget.AppWidgetProviderInfo; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.ServiceConnection; 29 import android.content.Intent.FilterComparison; 30 import android.content.pm.ActivityInfo; 31 import android.content.pm.ApplicationInfo; 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.net.Uri; 40 import android.os.Binder; 41 import android.os.Bundle; 42 import android.os.IBinder; 43 import android.os.RemoteException; 44 import android.os.SystemClock; 45 import android.util.AttributeSet; 46 import android.util.Log; 47 import android.util.Pair; 48 import android.util.Slog; 49 import android.util.TypedValue; 50 import android.util.Xml; 51 import android.widget.RemoteViews; 52 53 import com.android.internal.appwidget.IAppWidgetHost; 54 import com.android.internal.appwidget.IAppWidgetService; 55 import com.android.internal.os.AtomicFile; 56 import com.android.internal.util.FastXmlSerializer; 57 import com.android.internal.widget.IRemoteViewsAdapterConnection; 58 import com.android.internal.widget.IRemoteViewsFactory; 59 60 import org.xmlpull.v1.XmlPullParser; 61 import org.xmlpull.v1.XmlPullParserException; 62 import org.xmlpull.v1.XmlSerializer; 63 64 import java.io.File; 65 import java.io.FileDescriptor; 66 import java.io.FileInputStream; 67 import java.io.FileNotFoundException; 68 import java.io.FileOutputStream; 69 import java.io.IOException; 70 import java.io.PrintWriter; 71 import java.util.ArrayList; 72 import java.util.HashMap; 73 import java.util.HashSet; 74 import java.util.Iterator; 75 import java.util.List; 76 import java.util.Locale; 77 78 class AppWidgetService extends IAppWidgetService.Stub 79 { 80 private static final String TAG = "AppWidgetService"; 81 82 private static final String SETTINGS_FILENAME = "appwidgets.xml"; 83 private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes 84 85 /* 86 * When identifying a Host or Provider based on the calling process, use the uid field. 87 * When identifying a Host or Provider based on a package manager broadcast, use the 88 * package given. 89 */ 90 91 static class Provider { 92 int uid; 93 AppWidgetProviderInfo info; 94 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>(); 95 PendingIntent broadcast; 96 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 97 98 int tag; // for use while saving state (the index) 99 } 100 101 static class Host { 102 int uid; 103 int hostId; 104 String packageName; 105 ArrayList<AppWidgetId> instances = new ArrayList<AppWidgetId>(); 106 IAppWidgetHost callbacks; 107 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 108 109 int tag; // for use while saving state (the index) 110 } 111 112 static class AppWidgetId { 113 int appWidgetId; 114 Provider provider; 115 RemoteViews views; 116 Host host; 117 } 118 119 /** 120 * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. 121 * This needs to be a static inner class since a reference to the ServiceConnection is held 122 * globally and may lead us to leak AppWidgetService instances (if there were more than one). 123 */ 124 static class ServiceConnectionProxy implements ServiceConnection { 125 private final Pair<Integer, Intent.FilterComparison> mKey; 126 private final IBinder mConnectionCb; 127 128 ServiceConnectionProxy(Pair<Integer, Intent.FilterComparison> key, IBinder connectionCb) { 129 mKey = key; 130 mConnectionCb = connectionCb; 131 } 132 public void onServiceConnected(ComponentName name, IBinder service) { 133 final IRemoteViewsAdapterConnection cb = 134 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb); 135 try { 136 cb.onServiceConnected(service); 137 } catch (Exception e) { 138 e.printStackTrace(); 139 } 140 } 141 public void onServiceDisconnected(ComponentName name) { 142 disconnect(); 143 } 144 public void disconnect() { 145 final IRemoteViewsAdapterConnection cb = 146 IRemoteViewsAdapterConnection.Stub.asInterface(mConnectionCb); 147 try { 148 cb.onServiceDisconnected(); 149 } catch (Exception e) { 150 e.printStackTrace(); 151 } 152 } 153 } 154 155 // Manages active connections to RemoteViewsServices 156 private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection> 157 mBoundRemoteViewsServices = new HashMap<Pair<Integer,FilterComparison>,ServiceConnection>(); 158 // Manages persistent references to RemoteViewsServices from different App Widgets 159 private final HashMap<FilterComparison, HashSet<Integer>> 160 mRemoteViewsServicesAppWidgets = new HashMap<FilterComparison, HashSet<Integer>>(); 161 162 Context mContext; 163 Locale mLocale; 164 PackageManager mPackageManager; 165 AlarmManager mAlarmManager; 166 ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>(); 167 int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1; 168 final ArrayList<AppWidgetId> mAppWidgetIds = new ArrayList<AppWidgetId>(); 169 ArrayList<Host> mHosts = new ArrayList<Host>(); 170 boolean mSafeMode; 171 boolean mStateLoaded; 172 173 // These are for debugging only -- widgets are going missing in some rare instances 174 ArrayList<Provider> mDeletedProviders = new ArrayList<Provider>(); 175 ArrayList<Host> mDeletedHosts = new ArrayList<Host>(); 176 177 AppWidgetService(Context context) { 178 mContext = context; 179 mPackageManager = context.getPackageManager(); 180 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 181 } 182 183 public void systemReady(boolean safeMode) { 184 mSafeMode = safeMode; 185 186 synchronized (mAppWidgetIds) { 187 ensureStateLoadedLocked(); 188 } 189 190 // Register for the boot completed broadcast, so we can send the 191 // ENABLE broacasts. If we try to send them now, they time out, 192 // because the system isn't ready to handle them yet. 193 mContext.registerReceiver(mBroadcastReceiver, 194 new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 195 196 // Register for configuration changes so we can update the names 197 // of the widgets when the locale changes. 198 mContext.registerReceiver(mBroadcastReceiver, 199 new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null); 200 201 // Register for broadcasts about package install, etc., so we can 202 // update the provider list. 203 IntentFilter filter = new IntentFilter(); 204 filter.addAction(Intent.ACTION_PACKAGE_ADDED); 205 filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 206 filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 207 filter.addDataScheme("package"); 208 mContext.registerReceiver(mBroadcastReceiver, filter); 209 // Register for events related to sdcard installation. 210 IntentFilter sdFilter = new IntentFilter(); 211 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 212 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 213 mContext.registerReceiver(mBroadcastReceiver, sdFilter); 214 } 215 216 private void ensureStateLoadedLocked() { 217 if (!mStateLoaded) { 218 loadAppWidgetList(); 219 loadStateLocked(); 220 mStateLoaded = true; 221 } 222 } 223 224 private void dumpProvider(Provider p, int index, PrintWriter pw) { 225 AppWidgetProviderInfo info = p.info; 226 pw.print(" ["); pw.print(index); pw.print("] provider "); 227 pw.print(info.provider.flattenToShortString()); 228 pw.println(':'); 229 pw.print(" min=("); pw.print(info.minWidth); 230 pw.print("x"); pw.print(info.minHeight); 231 pw.print(") minResize=("); pw.print(info.minResizeWidth); 232 pw.print("x"); pw.print(info.minResizeHeight); 233 pw.print(") updatePeriodMillis="); 234 pw.print(info.updatePeriodMillis); 235 pw.print(" resizeMode="); 236 pw.print(info.resizeMode); 237 pw.print(" autoAdvanceViewId="); 238 pw.print(info.autoAdvanceViewId); 239 pw.print(" initialLayout=#"); 240 pw.print(Integer.toHexString(info.initialLayout)); 241 pw.print(" zombie="); pw.println(p.zombie); 242 } 243 244 private void dumpHost(Host host, int index, PrintWriter pw) { 245 pw.print(" ["); pw.print(index); pw.print("] hostId="); 246 pw.print(host.hostId); pw.print(' '); 247 pw.print(host.packageName); pw.print('/'); 248 pw.print(host.uid); pw.println(':'); 249 pw.print(" callbacks="); pw.println(host.callbacks); 250 pw.print(" instances.size="); pw.print(host.instances.size()); 251 pw.print(" zombie="); pw.println(host.zombie); 252 } 253 254 private void dumpAppWidgetId(AppWidgetId id, int index, PrintWriter pw) { 255 pw.print(" ["); pw.print(index); pw.print("] id="); 256 pw.println(id.appWidgetId); 257 pw.print(" hostId="); 258 pw.print(id.host.hostId); pw.print(' '); 259 pw.print(id.host.packageName); pw.print('/'); 260 pw.println(id.host.uid); 261 if (id.provider != null) { 262 pw.print(" provider="); 263 pw.println(id.provider.info.provider.flattenToShortString()); 264 } 265 if (id.host != null) { 266 pw.print(" host.callbacks="); pw.println(id.host.callbacks); 267 } 268 if (id.views != null) { 269 pw.print(" views="); pw.println(id.views); 270 } 271 } 272 273 @Override 274 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 275 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 276 != PackageManager.PERMISSION_GRANTED) { 277 pw.println("Permission Denial: can't dump from from pid=" 278 + Binder.getCallingPid() 279 + ", uid=" + Binder.getCallingUid()); 280 return; 281 } 282 283 synchronized (mAppWidgetIds) { 284 int N = mInstalledProviders.size(); 285 pw.println("Providers:"); 286 for (int i=0; i<N; i++) { 287 dumpProvider(mInstalledProviders.get(i), i, pw); 288 } 289 290 N = mAppWidgetIds.size(); 291 pw.println(" "); 292 pw.println("AppWidgetIds:"); 293 for (int i=0; i<N; i++) { 294 dumpAppWidgetId(mAppWidgetIds.get(i), i, pw); 295 } 296 297 N = mHosts.size(); 298 pw.println(" "); 299 pw.println("Hosts:"); 300 for (int i=0; i<N; i++) { 301 dumpHost(mHosts.get(i), i, pw); 302 } 303 304 N = mDeletedProviders.size(); 305 pw.println(" "); 306 pw.println("Deleted Providers:"); 307 for (int i=0; i<N; i++) { 308 dumpProvider(mDeletedProviders.get(i), i, pw); 309 } 310 311 N = mDeletedHosts.size(); 312 pw.println(" "); 313 pw.println("Deleted Hosts:"); 314 for (int i=0; i<N; i++) { 315 dumpHost(mDeletedHosts.get(i), i, pw); 316 } 317 } 318 } 319 320 public int allocateAppWidgetId(String packageName, int hostId) { 321 int callingUid = enforceCallingUid(packageName); 322 synchronized (mAppWidgetIds) { 323 ensureStateLoadedLocked(); 324 int appWidgetId = mNextAppWidgetId++; 325 326 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); 327 328 AppWidgetId id = new AppWidgetId(); 329 id.appWidgetId = appWidgetId; 330 id.host = host; 331 332 host.instances.add(id); 333 mAppWidgetIds.add(id); 334 335 saveStateLocked(); 336 337 return appWidgetId; 338 } 339 } 340 341 public void deleteAppWidgetId(int appWidgetId) { 342 synchronized (mAppWidgetIds) { 343 ensureStateLoadedLocked(); 344 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 345 if (id != null) { 346 deleteAppWidgetLocked(id); 347 saveStateLocked(); 348 } 349 } 350 } 351 352 public void deleteHost(int hostId) { 353 synchronized (mAppWidgetIds) { 354 ensureStateLoadedLocked(); 355 int callingUid = getCallingUid(); 356 Host host = lookupHostLocked(callingUid, hostId); 357 if (host != null) { 358 deleteHostLocked(host); 359 saveStateLocked(); 360 } 361 } 362 } 363 364 public void deleteAllHosts() { 365 synchronized (mAppWidgetIds) { 366 ensureStateLoadedLocked(); 367 int callingUid = getCallingUid(); 368 final int N = mHosts.size(); 369 boolean changed = false; 370 for (int i=N-1; i>=0; i--) { 371 Host host = mHosts.get(i); 372 if (host.uid == callingUid) { 373 deleteHostLocked(host); 374 changed = true; 375 } 376 } 377 if (changed) { 378 saveStateLocked(); 379 } 380 } 381 } 382 383 void deleteHostLocked(Host host) { 384 final int N = host.instances.size(); 385 for (int i=N-1; i>=0; i--) { 386 AppWidgetId id = host.instances.get(i); 387 deleteAppWidgetLocked(id); 388 } 389 host.instances.clear(); 390 mHosts.remove(host); 391 mDeletedHosts.add(host); 392 // it's gone or going away, abruptly drop the callback connection 393 host.callbacks = null; 394 } 395 396 void deleteAppWidgetLocked(AppWidgetId id) { 397 // We first unbind all services that are bound to this id 398 unbindAppWidgetRemoteViewsServicesLocked(id); 399 400 Host host = id.host; 401 host.instances.remove(id); 402 pruneHostLocked(host); 403 404 mAppWidgetIds.remove(id); 405 406 Provider p = id.provider; 407 if (p != null) { 408 p.instances.remove(id); 409 if (!p.zombie) { 410 // send the broacast saying that this appWidgetId has been deleted 411 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); 412 intent.setComponent(p.info.provider); 413 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); 414 mContext.sendBroadcast(intent); 415 if (p.instances.size() == 0) { 416 // cancel the future updates 417 cancelBroadcasts(p); 418 419 // send the broacast saying that the provider is not in use any more 420 intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); 421 intent.setComponent(p.info.provider); 422 mContext.sendBroadcast(intent); 423 } 424 } 425 } 426 } 427 428 void cancelBroadcasts(Provider p) { 429 if (p.broadcast != null) { 430 mAlarmManager.cancel(p.broadcast); 431 long token = Binder.clearCallingIdentity(); 432 try { 433 p.broadcast.cancel(); 434 } finally { 435 Binder.restoreCallingIdentity(token); 436 } 437 p.broadcast = null; 438 } 439 } 440 441 public void bindAppWidgetId(int appWidgetId, ComponentName provider) { 442 mContext.enforceCallingPermission(android.Manifest.permission.BIND_APPWIDGET, 443 "bindGagetId appWidgetId=" + appWidgetId + " provider=" + provider); 444 445 final long ident = Binder.clearCallingIdentity(); 446 try { 447 synchronized (mAppWidgetIds) { 448 ensureStateLoadedLocked(); 449 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 450 if (id == null) { 451 throw new IllegalArgumentException("bad appWidgetId"); 452 } 453 if (id.provider != null) { 454 throw new IllegalArgumentException("appWidgetId " + appWidgetId + " already bound to " 455 + id.provider.info.provider); 456 } 457 Provider p = lookupProviderLocked(provider); 458 if (p == null) { 459 throw new IllegalArgumentException("not a appwidget provider: " + provider); 460 } 461 if (p.zombie) { 462 throw new IllegalArgumentException("can't bind to a 3rd party provider in" 463 + " safe mode: " + provider); 464 } 465 466 id.provider = p; 467 p.instances.add(id); 468 int instancesSize = p.instances.size(); 469 if (instancesSize == 1) { 470 // tell the provider that it's ready 471 sendEnableIntentLocked(p); 472 } 473 474 // send an update now -- We need this update now, and just for this appWidgetId. 475 // It's less critical when the next one happens, so when we schdule the next one, 476 // we add updatePeriodMillis to its start time. That time will have some slop, 477 // but that's okay. 478 sendUpdateIntentLocked(p, new int[] { appWidgetId }); 479 480 // schedule the future updates 481 registerForBroadcastsLocked(p, getAppWidgetIds(p)); 482 saveStateLocked(); 483 } 484 } finally { 485 Binder.restoreCallingIdentity(ident); 486 } 487 } 488 489 // Binds to a specific RemoteViewsService 490 public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection) { 491 synchronized (mAppWidgetIds) { 492 ensureStateLoadedLocked(); 493 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 494 if (id == null) { 495 throw new IllegalArgumentException("bad appWidgetId"); 496 } 497 final ComponentName componentName = intent.getComponent(); 498 try { 499 final ServiceInfo si = mContext.getPackageManager().getServiceInfo(componentName, 500 PackageManager.GET_PERMISSIONS); 501 if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(si.permission)) { 502 throw new SecurityException("Selected service does not require " 503 + android.Manifest.permission.BIND_REMOTEVIEWS 504 + ": " + componentName); 505 } 506 } catch (PackageManager.NameNotFoundException e) { 507 throw new IllegalArgumentException("Unknown component " + componentName); 508 } 509 510 // If there is already a connection made for this service intent, then disconnect from 511 // that first. (This does not allow multiple connections to the same service under 512 // the same key) 513 ServiceConnectionProxy conn = null; 514 FilterComparison fc = new FilterComparison(intent); 515 Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc); 516 if (mBoundRemoteViewsServices.containsKey(key)) { 517 conn = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key); 518 conn.disconnect(); 519 mContext.unbindService(conn); 520 mBoundRemoteViewsServices.remove(key); 521 } 522 523 // Bind to the RemoteViewsService (which will trigger a callback to the 524 // RemoteViewsAdapter.onServiceConnected()) 525 final long token = Binder.clearCallingIdentity(); 526 try { 527 conn = new ServiceConnectionProxy(key, connection); 528 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE); 529 mBoundRemoteViewsServices.put(key, conn); 530 } finally { 531 Binder.restoreCallingIdentity(token); 532 } 533 534 // Add it to the mapping of RemoteViewsService to appWidgetIds so that we can determine 535 // when we can call back to the RemoteViewsService later to destroy associated 536 // factories. 537 incrementAppWidgetServiceRefCount(appWidgetId, fc); 538 } 539 } 540 541 // Unbinds from a specific RemoteViewsService 542 public void unbindRemoteViewsService(int appWidgetId, Intent intent) { 543 synchronized (mAppWidgetIds) { 544 ensureStateLoadedLocked(); 545 // Unbind from the RemoteViewsService (which will trigger a callback to the bound 546 // RemoteViewsAdapter) 547 Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, 548 new FilterComparison(intent)); 549 if (mBoundRemoteViewsServices.containsKey(key)) { 550 // We don't need to use the appWidgetId until after we are sure there is something 551 // to unbind. Note that this may mask certain issues with apps calling unbind() 552 // more than necessary. 553 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 554 if (id == null) { 555 throw new IllegalArgumentException("bad appWidgetId"); 556 } 557 558 ServiceConnectionProxy conn = 559 (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key); 560 conn.disconnect(); 561 mContext.unbindService(conn); 562 mBoundRemoteViewsServices.remove(key); 563 } else { 564 Log.e("AppWidgetService", "Error (unbindRemoteViewsService): Connection not bound"); 565 } 566 } 567 } 568 569 // Unbinds from a RemoteViewsService when we delete an app widget 570 private void unbindAppWidgetRemoteViewsServicesLocked(AppWidgetId id) { 571 int appWidgetId = id.appWidgetId; 572 // Unbind all connections to Services bound to this AppWidgetId 573 Iterator<Pair<Integer, Intent.FilterComparison>> it = 574 mBoundRemoteViewsServices.keySet().iterator(); 575 while (it.hasNext()) { 576 final Pair<Integer, Intent.FilterComparison> key = it.next(); 577 if (key.first.intValue() == appWidgetId) { 578 final ServiceConnectionProxy conn = (ServiceConnectionProxy) 579 mBoundRemoteViewsServices.get(key); 580 conn.disconnect(); 581 mContext.unbindService(conn); 582 it.remove(); 583 } 584 } 585 586 // Check if we need to destroy any services (if no other app widgets are 587 // referencing the same service) 588 decrementAppWidgetServiceRefCount(appWidgetId); 589 } 590 591 // Destroys the cached factory on the RemoteViewsService's side related to the specified intent 592 private void destroyRemoteViewsService(final Intent intent) { 593 final ServiceConnection conn = new ServiceConnection() { 594 @Override 595 public void onServiceConnected(ComponentName name, IBinder service) { 596 final IRemoteViewsFactory cb = 597 IRemoteViewsFactory.Stub.asInterface(service); 598 try { 599 cb.onDestroy(intent); 600 } catch (RemoteException e) { 601 e.printStackTrace(); 602 } catch (RuntimeException e) { 603 e.printStackTrace(); 604 } 605 mContext.unbindService(this); 606 } 607 @Override 608 public void onServiceDisconnected(android.content.ComponentName name) { 609 // Do nothing 610 } 611 }; 612 613 // Bind to the service and remove the static intent->factory mapping in the 614 // RemoteViewsService. 615 final long token = Binder.clearCallingIdentity(); 616 try { 617 mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE); 618 } finally { 619 Binder.restoreCallingIdentity(token); 620 } 621 } 622 623 // Adds to the ref-count for a given RemoteViewsService intent 624 private void incrementAppWidgetServiceRefCount(int appWidgetId, FilterComparison fc) { 625 HashSet<Integer> appWidgetIds = null; 626 if (mRemoteViewsServicesAppWidgets.containsKey(fc)) { 627 appWidgetIds = mRemoteViewsServicesAppWidgets.get(fc); 628 } else { 629 appWidgetIds = new HashSet<Integer>(); 630 mRemoteViewsServicesAppWidgets.put(fc, appWidgetIds); 631 } 632 appWidgetIds.add(appWidgetId); 633 } 634 635 // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if 636 // the ref-count reaches zero. 637 private void decrementAppWidgetServiceRefCount(int appWidgetId) { 638 Iterator<FilterComparison> it = 639 mRemoteViewsServicesAppWidgets.keySet().iterator(); 640 while (it.hasNext()) { 641 final FilterComparison key = it.next(); 642 final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key); 643 if (ids.remove(appWidgetId)) { 644 // If we have removed the last app widget referencing this service, then we 645 // should destroy it and remove it from this set 646 if (ids.isEmpty()) { 647 destroyRemoteViewsService(key.getIntent()); 648 it.remove(); 649 } 650 } 651 } 652 } 653 654 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { 655 synchronized (mAppWidgetIds) { 656 ensureStateLoadedLocked(); 657 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 658 if (id != null && id.provider != null && !id.provider.zombie) { 659 return id.provider.info; 660 } 661 return null; 662 } 663 } 664 665 public RemoteViews getAppWidgetViews(int appWidgetId) { 666 synchronized (mAppWidgetIds) { 667 ensureStateLoadedLocked(); 668 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetId); 669 if (id != null) { 670 return id.views; 671 } 672 return null; 673 } 674 } 675 676 public List<AppWidgetProviderInfo> getInstalledProviders() { 677 synchronized (mAppWidgetIds) { 678 ensureStateLoadedLocked(); 679 final int N = mInstalledProviders.size(); 680 ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(N); 681 for (int i=0; i<N; i++) { 682 Provider p = mInstalledProviders.get(i); 683 if (!p.zombie) { 684 result.add(p.info); 685 } 686 } 687 return result; 688 } 689 } 690 691 public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views) { 692 if (appWidgetIds == null) { 693 return; 694 } 695 if (appWidgetIds.length == 0) { 696 return; 697 } 698 final int N = appWidgetIds.length; 699 700 synchronized (mAppWidgetIds) { 701 ensureStateLoadedLocked(); 702 for (int i=0; i<N; i++) { 703 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 704 updateAppWidgetInstanceLocked(id, views); 705 } 706 } 707 } 708 709 public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views) { 710 if (appWidgetIds == null) { 711 return; 712 } 713 if (appWidgetIds.length == 0) { 714 return; 715 } 716 final int N = appWidgetIds.length; 717 718 synchronized (mAppWidgetIds) { 719 ensureStateLoadedLocked(); 720 for (int i=0; i<N; i++) { 721 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 722 updateAppWidgetInstanceLocked(id, views, true); 723 } 724 } 725 } 726 727 public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId) { 728 if (appWidgetIds == null) { 729 return; 730 } 731 if (appWidgetIds.length == 0) { 732 return; 733 } 734 final int N = appWidgetIds.length; 735 736 synchronized (mAppWidgetIds) { 737 ensureStateLoadedLocked(); 738 for (int i=0; i<N; i++) { 739 AppWidgetId id = lookupAppWidgetIdLocked(appWidgetIds[i]); 740 notifyAppWidgetViewDataChangedInstanceLocked(id, viewId); 741 } 742 } 743 } 744 745 public void updateAppWidgetProvider(ComponentName provider, RemoteViews views) { 746 synchronized (mAppWidgetIds) { 747 ensureStateLoadedLocked(); 748 Provider p = lookupProviderLocked(provider); 749 if (p == null) { 750 Slog.w(TAG, "updateAppWidgetProvider: provider doesn't exist: " + provider); 751 return; 752 } 753 ArrayList<AppWidgetId> instances = p.instances; 754 final int N = instances.size(); 755 for (int i=0; i<N; i++) { 756 AppWidgetId id = instances.get(i); 757 updateAppWidgetInstanceLocked(id, views); 758 } 759 } 760 } 761 762 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views) { 763 updateAppWidgetInstanceLocked(id, views, false); 764 } 765 766 void updateAppWidgetInstanceLocked(AppWidgetId id, RemoteViews views, boolean isPartialUpdate) { 767 // allow for stale appWidgetIds and other badness 768 // lookup also checks that the calling process can access the appWidgetId 769 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) 770 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { 771 772 // We do not want to save this RemoteViews 773 if (!isPartialUpdate) id.views = views; 774 775 // is anyone listening? 776 if (id.host.callbacks != null) { 777 try { 778 // the lock is held, but this is a oneway call 779 id.host.callbacks.updateAppWidget(id.appWidgetId, views); 780 } catch (RemoteException e) { 781 // It failed; remove the callback. No need to prune because 782 // we know that this host is still referenced by this instance. 783 id.host.callbacks = null; 784 } 785 } 786 } 787 } 788 789 void notifyAppWidgetViewDataChangedInstanceLocked(AppWidgetId id, int viewId) { 790 // allow for stale appWidgetIds and other badness 791 // lookup also checks that the calling process can access the appWidgetId 792 // drop unbound appWidgetIds (shouldn't be possible under normal circumstances) 793 if (id != null && id.provider != null && !id.provider.zombie && !id.host.zombie) { 794 // is anyone listening? 795 if (id.host.callbacks != null) { 796 try { 797 // the lock is held, but this is a oneway call 798 id.host.callbacks.viewDataChanged(id.appWidgetId, viewId); 799 } catch (RemoteException e) { 800 // It failed; remove the callback. No need to prune because 801 // we know that this host is still referenced by this instance. 802 id.host.callbacks = null; 803 } 804 } 805 } 806 } 807 808 public int[] startListening(IAppWidgetHost callbacks, String packageName, int hostId, 809 List<RemoteViews> updatedViews) { 810 int callingUid = enforceCallingUid(packageName); 811 synchronized (mAppWidgetIds) { 812 ensureStateLoadedLocked(); 813 Host host = lookupOrAddHostLocked(callingUid, packageName, hostId); 814 host.callbacks = callbacks; 815 816 updatedViews.clear(); 817 818 ArrayList<AppWidgetId> instances = host.instances; 819 int N = instances.size(); 820 int[] updatedIds = new int[N]; 821 for (int i=0; i<N; i++) { 822 AppWidgetId id = instances.get(i); 823 updatedIds[i] = id.appWidgetId; 824 updatedViews.add(id.views); 825 } 826 return updatedIds; 827 } 828 } 829 830 public void stopListening(int hostId) { 831 synchronized (mAppWidgetIds) { 832 ensureStateLoadedLocked(); 833 Host host = lookupHostLocked(getCallingUid(), hostId); 834 if (host != null) { 835 host.callbacks = null; 836 pruneHostLocked(host); 837 } 838 } 839 } 840 841 boolean canAccessAppWidgetId(AppWidgetId id, int callingUid) { 842 if (id.host.uid == callingUid) { 843 // Apps hosting the AppWidget have access to it. 844 return true; 845 } 846 if (id.provider != null && id.provider.uid == callingUid) { 847 // Apps providing the AppWidget have access to it (if the appWidgetId has been bound) 848 return true; 849 } 850 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BIND_APPWIDGET) 851 == PackageManager.PERMISSION_GRANTED) { 852 // Apps that can bind have access to all appWidgetIds. 853 return true; 854 } 855 // Nobody else can access it. 856 return false; 857 } 858 859 AppWidgetId lookupAppWidgetIdLocked(int appWidgetId) { 860 int callingUid = getCallingUid(); 861 final int N = mAppWidgetIds.size(); 862 for (int i=0; i<N; i++) { 863 AppWidgetId id = mAppWidgetIds.get(i); 864 if (id.appWidgetId == appWidgetId && canAccessAppWidgetId(id, callingUid)) { 865 return id; 866 } 867 } 868 return null; 869 } 870 871 Provider lookupProviderLocked(ComponentName provider) { 872 final int N = mInstalledProviders.size(); 873 for (int i=0; i<N; i++) { 874 Provider p = mInstalledProviders.get(i); 875 if (p.info.provider.equals(provider)) { 876 return p; 877 } 878 } 879 return null; 880 } 881 882 Host lookupHostLocked(int uid, int hostId) { 883 final int N = mHosts.size(); 884 for (int i=0; i<N; i++) { 885 Host h = mHosts.get(i); 886 if (h.uid == uid && h.hostId == hostId) { 887 return h; 888 } 889 } 890 return null; 891 } 892 893 Host lookupOrAddHostLocked(int uid, String packageName, int hostId) { 894 final int N = mHosts.size(); 895 for (int i=0; i<N; i++) { 896 Host h = mHosts.get(i); 897 if (h.hostId == hostId && h.packageName.equals(packageName)) { 898 return h; 899 } 900 } 901 Host host = new Host(); 902 host.packageName = packageName; 903 host.uid = uid; 904 host.hostId = hostId; 905 mHosts.add(host); 906 return host; 907 } 908 909 void pruneHostLocked(Host host) { 910 if (host.instances.size() == 0 && host.callbacks == null) { 911 mHosts.remove(host); 912 } 913 } 914 915 void loadAppWidgetList() { 916 PackageManager pm = mPackageManager; 917 918 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 919 List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent, 920 PackageManager.GET_META_DATA); 921 922 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 923 for (int i=0; i<N; i++) { 924 ResolveInfo ri = broadcastReceivers.get(i); 925 addProviderLocked(ri); 926 } 927 } 928 929 boolean addProviderLocked(ResolveInfo ri) { 930 if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 931 return false; 932 } 933 if (!ri.activityInfo.isEnabled()) { 934 return false; 935 } 936 Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName, 937 ri.activityInfo.name), ri); 938 if (p != null) { 939 mInstalledProviders.add(p); 940 return true; 941 } else { 942 return false; 943 } 944 } 945 946 void removeProviderLocked(int index, Provider p) { 947 int N = p.instances.size(); 948 for (int i=0; i<N; i++) { 949 AppWidgetId id = p.instances.get(i); 950 // Call back with empty RemoteViews 951 updateAppWidgetInstanceLocked(id, null); 952 // Stop telling the host about updates for this from now on 953 cancelBroadcasts(p); 954 // clear out references to this appWidgetId 955 id.host.instances.remove(id); 956 mAppWidgetIds.remove(id); 957 id.provider = null; 958 pruneHostLocked(id.host); 959 id.host = null; 960 } 961 p.instances.clear(); 962 mInstalledProviders.remove(index); 963 mDeletedProviders.add(p); 964 // no need to send the DISABLE broadcast, since the receiver is gone anyway 965 cancelBroadcasts(p); 966 } 967 968 void sendEnableIntentLocked(Provider p) { 969 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); 970 intent.setComponent(p.info.provider); 971 mContext.sendBroadcast(intent); 972 } 973 974 void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) { 975 if (appWidgetIds != null && appWidgetIds.length > 0) { 976 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 977 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 978 intent.setComponent(p.info.provider); 979 mContext.sendBroadcast(intent); 980 } 981 } 982 983 void registerForBroadcastsLocked(Provider p, int[] appWidgetIds) { 984 if (p.info.updatePeriodMillis > 0) { 985 // if this is the first instance, set the alarm. otherwise, 986 // rely on the fact that we've already set it and that 987 // PendingIntent.getBroadcast will update the extras. 988 boolean alreadyRegistered = p.broadcast != null; 989 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 990 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 991 intent.setComponent(p.info.provider); 992 long token = Binder.clearCallingIdentity(); 993 try { 994 p.broadcast = PendingIntent.getBroadcast(mContext, 1, intent, 995 PendingIntent.FLAG_UPDATE_CURRENT); 996 } finally { 997 Binder.restoreCallingIdentity(token); 998 } 999 if (!alreadyRegistered) { 1000 long period = p.info.updatePeriodMillis; 1001 if (period < MIN_UPDATE_PERIOD) { 1002 period = MIN_UPDATE_PERIOD; 1003 } 1004 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1005 SystemClock.elapsedRealtime() + period, period, p.broadcast); 1006 } 1007 } 1008 } 1009 1010 static int[] getAppWidgetIds(Provider p) { 1011 int instancesSize = p.instances.size(); 1012 int appWidgetIds[] = new int[instancesSize]; 1013 for (int i=0; i<instancesSize; i++) { 1014 appWidgetIds[i] = p.instances.get(i).appWidgetId; 1015 } 1016 return appWidgetIds; 1017 } 1018 1019 public int[] getAppWidgetIds(ComponentName provider) { 1020 synchronized (mAppWidgetIds) { 1021 ensureStateLoadedLocked(); 1022 Provider p = lookupProviderLocked(provider); 1023 if (p != null && getCallingUid() == p.uid) { 1024 return getAppWidgetIds(p); 1025 } else { 1026 return new int[0]; 1027 } 1028 } 1029 } 1030 1031 private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) { 1032 Provider p = null; 1033 1034 ActivityInfo activityInfo = ri.activityInfo; 1035 XmlResourceParser parser = null; 1036 try { 1037 parser = activityInfo.loadXmlMetaData(mPackageManager, 1038 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); 1039 if (parser == null) { 1040 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER + " meta-data for " 1041 + "AppWidget provider '" + component + '\''); 1042 return null; 1043 } 1044 1045 AttributeSet attrs = Xml.asAttributeSet(parser); 1046 1047 int type; 1048 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 1049 && type != XmlPullParser.START_TAG) { 1050 // drain whitespace, comments, etc. 1051 } 1052 1053 String nodeName = parser.getName(); 1054 if (!"appwidget-provider".equals(nodeName)) { 1055 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for" 1056 + " AppWidget provider '" + component + '\''); 1057 return null; 1058 } 1059 1060 p = new Provider(); 1061 AppWidgetProviderInfo info = p.info = new AppWidgetProviderInfo(); 1062 info.provider = component; 1063 p.uid = activityInfo.applicationInfo.uid; 1064 1065 Resources res = mPackageManager.getResourcesForApplication( 1066 activityInfo.applicationInfo); 1067 1068 TypedArray sa = res.obtainAttributes(attrs, 1069 com.android.internal.R.styleable.AppWidgetProviderInfo); 1070 1071 // These dimensions has to be resolved in the application's context. 1072 // We simply send back the raw complex data, which will be 1073 // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}. 1074 TypedValue value = sa.peekValue( 1075 com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth); 1076 info.minWidth = value != null ? value.data : 0; 1077 value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight); 1078 info.minHeight = value != null ? value.data : 0; 1079 value = sa.peekValue( 1080 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth); 1081 info.minResizeWidth = value != null ? value.data : info.minWidth; 1082 value = sa.peekValue( 1083 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight); 1084 info.minResizeHeight = value != null ? value.data : info.minHeight; 1085 1086 info.updatePeriodMillis = sa.getInt( 1087 com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0); 1088 info.initialLayout = sa.getResourceId( 1089 com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0); 1090 String className = sa.getString( 1091 com.android.internal.R.styleable.AppWidgetProviderInfo_configure); 1092 if (className != null) { 1093 info.configure = new ComponentName(component.getPackageName(), className); 1094 } 1095 info.label = activityInfo.loadLabel(mPackageManager).toString(); 1096 info.icon = ri.getIconResource(); 1097 info.previewImage = sa.getResourceId( 1098 com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); 1099 info.autoAdvanceViewId = sa.getResourceId( 1100 com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1); 1101 info.resizeMode = sa.getInt( 1102 com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode, 1103 AppWidgetProviderInfo.RESIZE_NONE); 1104 1105 sa.recycle(); 1106 } catch (Exception e) { 1107 // Ok to catch Exception here, because anything going wrong because 1108 // of what a client process passes to us should not be fatal for the 1109 // system process. 1110 Slog.w(TAG, "XML parsing failed for AppWidget provider '" + component + '\'', e); 1111 return null; 1112 } finally { 1113 if (parser != null) parser.close(); 1114 } 1115 return p; 1116 } 1117 1118 int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException { 1119 PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0); 1120 if (pkgInfo == null || pkgInfo.applicationInfo == null) { 1121 throw new PackageManager.NameNotFoundException(); 1122 } 1123 return pkgInfo.applicationInfo.uid; 1124 } 1125 1126 int enforceCallingUid(String packageName) throws IllegalArgumentException { 1127 int callingUid = getCallingUid(); 1128 int packageUid; 1129 try { 1130 packageUid = getUidForPackage(packageName); 1131 } catch (PackageManager.NameNotFoundException ex) { 1132 throw new IllegalArgumentException("packageName and uid don't match packageName=" 1133 + packageName); 1134 } 1135 if (callingUid != packageUid) { 1136 throw new IllegalArgumentException("packageName and uid don't match packageName=" 1137 + packageName); 1138 } 1139 return callingUid; 1140 } 1141 1142 void sendInitialBroadcasts() { 1143 synchronized (mAppWidgetIds) { 1144 ensureStateLoadedLocked(); 1145 final int N = mInstalledProviders.size(); 1146 for (int i=0; i<N; i++) { 1147 Provider p = mInstalledProviders.get(i); 1148 if (p.instances.size() > 0) { 1149 sendEnableIntentLocked(p); 1150 int[] appWidgetIds = getAppWidgetIds(p); 1151 sendUpdateIntentLocked(p, appWidgetIds); 1152 registerForBroadcastsLocked(p, appWidgetIds); 1153 } 1154 } 1155 } 1156 } 1157 1158 // only call from initialization -- it assumes that the data structures are all empty 1159 void loadStateLocked() { 1160 AtomicFile file = savedStateFile(); 1161 try { 1162 FileInputStream stream = file.openRead(); 1163 readStateFromFileLocked(stream); 1164 1165 if (stream != null) { 1166 try { 1167 stream.close(); 1168 } catch (IOException e) { 1169 Slog.w(TAG, "Failed to close state FileInputStream " + e); 1170 } 1171 } 1172 } catch (FileNotFoundException e) { 1173 Slog.w(TAG, "Failed to read state: " + e); 1174 } 1175 } 1176 1177 void saveStateLocked() { 1178 AtomicFile file = savedStateFile(); 1179 FileOutputStream stream; 1180 try { 1181 stream = file.startWrite(); 1182 if (writeStateToFileLocked(stream)) { 1183 file.finishWrite(stream); 1184 } else { 1185 file.failWrite(stream); 1186 Slog.w(TAG, "Failed to save state, restoring backup."); 1187 } 1188 } catch (IOException e) { 1189 Slog.w(TAG, "Failed open state file for write: " + e); 1190 } 1191 } 1192 1193 boolean writeStateToFileLocked(FileOutputStream stream) { 1194 int N; 1195 1196 try { 1197 XmlSerializer out = new FastXmlSerializer(); 1198 out.setOutput(stream, "utf-8"); 1199 out.startDocument(null, true); 1200 out.startTag(null, "gs"); 1201 1202 int providerIndex = 0; 1203 N = mInstalledProviders.size(); 1204 for (int i=0; i<N; i++) { 1205 Provider p = mInstalledProviders.get(i); 1206 if (p.instances.size() > 0) { 1207 out.startTag(null, "p"); 1208 out.attribute(null, "pkg", p.info.provider.getPackageName()); 1209 out.attribute(null, "cl", p.info.provider.getClassName()); 1210 out.endTag(null, "p"); 1211 p.tag = providerIndex; 1212 providerIndex++; 1213 } 1214 } 1215 1216 N = mHosts.size(); 1217 for (int i=0; i<N; i++) { 1218 Host host = mHosts.get(i); 1219 out.startTag(null, "h"); 1220 out.attribute(null, "pkg", host.packageName); 1221 out.attribute(null, "id", Integer.toHexString(host.hostId)); 1222 out.endTag(null, "h"); 1223 host.tag = i; 1224 } 1225 1226 N = mAppWidgetIds.size(); 1227 for (int i=0; i<N; i++) { 1228 AppWidgetId id = mAppWidgetIds.get(i); 1229 out.startTag(null, "g"); 1230 out.attribute(null, "id", Integer.toHexString(id.appWidgetId)); 1231 out.attribute(null, "h", Integer.toHexString(id.host.tag)); 1232 if (id.provider != null) { 1233 out.attribute(null, "p", Integer.toHexString(id.provider.tag)); 1234 } 1235 out.endTag(null, "g"); 1236 } 1237 1238 out.endTag(null, "gs"); 1239 1240 out.endDocument(); 1241 return true; 1242 } catch (IOException e) { 1243 Slog.w(TAG, "Failed to write state: " + e); 1244 return false; 1245 } 1246 } 1247 1248 void readStateFromFileLocked(FileInputStream stream) { 1249 boolean success = false; 1250 1251 try { 1252 XmlPullParser parser = Xml.newPullParser(); 1253 parser.setInput(stream, null); 1254 1255 int type; 1256 int providerIndex = 0; 1257 HashMap<Integer,Provider> loadedProviders = new HashMap<Integer, Provider>(); 1258 do { 1259 type = parser.next(); 1260 if (type == XmlPullParser.START_TAG) { 1261 String tag = parser.getName(); 1262 if ("p".equals(tag)) { 1263 // TODO: do we need to check that this package has the same signature 1264 // as before? 1265 String pkg = parser.getAttributeValue(null, "pkg"); 1266 String cl = parser.getAttributeValue(null, "cl"); 1267 1268 final PackageManager packageManager = mContext.getPackageManager(); 1269 try { 1270 packageManager.getReceiverInfo(new ComponentName(pkg, cl), 0); 1271 } catch (PackageManager.NameNotFoundException e) { 1272 String[] pkgs = packageManager.currentToCanonicalPackageNames( 1273 new String[] { pkg }); 1274 pkg = pkgs[0]; 1275 } 1276 1277 Provider p = lookupProviderLocked(new ComponentName(pkg, cl)); 1278 if (p == null && mSafeMode) { 1279 // if we're in safe mode, make a temporary one 1280 p = new Provider(); 1281 p.info = new AppWidgetProviderInfo(); 1282 p.info.provider = new ComponentName(pkg, cl); 1283 p.zombie = true; 1284 mInstalledProviders.add(p); 1285 } 1286 if (p != null) { 1287 // if it wasn't uninstalled or something 1288 loadedProviders.put(providerIndex, p); 1289 } 1290 providerIndex++; 1291 } 1292 else if ("h".equals(tag)) { 1293 Host host = new Host(); 1294 1295 // TODO: do we need to check that this package has the same signature 1296 // as before? 1297 host.packageName = parser.getAttributeValue(null, "pkg"); 1298 try { 1299 host.uid = getUidForPackage(host.packageName); 1300 } catch (PackageManager.NameNotFoundException ex) { 1301 host.zombie = true; 1302 } 1303 if (!host.zombie || mSafeMode) { 1304 // In safe mode, we don't discard the hosts we don't recognize 1305 // so that they're not pruned from our list. Otherwise, we do. 1306 host.hostId = Integer.parseInt( 1307 parser.getAttributeValue(null, "id"), 16); 1308 mHosts.add(host); 1309 } 1310 } 1311 else if ("g".equals(tag)) { 1312 AppWidgetId id = new AppWidgetId(); 1313 id.appWidgetId = Integer.parseInt(parser.getAttributeValue(null, "id"), 16); 1314 if (id.appWidgetId >= mNextAppWidgetId) { 1315 mNextAppWidgetId = id.appWidgetId + 1; 1316 } 1317 1318 String providerString = parser.getAttributeValue(null, "p"); 1319 if (providerString != null) { 1320 // there's no provider if it hasn't been bound yet. 1321 // maybe we don't have to save this, but it brings the system 1322 // to the state it was in. 1323 int pIndex = Integer.parseInt(providerString, 16); 1324 id.provider = loadedProviders.get(pIndex); 1325 if (false) { 1326 Slog.d(TAG, "bound appWidgetId=" + id.appWidgetId + " to provider " 1327 + pIndex + " which is " + id.provider); 1328 } 1329 if (id.provider == null) { 1330 // This provider is gone. We just let the host figure out 1331 // that this happened when it fails to load it. 1332 continue; 1333 } 1334 } 1335 1336 int hIndex = Integer.parseInt(parser.getAttributeValue(null, "h"), 16); 1337 id.host = mHosts.get(hIndex); 1338 if (id.host == null) { 1339 // This host is gone. 1340 continue; 1341 } 1342 1343 if (id.provider != null) { 1344 id.provider.instances.add(id); 1345 } 1346 id.host.instances.add(id); 1347 mAppWidgetIds.add(id); 1348 } 1349 } 1350 } while (type != XmlPullParser.END_DOCUMENT); 1351 success = true; 1352 } catch (NullPointerException e) { 1353 Slog.w(TAG, "failed parsing " + e); 1354 } catch (NumberFormatException e) { 1355 Slog.w(TAG, "failed parsing " + e); 1356 } catch (XmlPullParserException e) { 1357 Slog.w(TAG, "failed parsing " + e); 1358 } catch (IOException e) { 1359 Slog.w(TAG, "failed parsing " + e); 1360 } catch (IndexOutOfBoundsException e) { 1361 Slog.w(TAG, "failed parsing " + e); 1362 } 1363 1364 if (success) { 1365 // delete any hosts that didn't manage to get connected (should happen) 1366 // if it matters, they'll be reconnected. 1367 for (int i=mHosts.size()-1; i>=0; i--) { 1368 pruneHostLocked(mHosts.get(i)); 1369 } 1370 } else { 1371 // failed reading, clean up 1372 Slog.w(TAG, "Failed to read state, clearing widgets and hosts."); 1373 1374 mAppWidgetIds.clear(); 1375 mHosts.clear(); 1376 final int N = mInstalledProviders.size(); 1377 for (int i=0; i<N; i++) { 1378 mInstalledProviders.get(i).instances.clear(); 1379 } 1380 } 1381 } 1382 1383 AtomicFile savedStateFile() { 1384 return new AtomicFile(new File("/data/system/" + SETTINGS_FILENAME)); 1385 } 1386 1387 BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1388 public void onReceive(Context context, Intent intent) { 1389 String action = intent.getAction(); 1390 //Slog.d(TAG, "received " + action); 1391 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { 1392 sendInitialBroadcasts(); 1393 } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { 1394 Locale revised = Locale.getDefault(); 1395 if (revised == null || mLocale == null || 1396 !(revised.equals(mLocale))) { 1397 mLocale = revised; 1398 1399 synchronized (mAppWidgetIds) { 1400 ensureStateLoadedLocked(); 1401 int N = mInstalledProviders.size(); 1402 for (int i=N-1; i>=0; i--) { 1403 Provider p = mInstalledProviders.get(i); 1404 String pkgName = p.info.provider.getPackageName(); 1405 updateProvidersForPackageLocked(pkgName); 1406 } 1407 saveStateLocked(); 1408 } 1409 } 1410 } else { 1411 boolean added = false; 1412 boolean changed = false; 1413 String pkgList[] = null; 1414 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 1415 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1416 added = true; 1417 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 1418 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 1419 added = false; 1420 } else { 1421 Uri uri = intent.getData(); 1422 if (uri == null) { 1423 return; 1424 } 1425 String pkgName = uri.getSchemeSpecificPart(); 1426 if (pkgName == null) { 1427 return; 1428 } 1429 pkgList = new String[] { pkgName }; 1430 added = Intent.ACTION_PACKAGE_ADDED.equals(action); 1431 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); 1432 } 1433 if (pkgList == null || pkgList.length == 0) { 1434 return; 1435 } 1436 if (added || changed) { 1437 synchronized (mAppWidgetIds) { 1438 ensureStateLoadedLocked(); 1439 Bundle extras = intent.getExtras(); 1440 if (changed || (extras != null && 1441 extras.getBoolean(Intent.EXTRA_REPLACING, false))) { 1442 for (String pkgName : pkgList) { 1443 // The package was just upgraded 1444 updateProvidersForPackageLocked(pkgName); 1445 } 1446 } else { 1447 // The package was just added 1448 for (String pkgName : pkgList) { 1449 addProvidersForPackageLocked(pkgName); 1450 } 1451 } 1452 saveStateLocked(); 1453 } 1454 } else { 1455 Bundle extras = intent.getExtras(); 1456 if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { 1457 // The package is being updated. We'll receive a PACKAGE_ADDED shortly. 1458 } else { 1459 synchronized (mAppWidgetIds) { 1460 ensureStateLoadedLocked(); 1461 for (String pkgName : pkgList) { 1462 removeProvidersForPackageLocked(pkgName); 1463 saveStateLocked(); 1464 } 1465 } 1466 } 1467 } 1468 } 1469 } 1470 }; 1471 1472 void addProvidersForPackageLocked(String pkgName) { 1473 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1474 intent.setPackage(pkgName); 1475 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, 1476 PackageManager.GET_META_DATA); 1477 1478 final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1479 for (int i=0; i<N; i++) { 1480 ResolveInfo ri = broadcastReceivers.get(i); 1481 ActivityInfo ai = ri.activityInfo; 1482 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1483 continue; 1484 } 1485 if (pkgName.equals(ai.packageName)) { 1486 addProviderLocked(ri); 1487 } 1488 } 1489 } 1490 1491 void updateProvidersForPackageLocked(String pkgName) { 1492 HashSet<String> keep = new HashSet<String>(); 1493 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1494 intent.setPackage(pkgName); 1495 List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, 1496 PackageManager.GET_META_DATA); 1497 1498 // add the missing ones and collect which ones to keep 1499 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 1500 for (int i=0; i<N; i++) { 1501 ResolveInfo ri = broadcastReceivers.get(i); 1502 ActivityInfo ai = ri.activityInfo; 1503 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1504 continue; 1505 } 1506 if (pkgName.equals(ai.packageName)) { 1507 ComponentName component = new ComponentName(ai.packageName, ai.name); 1508 Provider p = lookupProviderLocked(component); 1509 if (p == null) { 1510 if (addProviderLocked(ri)) { 1511 keep.add(ai.name); 1512 } 1513 } else { 1514 Provider parsed = parseProviderInfoXml(component, ri); 1515 if (parsed != null) { 1516 keep.add(ai.name); 1517 // Use the new AppWidgetProviderInfo. 1518 p.info = parsed.info; 1519 // If it's enabled 1520 final int M = p.instances.size(); 1521 if (M > 0) { 1522 int[] appWidgetIds = getAppWidgetIds(p); 1523 // Reschedule for the new updatePeriodMillis (don't worry about handling 1524 // it specially if updatePeriodMillis didn't change because we just sent 1525 // an update, and the next one will be updatePeriodMillis from now). 1526 cancelBroadcasts(p); 1527 registerForBroadcastsLocked(p, appWidgetIds); 1528 // If it's currently showing, call back with the new AppWidgetProviderInfo. 1529 for (int j=0; j<M; j++) { 1530 AppWidgetId id = p.instances.get(j); 1531 id.views = null; 1532 if (id.host != null && id.host.callbacks != null) { 1533 try { 1534 id.host.callbacks.providerChanged(id.appWidgetId, p.info); 1535 } catch (RemoteException ex) { 1536 // It failed; remove the callback. No need to prune because 1537 // we know that this host is still referenced by this 1538 // instance. 1539 id.host.callbacks = null; 1540 } 1541 } 1542 } 1543 // Now that we've told the host, push out an update. 1544 sendUpdateIntentLocked(p, appWidgetIds); 1545 } 1546 } 1547 } 1548 } 1549 } 1550 1551 // prune the ones we don't want to keep 1552 N = mInstalledProviders.size(); 1553 for (int i=N-1; i>=0; i--) { 1554 Provider p = mInstalledProviders.get(i); 1555 if (pkgName.equals(p.info.provider.getPackageName()) 1556 && !keep.contains(p.info.provider.getClassName())) { 1557 removeProviderLocked(i, p); 1558 } 1559 } 1560 } 1561 1562 void removeProvidersForPackageLocked(String pkgName) { 1563 int N = mInstalledProviders.size(); 1564 for (int i=N-1; i>=0; i--) { 1565 Provider p = mInstalledProviders.get(i); 1566 if (pkgName.equals(p.info.provider.getPackageName())) { 1567 removeProviderLocked(i, p); 1568 } 1569 } 1570 1571 // Delete the hosts for this package too 1572 // 1573 // By now, we have removed any AppWidgets that were in any hosts here, 1574 // so we don't need to worry about sending DISABLE broadcasts to them. 1575 N = mHosts.size(); 1576 for (int i=N-1; i>=0; i--) { 1577 Host host = mHosts.get(i); 1578 if (pkgName.equals(host.packageName)) { 1579 deleteHostLocked(host); 1580 } 1581 } 1582 } 1583 } 1584 1585