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