AppWidgetServiceImpl.java revision 298a6c6b29798647b3d8f12d0723b1e49fc8b8da
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.appwidget; 18 19import android.app.AlarmManager; 20import android.app.AppGlobals; 21import android.app.AppOpsManager; 22import android.app.PendingIntent; 23import android.app.admin.DevicePolicyManagerInternal; 24import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener; 25import android.appwidget.AppWidgetManager; 26import android.appwidget.AppWidgetProviderInfo; 27import android.content.BroadcastReceiver; 28import android.content.ComponentName; 29import android.content.Context; 30import android.content.Intent; 31import android.content.Intent.FilterComparison; 32import android.content.IntentFilter; 33import android.content.IntentSender; 34import android.content.ServiceConnection; 35import android.content.pm.ActivityInfo; 36import android.content.pm.ApplicationInfo; 37import android.content.pm.IPackageManager; 38import android.content.pm.PackageInfo; 39import android.content.pm.PackageManager; 40import android.content.pm.ResolveInfo; 41import android.content.pm.ServiceInfo; 42import android.content.pm.UserInfo; 43import android.content.res.Resources; 44import android.content.res.TypedArray; 45import android.content.res.XmlResourceParser; 46import android.graphics.Point; 47import android.net.Uri; 48import android.os.Binder; 49import android.os.Bundle; 50import android.os.Environment; 51import android.os.Handler; 52import android.os.IBinder; 53import android.os.Looper; 54import android.os.Message; 55import android.os.Process; 56import android.os.RemoteException; 57import android.os.SystemClock; 58import android.os.UserHandle; 59import android.os.UserManager; 60import android.text.TextUtils; 61import android.util.ArraySet; 62import android.util.AtomicFile; 63import android.util.AttributeSet; 64import android.util.Pair; 65import android.util.Slog; 66import android.util.SparseIntArray; 67import android.util.TypedValue; 68import android.util.Xml; 69import android.view.Display; 70import android.view.WindowManager; 71import android.widget.RemoteViews; 72 73import com.android.internal.appwidget.IAppWidgetHost; 74import com.android.internal.appwidget.IAppWidgetService; 75import com.android.internal.os.BackgroundThread; 76import com.android.internal.os.SomeArgs; 77import com.android.internal.util.FastXmlSerializer; 78import com.android.internal.widget.IRemoteViewsAdapterConnection; 79import com.android.internal.widget.IRemoteViewsFactory; 80 81import com.android.server.LocalServices; 82import com.android.server.WidgetBackupProvider; 83import libcore.io.IoUtils; 84import org.xmlpull.v1.XmlPullParser; 85import org.xmlpull.v1.XmlPullParserException; 86import org.xmlpull.v1.XmlSerializer; 87 88import java.io.ByteArrayInputStream; 89import java.io.ByteArrayOutputStream; 90import java.io.File; 91import java.io.FileDescriptor; 92import java.io.FileInputStream; 93import java.io.FileNotFoundException; 94import java.io.FileOutputStream; 95import java.io.IOException; 96import java.io.PrintWriter; 97import java.util.ArrayList; 98import java.util.Collections; 99import java.util.HashMap; 100import java.util.HashSet; 101import java.util.Iterator; 102import java.util.List; 103import java.util.Locale; 104import java.util.Map; 105import java.util.Set; 106 107class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider, 108 OnCrossProfileWidgetProvidersChangeListener { 109 private static final String TAG = "AppWidgetServiceImpl"; 110 111 private static boolean DEBUG = false; 112 113 private static final String OLD_KEYGUARD_HOST_PACKAGE = "android"; 114 private static final String NEW_KEYGUARD_HOST_PACKAGE = "com.android.keyguard"; 115 private static final int KEYGUARD_HOST_ID = 0x4b455947; 116 117 private static final String STATE_FILENAME = "appwidgets.xml"; 118 119 private static final int MIN_UPDATE_PERIOD = DEBUG ? 0 : 30 * 60 * 1000; // 30 minutes 120 121 private static final int TAG_UNDEFINED = -1; 122 123 private static final int UNKNOWN_UID = -1; 124 125 private static final int LOADED_PROFILE_ID = -1; 126 127 private static final int UNKNOWN_USER_ID = -10; 128 129 // Bump if the stored widgets need to be upgraded. 130 private static final int CURRENT_VERSION = 1; 131 132 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 133 public void onReceive(Context context, Intent intent) { 134 String action = intent.getAction(); 135 136 if (DEBUG) { 137 Slog.i(TAG, "Received broadcast: " + action); 138 } 139 140 if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { 141 onConfigurationChanged(); 142 } else if (Intent.ACTION_USER_STARTED.equals(action)) { 143 onUserStarted(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 144 UserHandle.USER_NULL)); 145 } else if (Intent.ACTION_USER_STOPPED.equals(action)) { 146 onUserStopped(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 147 UserHandle.USER_NULL)); 148 } else { 149 onPackageBroadcastReceived(intent, intent.getIntExtra( 150 Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)); 151 } 152 } 153 }; 154 155 // Manages active connections to RemoteViewsServices. 156 private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection> 157 mBoundRemoteViewsServices = new HashMap<>(); 158 159 // Manages persistent references to RemoteViewsServices from different App Widgets. 160 private final HashMap<Pair<Integer, FilterComparison>, HashSet<Integer>> 161 mRemoteViewsServicesAppWidgets = new HashMap<>(); 162 163 private final Object mLock = new Object(); 164 165 private final ArrayList<Widget> mWidgets = new ArrayList<>(); 166 private final ArrayList<Host> mHosts = new ArrayList<>(); 167 private final ArrayList<Provider> mProviders = new ArrayList<>(); 168 169 private final ArraySet<Pair<Integer, String>> mPackagesWithBindWidgetPermission = 170 new ArraySet<>(); 171 172 private final SparseIntArray mLoadedUserIds = new SparseIntArray(); 173 174 private final BackupRestoreController mBackupRestoreController; 175 176 private final Context mContext; 177 178 private final IPackageManager mPackageManager; 179 private final AlarmManager mAlarmManager; 180 private final UserManager mUserManager; 181 private final AppOpsManager mAppOpsManager; 182 183 private final SecurityPolicy mSecurityPolicy; 184 185 private final Handler mSaveStateHandler; 186 private final Handler mCallbackHandler; 187 188 private Locale mLocale; 189 190 private final SparseIntArray mNextAppWidgetIds = new SparseIntArray(); 191 192 private boolean mSafeMode; 193 private int mMaxWidgetBitmapMemory; 194 195 AppWidgetServiceImpl(Context context) { 196 mContext = context; 197 mPackageManager = AppGlobals.getPackageManager(); 198 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 199 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 200 mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 201 mSaveStateHandler = BackgroundThread.getHandler(); 202 mCallbackHandler = new CallbackHandler(mContext.getMainLooper()); 203 mBackupRestoreController = new BackupRestoreController(); 204 mSecurityPolicy = new SecurityPolicy(); 205 computeMaximumWidgetBitmapMemory(); 206 registerBroadcastReceiver(); 207 registerOnCrossProfileProvidersChangedListener(); 208 } 209 210 private 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 220 private void registerBroadcastReceiver() { 221 // Register for configuration changes so we can update the names 222 // of the widgets when the locale changes. 223 IntentFilter configFilter = new IntentFilter(); 224 configFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 225 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 226 configFilter, null, null); 227 228 // Register for broadcasts about package install, etc., so we can 229 // update the provider list. 230 IntentFilter packageFilter = new IntentFilter(); 231 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 232 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 233 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 234 packageFilter.addDataScheme("package"); 235 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 236 packageFilter, null, null); 237 238 // Register for events related to sdcard installation. 239 IntentFilter sdFilter = new IntentFilter(); 240 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); 241 sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); 242 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 243 sdFilter, null, null); 244 245 IntentFilter userFilter = new IntentFilter(); 246 userFilter.addAction(Intent.ACTION_USER_STARTED); 247 userFilter.addAction(Intent.ACTION_USER_STOPPED); 248 mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, 249 userFilter, null, null); 250 } 251 252 private void registerOnCrossProfileProvidersChangedListener() { 253 DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService( 254 DevicePolicyManagerInternal.class); 255 // The device policy is an optional component. 256 if (devicePolicyManager != null) { 257 devicePolicyManager.addOnCrossProfileWidgetProvidersChangeListener(this); 258 } 259 } 260 261 public void setSafeMode(boolean safeMode) { 262 mSafeMode = safeMode; 263 } 264 265 private void onConfigurationChanged() { 266 if (DEBUG) { 267 Slog.i(TAG, "onConfigurationChanged()"); 268 } 269 270 Locale revised = Locale.getDefault(); 271 if (revised == null || mLocale == null || !revised.equals(mLocale)) { 272 mLocale = revised; 273 274 synchronized (mLock) { 275 SparseIntArray changedGroups = null; 276 277 // Note: updateProvidersForPackageLocked() may remove providers, so we must copy the 278 // list of installed providers and skip providers that we don't need to update. 279 // Also note that remove the provider does not clear the Provider component data. 280 ArrayList<Provider> installedProviders = new ArrayList<>(mProviders); 281 HashSet<ProviderId> removedProviders = new HashSet<>(); 282 283 int N = installedProviders.size(); 284 for (int i = N - 1; i >= 0; i--) { 285 Provider provider = installedProviders.get(i); 286 287 ensureGroupStateLoadedLocked(provider.getUserId()); 288 289 if (!removedProviders.contains(provider.id)) { 290 final boolean changed = updateProvidersForPackageLocked( 291 provider.id.componentName.getPackageName(), 292 provider.getUserId(), removedProviders); 293 294 if (changed) { 295 if (changedGroups == null) { 296 changedGroups = new SparseIntArray(); 297 } 298 final int groupId = mSecurityPolicy.getGroupParent( 299 provider.getUserId()); 300 changedGroups.put(groupId, groupId); 301 } 302 } 303 } 304 305 if (changedGroups != null) { 306 final int groupCount = changedGroups.size(); 307 for (int i = 0; i < groupCount; i++) { 308 final int groupId = changedGroups.get(i); 309 saveGroupStateAsync(groupId); 310 } 311 } 312 } 313 } 314 } 315 316 private void onPackageBroadcastReceived(Intent intent, int userId) { 317 final String action = intent.getAction(); 318 boolean added = false; 319 boolean changed = false; 320 boolean componentsModified = false; 321 322 String pkgList[] = null; 323 if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { 324 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 325 added = true; 326 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { 327 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); 328 added = false; 329 } else { 330 Uri uri = intent.getData(); 331 if (uri == null) { 332 return; 333 } 334 String pkgName = uri.getSchemeSpecificPart(); 335 if (pkgName == null) { 336 return; 337 } 338 pkgList = new String[] { pkgName }; 339 added = Intent.ACTION_PACKAGE_ADDED.equals(action); 340 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); 341 } 342 if (pkgList == null || pkgList.length == 0) { 343 return; 344 } 345 346 synchronized (mLock) { 347 ensureGroupStateLoadedLocked(userId); 348 349 Bundle extras = intent.getExtras(); 350 351 if (added || changed) { 352 final boolean newPackageAdded = added && (extras == null 353 || !extras.getBoolean(Intent.EXTRA_REPLACING, false)); 354 355 for (String pkgName : pkgList) { 356 // Fix up the providers - add/remove/update. 357 componentsModified |= updateProvidersForPackageLocked(pkgName, userId, null); 358 359 // ... and see if these are hosts we've been awaiting. 360 // NOTE: We are backing up and restoring only the owner. 361 if (newPackageAdded && userId == UserHandle.USER_OWNER) { 362 final int uid = getUidForPackage(pkgName, userId); 363 if (uid >= 0 ) { 364 resolveHostUidLocked(pkgName, uid); 365 } 366 } 367 } 368 } else { 369 // If the package is being updated, we'll receive a PACKAGE_ADDED 370 // shortly, otherwise it is removed permanently. 371 final boolean packageRemovedPermanently = (extras == null 372 || !extras.getBoolean(Intent.EXTRA_REPLACING, false)); 373 374 if (packageRemovedPermanently) { 375 for (String pkgName : pkgList) { 376 componentsModified |= removeHostsAndProvidersForPackageLocked( 377 pkgName, userId); 378 } 379 } 380 } 381 382 if (componentsModified) { 383 saveGroupStateAsync(userId); 384 385 // If the set of providers has been modified, notify each active AppWidgetHost 386 scheduleNotifyGroupHostsForProvidersChangedLocked(userId); 387 } 388 } 389 } 390 391 private void resolveHostUidLocked(String pkg, int uid) { 392 final int N = mHosts.size(); 393 for (int i = 0; i < N; i++) { 394 Host host = mHosts.get(i); 395 if (host.id.uid == UNKNOWN_UID && pkg.equals(host.id.packageName)) { 396 if (DEBUG) { 397 Slog.i(TAG, "host " + host.id + " resolved to uid " + uid); 398 } 399 host.id = new HostId(uid, host.id.hostId, host.id.packageName); 400 return; 401 } 402 } 403 } 404 405 private void ensureGroupStateLoadedLocked(int userId) { 406 final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId); 407 408 // Careful lad, we may have already loaded the state for some 409 // group members, so check before loading and read only the 410 // state for the new member(s). 411 int newMemberCount = 0; 412 final int profileIdCount = profileIds.length; 413 for (int i = 0; i < profileIdCount; i++) { 414 final int profileId = profileIds[i]; 415 if (mLoadedUserIds.indexOfKey(profileId) >= 0) { 416 profileIds[i] = LOADED_PROFILE_ID; 417 } else { 418 newMemberCount++; 419 } 420 } 421 422 if (newMemberCount <= 0) { 423 return; 424 } 425 426 int newMemberIndex = 0; 427 final int[] newProfileIds = new int[newMemberCount]; 428 for (int i = 0; i < profileIdCount; i++) { 429 final int profileId = profileIds[i]; 430 if (profileId != LOADED_PROFILE_ID) { 431 mLoadedUserIds.put(profileId, profileId); 432 newProfileIds[newMemberIndex] = profileId; 433 newMemberIndex++; 434 } 435 } 436 437 loadGroupWidgetProvidersLocked(newProfileIds); 438 loadGroupStateLocked(newProfileIds); 439 } 440 441 @Override 442 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 443 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 444 != PackageManager.PERMISSION_GRANTED) { 445 throw new SecurityException("Permission Denial: can't dump from from pid=" 446 + Binder.getCallingPid() 447 + ", uid=" + Binder.getCallingUid()); 448 } 449 450 synchronized (mLock) { 451 int N = mProviders.size(); 452 pw.println("Providers:"); 453 for (int i = 0; i < N; i++) { 454 dumpProvider(mProviders.get(i), i, pw); 455 } 456 457 N = mWidgets.size(); 458 pw.println(" "); 459 pw.println("Widgets:"); 460 for (int i = 0; i < N; i++) { 461 dumpWidget(mWidgets.get(i), i, pw); 462 } 463 464 N = mHosts.size(); 465 pw.println(" "); 466 pw.println("Hosts:"); 467 for (int i = 0; i < N; i++) { 468 dumpHost(mHosts.get(i), i, pw); 469 } 470 471 472 N = mPackagesWithBindWidgetPermission.size(); 473 pw.println(" "); 474 pw.println("Grants:"); 475 for (int i = 0; i < N; i++) { 476 Pair<Integer, String> grant = mPackagesWithBindWidgetPermission.valueAt(i); 477 dumpGrant(grant, i, pw); 478 } 479 } 480 } 481 482 @Override 483 public int[] startListening(IAppWidgetHost callbacks, String callingPackage, 484 int hostId, List<RemoteViews> updatedViews) { 485 final int userId = UserHandle.getCallingUserId(); 486 487 if (DEBUG) { 488 Slog.i(TAG, "startListening() " + userId); 489 } 490 491 // Make sure the package runs under the caller uid. 492 mSecurityPolicy.enforceCallFromPackage(callingPackage); 493 494 synchronized (mLock) { 495 ensureGroupStateLoadedLocked(userId); 496 497 // NOTE: The lookup is enforcing security across users by making 498 // sure the caller can only access hosts it owns. 499 HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage); 500 Host host = lookupOrAddHostLocked(id); 501 502 host.callbacks = callbacks; 503 504 updatedViews.clear(); 505 506 ArrayList<Widget> instances = host.widgets; 507 int N = instances.size(); 508 int[] updatedIds = new int[N]; 509 for (int i = 0; i < N; i++) { 510 Widget widget = instances.get(i); 511 updatedIds[i] = widget.appWidgetId; 512 updatedViews.add(cloneIfLocalBinder(widget.views)); 513 } 514 515 return updatedIds; 516 } 517 } 518 519 @Override 520 public void stopListening(String callingPackage, int hostId) { 521 final int userId = UserHandle.getCallingUserId(); 522 523 if (DEBUG) { 524 Slog.i(TAG, "stopListening() " + userId); 525 } 526 527 // Make sure the package runs under the caller uid. 528 mSecurityPolicy.enforceCallFromPackage(callingPackage); 529 530 synchronized (mLock) { 531 ensureGroupStateLoadedLocked(userId); 532 533 // NOTE: The lookup is enforcing security across users by making 534 // sure the caller can only access hosts it owns. 535 HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage); 536 Host host = lookupHostLocked(id); 537 538 if (host != null) { 539 host.callbacks = null; 540 pruneHostLocked(host); 541 } 542 } 543 } 544 545 @Override 546 public int allocateAppWidgetId(String callingPackage, int hostId) { 547 final int userId = UserHandle.getCallingUserId(); 548 549 if (DEBUG) { 550 Slog.i(TAG, "allocateAppWidgetId() " + userId); 551 } 552 553 // Make sure the package runs under the caller uid. 554 mSecurityPolicy.enforceCallFromPackage(callingPackage); 555 556 synchronized (mLock) { 557 ensureGroupStateLoadedLocked(userId); 558 559 if (mNextAppWidgetIds.indexOfKey(userId) < 0) { 560 mNextAppWidgetIds.put(userId, AppWidgetManager.INVALID_APPWIDGET_ID + 1); 561 } 562 563 final int appWidgetId = incrementAndGetAppWidgetIdLocked(userId); 564 565 // NOTE: The lookup is enforcing security across users by making 566 // sure the caller can only access hosts it owns. 567 HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage); 568 Host host = lookupOrAddHostLocked(id); 569 570 Widget widget = new Widget(); 571 widget.appWidgetId = appWidgetId; 572 widget.host = host; 573 574 host.widgets.add(widget); 575 mWidgets.add(widget); 576 577 saveGroupStateAsync(userId); 578 579 if (DEBUG) { 580 Slog.i(TAG, "Allocated widget id " + appWidgetId 581 + " for host " + host.id); 582 } 583 584 return appWidgetId; 585 } 586 } 587 588 @Override 589 public void deleteAppWidgetId(String callingPackage, int appWidgetId) { 590 final int userId = UserHandle.getCallingUserId(); 591 592 if (DEBUG) { 593 Slog.i(TAG, "deleteAppWidgetId() " + userId); 594 } 595 596 // Make sure the package runs under the caller uid. 597 mSecurityPolicy.enforceCallFromPackage(callingPackage); 598 599 synchronized (mLock) { 600 ensureGroupStateLoadedLocked(userId); 601 602 // NOTE: The lookup is enforcing security across users by making 603 // sure the caller can only access widgets it hosts or provides. 604 Widget widget = lookupWidgetLocked(appWidgetId, 605 Binder.getCallingUid(), callingPackage); 606 607 if (widget == null) { 608 return; 609 } 610 611 deleteAppWidgetLocked(widget); 612 613 saveGroupStateAsync(userId); 614 615 if (DEBUG) { 616 Slog.i(TAG, "Deleted widget id " + appWidgetId 617 + " for host " + widget.host.id); 618 } 619 } 620 } 621 622 @Override 623 public boolean hasBindAppWidgetPermission(String packageName, int grantId) { 624 if (DEBUG) { 625 Slog.i(TAG, "hasBindAppWidgetPermission() " + UserHandle.getCallingUserId()); 626 } 627 628 // A special permission is required for managing white listing. 629 mSecurityPolicy.enforceModifyAppWidgetBindPermissions(packageName); 630 631 synchronized (mLock) { 632 // The grants are stored in user state wich gets the grant. 633 ensureGroupStateLoadedLocked(grantId); 634 635 final int packageUid = getUidForPackage(packageName, grantId); 636 if (packageUid < 0) { 637 return false; 638 } 639 640 Pair<Integer, String> packageId = Pair.create(grantId, packageName); 641 return mPackagesWithBindWidgetPermission.contains(packageId); 642 } 643 } 644 645 @Override 646 public void setBindAppWidgetPermission(String packageName, int grantId, 647 boolean grantPermission) { 648 if (DEBUG) { 649 Slog.i(TAG, "setBindAppWidgetPermission() " + UserHandle.getCallingUserId()); 650 } 651 652 // A special permission is required for managing white listing. 653 mSecurityPolicy.enforceModifyAppWidgetBindPermissions(packageName); 654 655 synchronized (mLock) { 656 // The grants are stored in user state wich gets the grant. 657 ensureGroupStateLoadedLocked(grantId); 658 659 final int packageUid = getUidForPackage(packageName, grantId); 660 if (packageUid < 0) { 661 return; 662 } 663 664 Pair<Integer, String> packageId = Pair.create(grantId, packageName); 665 if (grantPermission) { 666 mPackagesWithBindWidgetPermission.add(packageId); 667 } else { 668 mPackagesWithBindWidgetPermission.remove(packageId); 669 } 670 671 saveGroupStateAsync(grantId); 672 } 673 } 674 675 @Override 676 public IntentSender createAppWidgetConfigIntentSender(String callingPackage, int appWidgetId, 677 int intentFlags) { 678 final int userId = UserHandle.getCallingUserId(); 679 680 if (DEBUG) { 681 Slog.i(TAG, "createAppWidgetConfigIntentSender() " + userId); 682 } 683 684 // Make sure the package runs under the caller uid. 685 mSecurityPolicy.enforceCallFromPackage(callingPackage); 686 687 synchronized (mLock) { 688 ensureGroupStateLoadedLocked(userId); 689 690 // NOTE: The lookup is enforcing security across users by making 691 // sure the caller can only access widgets it hosts or provides. 692 Widget widget = lookupWidgetLocked(appWidgetId, 693 Binder.getCallingUid(), callingPackage); 694 695 if (widget == null) { 696 throw new IllegalArgumentException("Bad widget id " + appWidgetId); 697 } 698 699 Provider provider = widget.provider; 700 if (provider == null) { 701 throw new IllegalArgumentException("Widget not bound " + appWidgetId); 702 } 703 704 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); 705 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); 706 intent.setComponent(provider.info.configure); 707 intent.setFlags(intentFlags); 708 709 // All right, create the sender. 710 final long identity = Binder.clearCallingIdentity(); 711 try { 712 return PendingIntent.getActivityAsUser( 713 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT 714 | PendingIntent.FLAG_CANCEL_CURRENT, null, 715 new UserHandle(provider.getUserId())) 716 .getIntentSender(); 717 } finally { 718 Binder.restoreCallingIdentity(identity); 719 } 720 } 721 } 722 723 @Override 724 public boolean bindAppWidgetId(String callingPackage, int appWidgetId, 725 int providerProfileId, ComponentName providerComponent, Bundle options) { 726 final int userId = UserHandle.getCallingUserId(); 727 728 if (DEBUG) { 729 Slog.i(TAG, "bindAppWidgetId() " + userId); 730 } 731 732 // Make sure the package runs under the caller uid. 733 mSecurityPolicy.enforceCallFromPackage(callingPackage); 734 735 // Check that if a cross-profile binding is attempted, it is allowed. 736 if (!mSecurityPolicy.isEnabledGroupProfile(providerProfileId)) { 737 return false; 738 } 739 740 // If the provider is not under the calling user, make sure this 741 // provider is white listed for access from the parent. 742 if (!mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed( 743 providerComponent.getPackageName(), providerProfileId)) { 744 return false; 745 } 746 747 synchronized (mLock) { 748 ensureGroupStateLoadedLocked(userId); 749 750 // A special permission or white listing is required to bind widgets. 751 if (!mSecurityPolicy.hasCallerBindPermissionOrBindWhiteListedLocked( 752 callingPackage)) { 753 return false; 754 } 755 756 // NOTE: The lookup is enforcing security across users by making 757 // sure the caller can only access widgets it hosts or provides. 758 Widget widget = lookupWidgetLocked(appWidgetId, 759 Binder.getCallingUid(), callingPackage); 760 761 if (widget == null) { 762 Slog.e(TAG, "Bad widget id " + appWidgetId); 763 return false; 764 } 765 766 if (widget.provider != null) { 767 Slog.e(TAG, "Widget id " + appWidgetId 768 + " already bound to: " + widget.provider.id); 769 return false; 770 } 771 772 final int providerUid = getUidForPackage(providerComponent.getPackageName(), 773 providerProfileId); 774 if (providerUid < 0) { 775 Slog.e(TAG, "Package " + providerComponent.getPackageName() + " not installed " 776 + " for profile " + providerProfileId); 777 return false; 778 } 779 780 // NOTE: The lookup is enforcing security across users by making 781 // sure the provider is in the already vetted user profile. 782 ProviderId providerId = new ProviderId(providerUid, providerComponent); 783 Provider provider = lookupProviderLocked(providerId); 784 785 if (provider == null) { 786 Slog.e(TAG, "No widget provider " + providerComponent + " for profile " 787 + providerProfileId); 788 return false; 789 } 790 791 if (provider.zombie) { 792 Slog.e(TAG, "Can't bind to a 3rd party provider in" 793 + " safe mode " + provider); 794 return false; 795 } 796 797 widget.provider = provider; 798 widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle(); 799 800 // We need to provide a default value for the widget category if it is not specified 801 if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) { 802 widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 803 AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); 804 } 805 806 provider.widgets.add(widget); 807 808 final int widgetCount = provider.widgets.size(); 809 if (widgetCount == 1) { 810 // Tell the provider that it's ready. 811 sendEnableIntentLocked(provider); 812 } 813 814 // Send an update now -- We need this update now, and just for this appWidgetId. 815 // It's less critical when the next one happens, so when we schedule the next one, 816 // we add updatePeriodMillis to its start time. That time will have some slop, 817 // but that's okay. 818 sendUpdateIntentLocked(provider, new int[] {appWidgetId}); 819 820 // Schedule the future updates. 821 registerForBroadcastsLocked(provider, getWidgetIds(provider.widgets)); 822 823 saveGroupStateAsync(userId); 824 825 if (DEBUG) { 826 Slog.i(TAG, "Bound widget " + appWidgetId + " to provider " + provider.id); 827 } 828 } 829 830 return true; 831 } 832 833 @Override 834 public int[] getAppWidgetIds(ComponentName componentName) { 835 final int userId = UserHandle.getCallingUserId(); 836 837 if (DEBUG) { 838 Slog.i(TAG, "getAppWidgetIds() " + userId); 839 } 840 841 // Make sure the package runs under the caller uid. 842 mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName()); 843 844 synchronized (mLock) { 845 ensureGroupStateLoadedLocked(userId); 846 847 // NOTE: The lookup is enforcing security across users by making 848 // sure the caller can access only its providers. 849 ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName); 850 Provider provider = lookupProviderLocked(providerId); 851 852 if (provider != null) { 853 return getWidgetIds(provider.widgets); 854 } 855 856 return new int[0]; 857 } 858 } 859 860 @Override 861 public int[] getAppWidgetIdsForHost(String callingPackage, int hostId) { 862 final int userId = UserHandle.getCallingUserId(); 863 864 if (DEBUG) { 865 Slog.i(TAG, "getAppWidgetIdsForHost() " + userId); 866 } 867 868 // Make sure the package runs under the caller uid. 869 mSecurityPolicy.enforceCallFromPackage(callingPackage); 870 871 synchronized (mLock) { 872 ensureGroupStateLoadedLocked(userId); 873 874 // NOTE: The lookup is enforcing security across users by making 875 // sure the caller can only access its hosts. 876 HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage); 877 Host host = lookupHostLocked(id); 878 879 if (host != null) { 880 return getWidgetIds(host.widgets); 881 } 882 883 return new int[0]; 884 } 885 } 886 887 @Override 888 public void bindRemoteViewsService(String callingPackage, int appWidgetId, 889 Intent intent, IBinder callbacks) { 890 final int userId = UserHandle.getCallingUserId(); 891 892 if (DEBUG) { 893 Slog.i(TAG, "bindRemoteViewsService() " + userId); 894 } 895 896 // Make sure the package runs under the caller uid. 897 mSecurityPolicy.enforceCallFromPackage(callingPackage); 898 899 synchronized (mLock) { 900 ensureGroupStateLoadedLocked(userId); 901 902 // NOTE: The lookup is enforcing security across users by making 903 // sure the caller can only access widgets it hosts or provides. 904 Widget widget = lookupWidgetLocked(appWidgetId, 905 Binder.getCallingUid(), callingPackage); 906 907 if (widget == null) { 908 throw new IllegalArgumentException("Bad widget id"); 909 } 910 911 // Make sure the widget has a provider. 912 if (widget.provider == null) { 913 throw new IllegalArgumentException("No provider for widget " 914 + appWidgetId); 915 } 916 917 ComponentName componentName = intent.getComponent(); 918 919 // Ensure that the service belongs to the same package as the provider. 920 // But this is not enough as they may be under different users - see below... 921 String providerPackage = widget.provider.id.componentName.getPackageName(); 922 String servicePackage = componentName.getPackageName(); 923 if (!servicePackage.equals(providerPackage)) { 924 throw new SecurityException("The taget service not in the same package" 925 + " as the widget provider"); 926 } 927 928 // Make sure this service exists under the same user as the provider and 929 // requires a permission which allows only the system to bind to it. 930 mSecurityPolicy.enforceServiceExistsAndRequiresBindRemoteViewsPermission( 931 componentName, widget.provider.getUserId()); 932 933 // Good to go - the service pakcage is correct, it exists for the correct 934 // user, and requires the bind permission. 935 936 // If there is already a connection made for this service intent, then 937 // disconnect from that first. (This does not allow multiple connections 938 // to the same service under the same key). 939 ServiceConnectionProxy connection = null; 940 FilterComparison fc = new FilterComparison(intent); 941 Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc); 942 943 if (mBoundRemoteViewsServices.containsKey(key)) { 944 connection = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key); 945 connection.disconnect(); 946 unbindService(connection); 947 mBoundRemoteViewsServices.remove(key); 948 } 949 950 // Bind to the RemoteViewsService (which will trigger a callback to the 951 // RemoteViewsAdapter.onServiceConnected()) 952 connection = new ServiceConnectionProxy(callbacks); 953 bindService(intent, connection, widget.provider.info.getProfile()); 954 mBoundRemoteViewsServices.put(key, connection); 955 956 // Add it to the mapping of RemoteViewsService to appWidgetIds so that we 957 // can determine when we can call back to the RemoteViewsService later to 958 // destroy associated factories. 959 Pair<Integer, FilterComparison> serviceId = Pair.create(widget.provider.id.uid, fc); 960 incrementAppWidgetServiceRefCount(appWidgetId, serviceId); 961 } 962 } 963 964 @Override 965 public void unbindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent) { 966 final int userId = UserHandle.getCallingUserId(); 967 968 if (DEBUG) { 969 Slog.i(TAG, "unbindRemoteViewsService() " + userId); 970 } 971 972 // Make sure the package runs under the caller uid. 973 mSecurityPolicy.enforceCallFromPackage(callingPackage); 974 975 synchronized (mLock) { 976 ensureGroupStateLoadedLocked(userId); 977 978 // Unbind from the RemoteViewsService (which will trigger a callback to the bound 979 // RemoteViewsAdapter) 980 Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, 981 new FilterComparison(intent)); 982 if (mBoundRemoteViewsServices.containsKey(key)) { 983 // We don't need to use the appWidgetId until after we are sure there is something 984 // to unbind. Note that this may mask certain issues with apps calling unbind() 985 // more than necessary. 986 987 // NOTE: The lookup is enforcing security across users by making 988 // sure the caller can only access widgets it hosts or provides. 989 Widget widget = lookupWidgetLocked(appWidgetId, 990 Binder.getCallingUid(), callingPackage); 991 992 if (widget == null) { 993 throw new IllegalArgumentException("Bad widget id " + appWidgetId); 994 } 995 996 ServiceConnectionProxy connection = (ServiceConnectionProxy) 997 mBoundRemoteViewsServices.get(key); 998 connection.disconnect(); 999 mContext.unbindService(connection); 1000 mBoundRemoteViewsServices.remove(key); 1001 } 1002 } 1003 } 1004 1005 @Override 1006 public void deleteHost(String callingPackage, int hostId) { 1007 final int userId = UserHandle.getCallingUserId(); 1008 1009 if (DEBUG) { 1010 Slog.i(TAG, "deleteHost() " + userId); 1011 } 1012 1013 // Make sure the package runs under the caller uid. 1014 mSecurityPolicy.enforceCallFromPackage(callingPackage); 1015 1016 synchronized (mLock) { 1017 ensureGroupStateLoadedLocked(userId); 1018 1019 // NOTE: The lookup is enforcing security across users by making 1020 // sure the caller can only access hosts in its uid and package. 1021 HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage); 1022 Host host = lookupHostLocked(id); 1023 1024 if (host == null) { 1025 return; 1026 } 1027 1028 deleteHostLocked(host); 1029 1030 saveGroupStateAsync(userId); 1031 1032 if (DEBUG) { 1033 Slog.i(TAG, "Deleted host " + host.id); 1034 } 1035 } 1036 } 1037 1038 @Override 1039 public void deleteAllHosts() { 1040 final int userId = UserHandle.getCallingUserId(); 1041 1042 if (DEBUG) { 1043 Slog.i(TAG, "deleteAllHosts() " + userId); 1044 } 1045 1046 synchronized (mLock) { 1047 ensureGroupStateLoadedLocked(userId); 1048 1049 boolean changed = false; 1050 1051 final int N = mHosts.size(); 1052 for (int i = N - 1; i >= 0; i--) { 1053 Host host = mHosts.get(i); 1054 1055 // Delete only hosts in the calling uid. 1056 if (host.id.uid == Binder.getCallingUid()) { 1057 deleteHostLocked(host); 1058 changed = true; 1059 1060 if (DEBUG) { 1061 Slog.i(TAG, "Deleted host " + host.id); 1062 } 1063 } 1064 } 1065 1066 if (changed) { 1067 saveGroupStateAsync(userId); 1068 } 1069 } 1070 } 1071 1072 @Override 1073 public AppWidgetProviderInfo getAppWidgetInfo(String callingPackage, int appWidgetId) { 1074 final int userId = UserHandle.getCallingUserId(); 1075 1076 if (DEBUG) { 1077 Slog.i(TAG, "getAppWidgetInfo() " + userId); 1078 } 1079 1080 // Make sure the package runs under the caller uid. 1081 mSecurityPolicy.enforceCallFromPackage(callingPackage); 1082 1083 synchronized (mLock) { 1084 ensureGroupStateLoadedLocked(userId); 1085 1086 // NOTE: The lookup is enforcing security across users by making 1087 // sure the caller can only access widgets it hosts or provides. 1088 Widget widget = lookupWidgetLocked(appWidgetId, 1089 Binder.getCallingUid(), callingPackage); 1090 1091 if (widget != null && widget.provider != null && !widget.provider.zombie) { 1092 return cloneIfLocalBinder(widget.provider.info); 1093 } 1094 1095 return null; 1096 } 1097 } 1098 1099 @Override 1100 public RemoteViews getAppWidgetViews(String callingPackage, int appWidgetId) { 1101 final int userId = UserHandle.getCallingUserId(); 1102 1103 if (DEBUG) { 1104 Slog.i(TAG, "getAppWidgetViews() " + userId); 1105 } 1106 1107 // Make sure the package runs under the caller uid. 1108 mSecurityPolicy.enforceCallFromPackage(callingPackage); 1109 1110 synchronized (mLock) { 1111 ensureGroupStateLoadedLocked(userId); 1112 1113 // NOTE: The lookup is enforcing security across users by making 1114 // sure the caller can only access widgets it hosts or provides. 1115 Widget widget = lookupWidgetLocked(appWidgetId, 1116 Binder.getCallingUid(), callingPackage); 1117 1118 if (widget != null) { 1119 return cloneIfLocalBinder(widget.views); 1120 } 1121 1122 return null; 1123 } 1124 } 1125 1126 @Override 1127 public void updateAppWidgetOptions(String callingPackage, int appWidgetId, Bundle options) { 1128 final int userId = UserHandle.getCallingUserId(); 1129 1130 if (DEBUG) { 1131 Slog.i(TAG, "updateAppWidgetOptions() " + userId); 1132 } 1133 1134 // Make sure the package runs under the caller uid. 1135 mSecurityPolicy.enforceCallFromPackage(callingPackage); 1136 1137 synchronized (mLock) { 1138 ensureGroupStateLoadedLocked(userId); 1139 1140 // NOTE: The lookup is enforcing security across users by making 1141 // sure the caller can only access widgets it hosts or provides. 1142 Widget widget = lookupWidgetLocked(appWidgetId, 1143 Binder.getCallingUid(), callingPackage); 1144 1145 if (widget == null) { 1146 return; 1147 } 1148 1149 // Merge the options. 1150 widget.options.putAll(options); 1151 1152 // Send the broacast to notify the provider that options changed. 1153 sendOptionsChangedIntentLocked(widget); 1154 1155 saveGroupStateAsync(userId); 1156 } 1157 } 1158 1159 @Override 1160 public Bundle getAppWidgetOptions(String callingPackage, int appWidgetId) { 1161 final int userId = UserHandle.getCallingUserId(); 1162 1163 if (DEBUG) { 1164 Slog.i(TAG, "getAppWidgetOptions() " + userId); 1165 } 1166 1167 // Make sure the package runs under the caller uid. 1168 mSecurityPolicy.enforceCallFromPackage(callingPackage); 1169 1170 synchronized (mLock) { 1171 ensureGroupStateLoadedLocked(userId); 1172 1173 // NOTE: The lookup is enforcing security across users by making 1174 // sure the caller can only access widgets it hosts or provides. 1175 Widget widget = lookupWidgetLocked(appWidgetId, 1176 Binder.getCallingUid(), callingPackage); 1177 1178 if (widget != null && widget.options != null) { 1179 return cloneIfLocalBinder(widget.options); 1180 } 1181 1182 return Bundle.EMPTY; 1183 } 1184 } 1185 1186 @Override 1187 public void updateAppWidgetIds(String callingPackage, int[] appWidgetIds, 1188 RemoteViews views) { 1189 if (DEBUG) { 1190 Slog.i(TAG, "updateAppWidgetIds() " + UserHandle.getCallingUserId()); 1191 } 1192 1193 updateAppWidgetIds(callingPackage, appWidgetIds, views, false); 1194 } 1195 1196 @Override 1197 public void partiallyUpdateAppWidgetIds(String callingPackage, int[] appWidgetIds, 1198 RemoteViews views) { 1199 if (DEBUG) { 1200 Slog.i(TAG, "partiallyUpdateAppWidgetIds() " + UserHandle.getCallingUserId()); 1201 } 1202 1203 updateAppWidgetIds(callingPackage, appWidgetIds, views, true); 1204 } 1205 1206 @Override 1207 public void notifyAppWidgetViewDataChanged(String callingPackage, int[] appWidgetIds, 1208 int viewId) { 1209 final int userId = UserHandle.getCallingUserId(); 1210 1211 if (DEBUG) { 1212 Slog.i(TAG, "notifyAppWidgetViewDataChanged() " + userId); 1213 } 1214 1215 // Make sure the package runs under the caller uid. 1216 mSecurityPolicy.enforceCallFromPackage(callingPackage); 1217 1218 if (appWidgetIds == null || appWidgetIds.length == 0) { 1219 return; 1220 } 1221 1222 synchronized (mLock) { 1223 ensureGroupStateLoadedLocked(userId); 1224 1225 final int N = appWidgetIds.length; 1226 for (int i = 0; i < N; i++) { 1227 final int appWidgetId = appWidgetIds[i]; 1228 1229 // NOTE: The lookup is enforcing security across users by making 1230 // sure the caller can only access widgets it hosts or provides. 1231 Widget widget = lookupWidgetLocked(appWidgetId, 1232 Binder.getCallingUid(), callingPackage); 1233 1234 if (widget != null) { 1235 scheduleNotifyAppWidgetViewDataChanged(widget, viewId); 1236 } 1237 } 1238 } 1239 } 1240 1241 @Override 1242 public void updateAppWidgetProvider(ComponentName componentName, RemoteViews views) { 1243 final int userId = UserHandle.getCallingUserId(); 1244 1245 if (DEBUG) { 1246 Slog.i(TAG, "updateAppWidgetProvider() " + userId); 1247 } 1248 1249 // Make sure the package runs under the caller uid. 1250 mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName()); 1251 1252 synchronized (mLock) { 1253 ensureGroupStateLoadedLocked(userId); 1254 1255 // NOTE: The lookup is enforcing security across users by making 1256 // sure the caller can access only its providers. 1257 ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName); 1258 Provider provider = lookupProviderLocked(providerId); 1259 1260 if (provider == null) { 1261 Slog.w(TAG, "Provider doesn't exist " + providerId); 1262 return; 1263 } 1264 1265 ArrayList<Widget> instances = provider.widgets; 1266 final int N = instances.size(); 1267 for (int i = 0; i < N; i++) { 1268 Widget widget = instances.get(i); 1269 updateAppWidgetInstanceLocked(widget, views, false); 1270 } 1271 } 1272 } 1273 1274 @Override 1275 public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, 1276 int profileId) { 1277 final int userId = UserHandle.getCallingUserId(); 1278 1279 if (DEBUG) { 1280 Slog.i(TAG, "getInstalledProvidersForProfiles() " + userId); 1281 } 1282 1283 // Ensure the profile is in the group and enabled. 1284 if (!mSecurityPolicy.isEnabledGroupProfile(profileId)) { 1285 return null; 1286 } 1287 1288 synchronized (mLock) { 1289 ensureGroupStateLoadedLocked(userId); 1290 1291 ArrayList<AppWidgetProviderInfo> result = null; 1292 1293 final int providerCount = mProviders.size(); 1294 for (int i = 0; i < providerCount; i++) { 1295 Provider provider = mProviders.get(i); 1296 AppWidgetProviderInfo info = provider.info; 1297 1298 // Ignore an invalid provider or one not matching the filter. 1299 if (provider.zombie || (info.widgetCategory & categoryFilter) == 0) { 1300 continue; 1301 } 1302 1303 // Add providers only for the requested profile that are white-listed. 1304 final int providerProfileId = info.getProfile().getIdentifier(); 1305 if (providerProfileId == profileId 1306 && mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed( 1307 provider.id.componentName.getPackageName(), providerProfileId)) { 1308 if (result == null) { 1309 result = new ArrayList<>(); 1310 } 1311 result.add(cloneIfLocalBinder(info)); 1312 } 1313 } 1314 1315 return result; 1316 } 1317 } 1318 1319 private void updateAppWidgetIds(String callingPackage, int[] appWidgetIds, 1320 RemoteViews views, boolean partially) { 1321 final int userId = UserHandle.getCallingUserId(); 1322 1323 if (appWidgetIds == null || appWidgetIds.length == 0) { 1324 return; 1325 } 1326 1327 // Make sure the package runs under the caller uid. 1328 mSecurityPolicy.enforceCallFromPackage(callingPackage); 1329 1330 final int bitmapMemoryUsage = (views != null) ? views.estimateMemoryUsage() : 0; 1331 if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) { 1332 throw new IllegalArgumentException("RemoteViews for widget update exceeds" 1333 + " maximum bitmap memory usage (used: " + bitmapMemoryUsage 1334 + ", max: " + mMaxWidgetBitmapMemory + ")"); 1335 } 1336 1337 synchronized (mLock) { 1338 ensureGroupStateLoadedLocked(userId); 1339 1340 final int N = appWidgetIds.length; 1341 for (int i = 0; i < N; i++) { 1342 final int appWidgetId = appWidgetIds[i]; 1343 1344 // NOTE: The lookup is enforcing security across users by making 1345 // sure the caller can only access widgets it hosts or provides. 1346 Widget widget = lookupWidgetLocked(appWidgetId, 1347 Binder.getCallingUid(), callingPackage); 1348 1349 if (widget != null) { 1350 updateAppWidgetInstanceLocked(widget, views, partially); 1351 } 1352 } 1353 } 1354 } 1355 1356 private int incrementAndGetAppWidgetIdLocked(int userId) { 1357 final int appWidgetId = peekNextAppWidgetIdLocked(userId) + 1; 1358 mNextAppWidgetIds.put(userId, appWidgetId); 1359 return appWidgetId; 1360 } 1361 1362 private void setMinAppWidgetIdLocked(int userId, int minWidgetId) { 1363 final int nextAppWidgetId = peekNextAppWidgetIdLocked(userId); 1364 if (nextAppWidgetId < minWidgetId) { 1365 mNextAppWidgetIds.put(userId, minWidgetId); 1366 } 1367 } 1368 1369 private int peekNextAppWidgetIdLocked(int userId) { 1370 if (mNextAppWidgetIds.indexOfKey(userId) < 0) { 1371 return AppWidgetManager.INVALID_APPWIDGET_ID + 1; 1372 } else { 1373 return mNextAppWidgetIds.get(userId); 1374 } 1375 } 1376 1377 private Host lookupOrAddHostLocked(HostId id) { 1378 Host host = lookupHostLocked(id); 1379 if (host != null) { 1380 return host; 1381 } 1382 1383 host = new Host(); 1384 host.id = id; 1385 mHosts.add(host); 1386 1387 return host; 1388 } 1389 1390 private void deleteHostLocked(Host host) { 1391 final int N = host.widgets.size(); 1392 for (int i = N - 1; i >= 0; i--) { 1393 Widget widget = host.widgets.remove(i); 1394 deleteAppWidgetLocked(widget); 1395 } 1396 mHosts.remove(host); 1397 1398 // it's gone or going away, abruptly drop the callback connection 1399 host.callbacks = null; 1400 } 1401 1402 private void deleteAppWidgetLocked(Widget widget) { 1403 // We first unbind all services that are bound to this id 1404 unbindAppWidgetRemoteViewsServicesLocked(widget); 1405 1406 Host host = widget.host; 1407 host.widgets.remove(widget); 1408 pruneHostLocked(host); 1409 1410 mWidgets.remove(widget); 1411 1412 Provider provider = widget.provider; 1413 if (provider != null) { 1414 provider.widgets.remove(widget); 1415 if (!provider.zombie) { 1416 // send the broacast saying that this appWidgetId has been deleted 1417 sendDeletedIntentLocked(widget); 1418 1419 if (provider.widgets.isEmpty()) { 1420 // cancel the future updates 1421 cancelBroadcasts(provider); 1422 1423 // send the broacast saying that the provider is not in use any more 1424 sendDisabledIntentLocked(provider); 1425 } 1426 } 1427 } 1428 } 1429 1430 private void cancelBroadcasts(Provider provider) { 1431 if (DEBUG) { 1432 Slog.i(TAG, "cancelBroadcasts() for " + provider); 1433 } 1434 if (provider.broadcast != null) { 1435 mAlarmManager.cancel(provider.broadcast); 1436 long token = Binder.clearCallingIdentity(); 1437 try { 1438 provider.broadcast.cancel(); 1439 } finally { 1440 Binder.restoreCallingIdentity(token); 1441 } 1442 provider.broadcast = null; 1443 } 1444 } 1445 1446 // Unbinds from a RemoteViewsService when we delete an app widget 1447 private void unbindAppWidgetRemoteViewsServicesLocked(Widget widget) { 1448 int appWidgetId = widget.appWidgetId; 1449 // Unbind all connections to Services bound to this AppWidgetId 1450 Iterator<Pair<Integer, Intent.FilterComparison>> it = mBoundRemoteViewsServices.keySet() 1451 .iterator(); 1452 while (it.hasNext()) { 1453 final Pair<Integer, Intent.FilterComparison> key = it.next(); 1454 if (key.first == appWidgetId) { 1455 final ServiceConnectionProxy conn = (ServiceConnectionProxy) 1456 mBoundRemoteViewsServices.get(key); 1457 conn.disconnect(); 1458 mContext.unbindService(conn); 1459 it.remove(); 1460 } 1461 } 1462 1463 // Check if we need to destroy any services (if no other app widgets are 1464 // referencing the same service) 1465 decrementAppWidgetServiceRefCount(widget); 1466 } 1467 1468 // Destroys the cached factory on the RemoteViewsService's side related to the specified intent 1469 private void destroyRemoteViewsService(final Intent intent, Widget widget) { 1470 final ServiceConnection conn = new ServiceConnection() { 1471 @Override 1472 public void onServiceConnected(ComponentName name, IBinder service) { 1473 final IRemoteViewsFactory cb = IRemoteViewsFactory.Stub.asInterface(service); 1474 try { 1475 cb.onDestroy(intent); 1476 } catch (RemoteException re) { 1477 Slog.e(TAG, "Error calling remove view factory", re); 1478 } 1479 mContext.unbindService(this); 1480 } 1481 1482 @Override 1483 public void onServiceDisconnected(ComponentName name) { 1484 // Do nothing 1485 } 1486 }; 1487 1488 // Bind to the service and remove the static intent->factory mapping in the 1489 // RemoteViewsService. 1490 final long token = Binder.clearCallingIdentity(); 1491 try { 1492 mContext.bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE, 1493 widget.provider.info.getProfile()); 1494 } finally { 1495 Binder.restoreCallingIdentity(token); 1496 } 1497 } 1498 1499 // Adds to the ref-count for a given RemoteViewsService intent 1500 private void incrementAppWidgetServiceRefCount(int appWidgetId, 1501 Pair<Integer, FilterComparison> serviceId) { 1502 HashSet<Integer> appWidgetIds = null; 1503 if (mRemoteViewsServicesAppWidgets.containsKey(serviceId)) { 1504 appWidgetIds = mRemoteViewsServicesAppWidgets.get(serviceId); 1505 } else { 1506 appWidgetIds = new HashSet<>(); 1507 mRemoteViewsServicesAppWidgets.put(serviceId, appWidgetIds); 1508 } 1509 appWidgetIds.add(appWidgetId); 1510 } 1511 1512 // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if 1513 // the ref-count reaches zero. 1514 private void decrementAppWidgetServiceRefCount(Widget widget) { 1515 Iterator<Pair<Integer, FilterComparison>> it = mRemoteViewsServicesAppWidgets 1516 .keySet().iterator(); 1517 while (it.hasNext()) { 1518 final Pair<Integer, FilterComparison> key = it.next(); 1519 final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key); 1520 if (ids.remove(widget.appWidgetId)) { 1521 // If we have removed the last app widget referencing this service, then we 1522 // should destroy it and remove it from this set 1523 if (ids.isEmpty()) { 1524 destroyRemoteViewsService(key.second.getIntent(), widget); 1525 it.remove(); 1526 } 1527 } 1528 } 1529 } 1530 1531 private void saveGroupStateAsync(int groupId) { 1532 mSaveStateHandler.post(new SaveStateRunnable(groupId)); 1533 } 1534 1535 private void updateAppWidgetInstanceLocked(Widget widget, RemoteViews views, 1536 boolean isPartialUpdate) { 1537 if (widget != null && widget.provider != null 1538 && !widget.provider.zombie && !widget.host.zombie) { 1539 1540 if (isPartialUpdate && widget.views != null) { 1541 // For a partial update, we merge the new RemoteViews with the old. 1542 widget.views.mergeRemoteViews(views); 1543 } else { 1544 // For a full update we replace the RemoteViews completely. 1545 widget.views = views; 1546 } 1547 1548 scheduleNotifyUpdateAppWidgetLocked(widget, views); 1549 } 1550 } 1551 1552 private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) { 1553 if (widget == null || widget.host == null || widget.host.zombie 1554 || widget.host.callbacks == null || widget.provider == null 1555 || widget.provider.zombie) { 1556 return; 1557 } 1558 1559 SomeArgs args = SomeArgs.obtain(); 1560 args.arg1 = widget.host; 1561 args.arg2 = widget.host.callbacks; 1562 args.argi1 = widget.appWidgetId; 1563 args.argi2 = viewId; 1564 1565 mCallbackHandler.obtainMessage( 1566 CallbackHandler.MSG_NOTIFY_VIEW_DATA_CHANGED, 1567 args).sendToTarget(); 1568 } 1569 1570 1571 private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks, 1572 int appWidgetId, int viewId) { 1573 try { 1574 callbacks.viewDataChanged(appWidgetId, viewId); 1575 } catch (RemoteException re) { 1576 // It failed; remove the callback. No need to prune because 1577 // we know that this host is still referenced by this instance. 1578 callbacks = null; 1579 } 1580 1581 // If the host is unavailable, then we call the associated 1582 // RemoteViewsFactory.onDataSetChanged() directly 1583 synchronized (mLock) { 1584 if (callbacks == null) { 1585 host.callbacks = null; 1586 1587 Set<Pair<Integer, FilterComparison>> keys = mRemoteViewsServicesAppWidgets.keySet(); 1588 for (Pair<Integer, FilterComparison> key : keys) { 1589 if (mRemoteViewsServicesAppWidgets.get(key).contains(appWidgetId)) { 1590 final ServiceConnection connection = new ServiceConnection() { 1591 @Override 1592 public void onServiceConnected(ComponentName name, IBinder service) { 1593 IRemoteViewsFactory cb = IRemoteViewsFactory.Stub 1594 .asInterface(service); 1595 try { 1596 cb.onDataSetChangedAsync(); 1597 } catch (RemoteException e) { 1598 Slog.e(TAG, "Error calling onDataSetChangedAsync()", e); 1599 } 1600 mContext.unbindService(this); 1601 } 1602 1603 @Override 1604 public void onServiceDisconnected(android.content.ComponentName name) { 1605 // Do nothing 1606 } 1607 }; 1608 1609 final int userId = UserHandle.getUserId(key.first); 1610 Intent intent = key.second.getIntent(); 1611 1612 // Bind to the service and call onDataSetChanged() 1613 bindService(intent, connection, new UserHandle(userId)); 1614 } 1615 } 1616 } 1617 } 1618 } 1619 1620 private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) { 1621 if (widget == null || widget.provider == null || widget.provider.zombie 1622 || widget.host.callbacks == null || widget.host.zombie) { 1623 return; 1624 } 1625 1626 SomeArgs args = SomeArgs.obtain(); 1627 args.arg1 = widget.host; 1628 args.arg2 = widget.host.callbacks; 1629 args.arg3 = updateViews; 1630 args.argi1 = widget.appWidgetId; 1631 1632 mCallbackHandler.obtainMessage( 1633 CallbackHandler.MSG_NOTIFY_UPDATE_APP_WIDGET, 1634 args).sendToTarget(); 1635 } 1636 1637 private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks, 1638 int appWidgetId, RemoteViews views) { 1639 try { 1640 callbacks.updateAppWidget(appWidgetId, views); 1641 } catch (RemoteException re) { 1642 synchronized (mLock) { 1643 Slog.e(TAG, "Widget host dead: " + host.id, re); 1644 host.callbacks = null; 1645 } 1646 } 1647 } 1648 1649 private void scheduleNotifyProviderChangedLocked(Widget widget) { 1650 if (widget == null || widget.provider == null || widget.provider.zombie 1651 || widget.host.callbacks == null || widget.host.zombie) { 1652 return; 1653 } 1654 1655 SomeArgs args = SomeArgs.obtain(); 1656 args.arg1 = widget.host; 1657 args.arg2 = widget.host.callbacks; 1658 args.arg3 = widget.provider.info; 1659 args.argi1 = widget.appWidgetId; 1660 1661 mCallbackHandler.obtainMessage( 1662 CallbackHandler.MSG_NOTIFY_PROVIDER_CHANGED, 1663 args).sendToTarget(); 1664 } 1665 1666 private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks, 1667 int appWidgetId, AppWidgetProviderInfo info) { 1668 try { 1669 callbacks.providerChanged(appWidgetId, info); 1670 } catch (RemoteException re) { 1671 synchronized (mLock){ 1672 Slog.e(TAG, "Widget host dead: " + host.id, re); 1673 host.callbacks = null; 1674 } 1675 } 1676 } 1677 1678 private void scheduleNotifyGroupHostsForProvidersChangedLocked(int userId) { 1679 final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId); 1680 1681 final int N = mHosts.size(); 1682 for (int i = N - 1; i >= 0; i--) { 1683 Host host = mHosts.get(i); 1684 1685 boolean hostInGroup = false; 1686 final int M = profileIds.length; 1687 for (int j = 0; j < M; j++) { 1688 final int profileId = profileIds[j]; 1689 if (host.getUserId() == profileId) { 1690 hostInGroup = true; 1691 break; 1692 } 1693 } 1694 1695 if (!hostInGroup) { 1696 continue; 1697 } 1698 1699 if (host == null || host.zombie || host.callbacks == null) { 1700 continue; 1701 } 1702 1703 SomeArgs args = SomeArgs.obtain(); 1704 args.arg1 = host; 1705 args.arg2 = host.callbacks; 1706 1707 mCallbackHandler.obtainMessage( 1708 CallbackHandler.MSG_NOTIFY_PROVIDERS_CHANGED, 1709 args).sendToTarget(); 1710 } 1711 } 1712 1713 private void handleNotifyProvidersChanged(Host host, IAppWidgetHost callbacks) { 1714 try { 1715 callbacks.providersChanged(); 1716 } catch (RemoteException re) { 1717 synchronized (mLock) { 1718 Slog.e(TAG, "Widget host dead: " + host.id, re); 1719 host.callbacks = null; 1720 } 1721 } 1722 } 1723 1724 private static boolean isLocalBinder() { 1725 return Process.myPid() == Binder.getCallingPid(); 1726 } 1727 1728 private static RemoteViews cloneIfLocalBinder(RemoteViews rv) { 1729 if (isLocalBinder() && rv != null) { 1730 return rv.clone(); 1731 } 1732 return rv; 1733 } 1734 1735 private static AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) { 1736 if (isLocalBinder() && info != null) { 1737 return info.clone(); 1738 } 1739 return info; 1740 } 1741 1742 private static Bundle cloneIfLocalBinder(Bundle bundle) { 1743 // Note: this is only a shallow copy. For now this will be fine, but it could be problematic 1744 // if we start adding objects to the options. Further, it would only be an issue if keyguard 1745 // used such options. 1746 if (isLocalBinder() && bundle != null) { 1747 return (Bundle) bundle.clone(); 1748 } 1749 return bundle; 1750 } 1751 1752 private Widget lookupWidgetLocked(int appWidgetId, int uid, String packageName) { 1753 final int N = mWidgets.size(); 1754 for (int i = 0; i < N; i++) { 1755 Widget widget = mWidgets.get(i); 1756 if (widget.appWidgetId == appWidgetId 1757 && mSecurityPolicy.canAccessAppWidget(widget, uid, packageName)) { 1758 return widget; 1759 } 1760 } 1761 return null; 1762 } 1763 1764 private Provider lookupProviderLocked(ProviderId id) { 1765 final int N = mProviders.size(); 1766 for (int i = 0; i < N; i++) { 1767 Provider provider = mProviders.get(i); 1768 if (provider.id.equals(id)) { 1769 return provider; 1770 } 1771 } 1772 return null; 1773 } 1774 1775 private Host lookupHostLocked(HostId hostId) { 1776 final int N = mHosts.size(); 1777 for (int i = 0; i < N; i++) { 1778 Host host = mHosts.get(i); 1779 if (host.id.equals(hostId)) { 1780 return host; 1781 } 1782 } 1783 return null; 1784 } 1785 1786 private void pruneHostLocked(Host host) { 1787 if (host.widgets.size() == 0 && host.callbacks == null) { 1788 if (DEBUG) { 1789 Slog.i(TAG, "Pruning host " + host.id); 1790 } 1791 mHosts.remove(host); 1792 } 1793 } 1794 1795 private void loadGroupWidgetProvidersLocked(int[] profileIds) { 1796 List<ResolveInfo> allReceivers = null; 1797 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1798 1799 final int profileCount = profileIds.length; 1800 for (int i = 0; i < profileCount; i++) { 1801 final int profileId = profileIds[i]; 1802 1803 List<ResolveInfo> receivers = queryIntentReceivers(intent, profileId); 1804 if (receivers != null && !receivers.isEmpty()) { 1805 if (allReceivers == null) { 1806 allReceivers = new ArrayList<>(); 1807 } 1808 allReceivers.addAll(receivers); 1809 } 1810 } 1811 1812 final int N = (allReceivers == null) ? 0 : allReceivers.size(); 1813 for (int i = 0; i < N; i++) { 1814 ResolveInfo receiver = allReceivers.get(i); 1815 addProviderLocked(receiver); 1816 } 1817 } 1818 1819 private boolean addProviderLocked(ResolveInfo ri) { 1820 if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 1821 return false; 1822 } 1823 1824 if (!ri.activityInfo.isEnabled()) { 1825 return false; 1826 } 1827 1828 ComponentName componentName = new ComponentName(ri.activityInfo.packageName, 1829 ri.activityInfo.name); 1830 ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName); 1831 1832 Provider provider = parseProviderInfoXml(providerId, ri); 1833 if (provider != null) { 1834 // we might have an inactive entry for this provider already due to 1835 // a preceding restore operation. if so, fix it up in place; otherwise 1836 // just add this new one. 1837 Provider existing = lookupProviderLocked(providerId); 1838 1839 // If the provider was not found it may be because it was restored and 1840 // we did not know its UID so let us find if there is such one. 1841 if (existing == null) { 1842 providerId = new ProviderId(UNKNOWN_UID, componentName); 1843 existing = lookupProviderLocked(providerId); 1844 } 1845 1846 if (existing != null) { 1847 if (existing.zombie && !mSafeMode) { 1848 // it's a placeholder that was set up during an app restore 1849 existing.zombie = false; 1850 existing.info = provider.info; // the real one filled out from the ResolveInfo 1851 if (DEBUG) { 1852 Slog.i(TAG, "Provider placeholder now reified: " + existing); 1853 } 1854 } 1855 } else { 1856 mProviders.add(provider); 1857 } 1858 return true; 1859 } 1860 1861 return false; 1862 } 1863 1864 private void deleteProviderLocked(Provider provider) { 1865 int N = provider.widgets.size(); 1866 for (int i = N - 1; i >= 0; i--) { 1867 Widget widget = provider.widgets.remove(i); 1868 // Call back with empty RemoteViews 1869 updateAppWidgetInstanceLocked(widget, null, false); 1870 // clear out references to this appWidgetId 1871 widget.host.widgets.remove(widget); 1872 mWidgets.remove(widget); 1873 widget.provider = null; 1874 pruneHostLocked(widget.host); 1875 widget.host = null; 1876 } 1877 mProviders.remove(provider); 1878 1879 // no need to send the DISABLE broadcast, since the receiver is gone anyway 1880 cancelBroadcasts(provider); 1881 } 1882 1883 private void sendEnableIntentLocked(Provider p) { 1884 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); 1885 intent.setComponent(p.info.provider); 1886 sendBroadcastAsUser(intent, p.info.getProfile()); 1887 } 1888 1889 private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds) { 1890 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1891 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 1892 intent.setComponent(provider.info.provider); 1893 sendBroadcastAsUser(intent, provider.info.getProfile()); 1894 } 1895 1896 private void sendDeletedIntentLocked(Widget widget) { 1897 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); 1898 intent.setComponent(widget.provider.info.provider); 1899 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId); 1900 sendBroadcastAsUser(intent, widget.provider.info.getProfile()); 1901 } 1902 1903 private void sendDisabledIntentLocked(Provider provider) { 1904 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); 1905 intent.setComponent(provider.info.provider); 1906 sendBroadcastAsUser(intent, provider.info.getProfile()); 1907 } 1908 1909 public void sendOptionsChangedIntentLocked(Widget widget) { 1910 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED); 1911 intent.setComponent(widget.provider.info.provider); 1912 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId); 1913 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, widget.options); 1914 sendBroadcastAsUser(intent, widget.provider.info.getProfile()); 1915 } 1916 1917 private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) { 1918 if (provider.info.updatePeriodMillis > 0) { 1919 // if this is the first instance, set the alarm. otherwise, 1920 // rely on the fact that we've already set it and that 1921 // PendingIntent.getBroadcast will update the extras. 1922 boolean alreadyRegistered = provider.broadcast != null; 1923 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1924 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 1925 intent.setComponent(provider.info.provider); 1926 long token = Binder.clearCallingIdentity(); 1927 try { 1928 provider.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent, 1929 PendingIntent.FLAG_UPDATE_CURRENT, provider.info.getProfile()); 1930 } finally { 1931 Binder.restoreCallingIdentity(token); 1932 } 1933 if (!alreadyRegistered) { 1934 long period = provider.info.updatePeriodMillis; 1935 if (period < MIN_UPDATE_PERIOD) { 1936 period = MIN_UPDATE_PERIOD; 1937 } 1938 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1939 SystemClock.elapsedRealtime() + period, period, provider.broadcast); 1940 } 1941 } 1942 } 1943 1944 private static int[] getWidgetIds(ArrayList<Widget> widgets) { 1945 int instancesSize = widgets.size(); 1946 int appWidgetIds[] = new int[instancesSize]; 1947 for (int i = 0; i < instancesSize; i++) { 1948 appWidgetIds[i] = widgets.get(i).appWidgetId; 1949 } 1950 return appWidgetIds; 1951 } 1952 1953 private static void dumpProvider(Provider provider, int index, PrintWriter pw) { 1954 AppWidgetProviderInfo info = provider.info; 1955 pw.print(" ["); pw.print(index); pw.print("] provider "); 1956 pw.println(provider.id); 1957 pw.print(" min=("); pw.print(info.minWidth); 1958 pw.print("x"); pw.print(info.minHeight); 1959 pw.print(") minResize=("); pw.print(info.minResizeWidth); 1960 pw.print("x"); pw.print(info.minResizeHeight); 1961 pw.print(") updatePeriodMillis="); 1962 pw.print(info.updatePeriodMillis); 1963 pw.print(" resizeMode="); 1964 pw.print(info.resizeMode); 1965 pw.print(info.widgetCategory); 1966 pw.print(" autoAdvanceViewId="); 1967 pw.print(info.autoAdvanceViewId); 1968 pw.print(" initialLayout=#"); 1969 pw.print(Integer.toHexString(info.initialLayout)); 1970 pw.print(" initialKeyguardLayout=#"); 1971 pw.print(Integer.toHexString(info.initialKeyguardLayout)); 1972 pw.print(" zombie="); pw.println(provider.zombie); 1973 } 1974 1975 private static void dumpHost(Host host, int index, PrintWriter pw) { 1976 pw.print(" ["); pw.print(index); pw.print("] hostId="); 1977 pw.println(host.id); 1978 pw.print(" callbacks="); pw.println(host.callbacks); 1979 pw.print(" widgets.size="); pw.print(host.widgets.size()); 1980 pw.print(" zombie="); pw.println(host.zombie); 1981 } 1982 1983 private static void dumpGrant(Pair<Integer, String> grant, int index, PrintWriter pw) { 1984 pw.print(" ["); pw.print(index); pw.print(']'); 1985 pw.print(" user="); pw.print(grant.first); 1986 pw.print(" package="); pw.println(grant.second); 1987 } 1988 1989 private static void dumpWidget(Widget widget, int index, PrintWriter pw) { 1990 pw.print(" ["); pw.print(index); pw.print("] id="); 1991 pw.println(widget.appWidgetId); 1992 pw.print(" host="); 1993 pw.println(widget.host.id); 1994 if (widget.provider != null) { 1995 pw.print(" provider="); pw.println(widget.provider.id); 1996 } 1997 if (widget.host != null) { 1998 pw.print(" host.callbacks="); pw.println(widget.host.callbacks); 1999 } 2000 if (widget.views != null) { 2001 pw.print(" views="); pw.println(widget.views); 2002 } 2003 } 2004 2005 private static void serializeProvider(XmlSerializer out, Provider p) throws IOException { 2006 out.startTag(null, "p"); 2007 out.attribute(null, "pkg", p.info.provider.getPackageName()); 2008 out.attribute(null, "cl", p.info.provider.getClassName()); 2009 out.attribute(null, "tag", Integer.toHexString(p.tag)); 2010 out.endTag(null, "p"); 2011 } 2012 2013 private static void serializeHost(XmlSerializer out, Host host) throws IOException { 2014 out.startTag(null, "h"); 2015 out.attribute(null, "pkg", host.id.packageName); 2016 out.attribute(null, "id", Integer.toHexString(host.id.hostId)); 2017 out.attribute(null, "tag", Integer.toHexString(host.tag)); 2018 out.endTag(null, "h"); 2019 } 2020 2021 private static void serializeAppWidget(XmlSerializer out, Widget widget) throws IOException { 2022 out.startTag(null, "g"); 2023 out.attribute(null, "id", Integer.toHexString(widget.appWidgetId)); 2024 out.attribute(null, "rid", Integer.toHexString(widget.restoredId)); 2025 out.attribute(null, "h", Integer.toHexString(widget.host.tag)); 2026 if (widget.provider != null) { 2027 out.attribute(null, "p", Integer.toHexString(widget.provider.tag)); 2028 } 2029 if (widget.options != null) { 2030 out.attribute(null, "min_width", Integer.toHexString(widget.options.getInt( 2031 AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH))); 2032 out.attribute(null, "min_height", Integer.toHexString(widget.options.getInt( 2033 AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT))); 2034 out.attribute(null, "max_width", Integer.toHexString(widget.options.getInt( 2035 AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH))); 2036 out.attribute(null, "max_height", Integer.toHexString(widget.options.getInt( 2037 AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT))); 2038 out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt( 2039 AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))); 2040 } 2041 out.endTag(null, "g"); 2042 } 2043 2044 @Override 2045 public List<String> getWidgetParticipants(int userId) { 2046 return mBackupRestoreController.getWidgetParticipants(userId); 2047 } 2048 2049 @Override 2050 public byte[] getWidgetState(String packageName, int userId) { 2051 return mBackupRestoreController.getWidgetState(packageName, userId); 2052 } 2053 2054 @Override 2055 public void restoreStarting(int userId) { 2056 mBackupRestoreController.restoreStarting(userId); 2057 } 2058 2059 @Override 2060 public void restoreWidgetState(String packageName, byte[] restoredState, int userId) { 2061 mBackupRestoreController.restoreWidgetState(packageName, restoredState, userId); 2062 } 2063 2064 @Override 2065 public void restoreFinished(int userId) { 2066 mBackupRestoreController.restoreFinished(userId); 2067 } 2068 2069 @SuppressWarnings("deprecation") 2070 private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri) { 2071 Provider provider = null; 2072 2073 ActivityInfo activityInfo = ri.activityInfo; 2074 XmlResourceParser parser = null; 2075 try { 2076 parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(), 2077 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); 2078 if (parser == null) { 2079 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER 2080 + " meta-data for " + "AppWidget provider '" + providerId + '\''); 2081 return null; 2082 } 2083 2084 AttributeSet attrs = Xml.asAttributeSet(parser); 2085 2086 int type; 2087 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2088 && type != XmlPullParser.START_TAG) { 2089 // drain whitespace, comments, etc. 2090 } 2091 2092 String nodeName = parser.getName(); 2093 if (!"appwidget-provider".equals(nodeName)) { 2094 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for" 2095 + " AppWidget provider " + providerId.componentName 2096 + " for user " + providerId.uid); 2097 return null; 2098 } 2099 2100 provider = new Provider(); 2101 provider.id = providerId; 2102 AppWidgetProviderInfo info = provider.info = new AppWidgetProviderInfo(); 2103 info.provider = providerId.componentName; 2104 info.providerInfo = activityInfo; 2105 2106 final Resources resources; 2107 final long identity = Binder.clearCallingIdentity(); 2108 try { 2109 resources = mContext.getPackageManager() 2110 .getResourcesForApplicationAsUser(activityInfo.packageName, 2111 UserHandle.getUserId(providerId.uid)); 2112 } finally { 2113 Binder.restoreCallingIdentity(identity); 2114 } 2115 2116 TypedArray sa = resources.obtainAttributes(attrs, 2117 com.android.internal.R.styleable.AppWidgetProviderInfo); 2118 2119 // These dimensions has to be resolved in the application's context. 2120 // We simply send back the raw complex data, which will be 2121 // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}. 2122 TypedValue value = sa 2123 .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth); 2124 info.minWidth = value != null ? value.data : 0; 2125 value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight); 2126 info.minHeight = value != null ? value.data : 0; 2127 value = sa.peekValue( 2128 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth); 2129 info.minResizeWidth = value != null ? value.data : info.minWidth; 2130 value = sa.peekValue( 2131 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight); 2132 info.minResizeHeight = value != null ? value.data : info.minHeight; 2133 info.updatePeriodMillis = sa.getInt( 2134 com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0); 2135 info.initialLayout = sa.getResourceId( 2136 com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0); 2137 info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable. 2138 AppWidgetProviderInfo_initialKeyguardLayout, 0); 2139 2140 String className = sa 2141 .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure); 2142 if (className != null) { 2143 info.configure = new ComponentName(providerId.componentName.getPackageName(), 2144 className); 2145 } 2146 info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString(); 2147 info.icon = ri.getIconResource(); 2148 info.previewImage = sa.getResourceId( 2149 com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); 2150 info.autoAdvanceViewId = sa.getResourceId( 2151 com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1); 2152 info.resizeMode = sa.getInt( 2153 com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode, 2154 AppWidgetProviderInfo.RESIZE_NONE); 2155 info.widgetCategory = sa.getInt( 2156 com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory, 2157 AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); 2158 2159 sa.recycle(); 2160 } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) { 2161 // Ok to catch Exception here, because anything going wrong because 2162 // of what a client process passes to us should not be fatal for the 2163 // system process. 2164 Slog.w(TAG, "XML parsing failed for AppWidget provider " 2165 + providerId.componentName + " for user " + providerId.uid, e); 2166 return null; 2167 } finally { 2168 if (parser != null) { 2169 parser.close(); 2170 } 2171 } 2172 return provider; 2173 } 2174 2175 private int getUidForPackage(String packageName, int userId) { 2176 PackageInfo pkgInfo = null; 2177 2178 final long identity = Binder.clearCallingIdentity(); 2179 try { 2180 pkgInfo = mPackageManager.getPackageInfo(packageName, 0, userId); 2181 } catch (RemoteException re) { 2182 // Shouldn't happen, local call 2183 } finally { 2184 Binder.restoreCallingIdentity(identity); 2185 } 2186 2187 if (pkgInfo == null || pkgInfo.applicationInfo == null) { 2188 return -1; 2189 } 2190 2191 return pkgInfo.applicationInfo.uid; 2192 } 2193 2194 private ActivityInfo getProviderInfo(ComponentName componentName, int userId) { 2195 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 2196 intent.setComponent(componentName); 2197 2198 List<ResolveInfo> receivers = queryIntentReceivers(intent, userId); 2199 // We are setting component, so there is only one or none. 2200 if (!receivers.isEmpty()) { 2201 return receivers.get(0).activityInfo; 2202 } 2203 2204 return null; 2205 } 2206 2207 private List<ResolveInfo> queryIntentReceivers(Intent intent, int userId) { 2208 final long identity = Binder.clearCallingIdentity(); 2209 try { 2210 return mPackageManager.queryIntentReceivers(intent, 2211 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 2212 PackageManager.GET_META_DATA, userId); 2213 } catch (RemoteException re) { 2214 return Collections.emptyList(); 2215 } finally { 2216 Binder.restoreCallingIdentity(identity); 2217 } 2218 } 2219 2220 private void onUserStarted(int userId) { 2221 synchronized (mLock) { 2222 ensureGroupStateLoadedLocked(userId); 2223 2224 final int N = mProviders.size(); 2225 for (int i = 0; i < N; i++) { 2226 Provider provider = mProviders.get(i); 2227 2228 // Send broadcast only to the providers of the user. 2229 if (provider.getUserId() != userId) { 2230 continue; 2231 } 2232 2233 if (provider.widgets.size() > 0) { 2234 sendEnableIntentLocked(provider); 2235 int[] appWidgetIds = getWidgetIds(provider.widgets); 2236 sendUpdateIntentLocked(provider, appWidgetIds); 2237 registerForBroadcastsLocked(provider, appWidgetIds); 2238 } 2239 } 2240 } 2241 } 2242 2243 // only call from initialization -- it assumes that the data structures are all empty 2244 private void loadGroupStateLocked(int[] profileIds) { 2245 // We can bind the widgets to host and providers only after 2246 // reading the host and providers for all users since a widget 2247 // can have a host and a provider in different users. 2248 List<LoadedWidgetState> loadedWidgets = new ArrayList<>(); 2249 2250 int version = 0; 2251 2252 final int profileIdCount = profileIds.length; 2253 for (int i = 0; i < profileIdCount; i++) { 2254 final int profileId = profileIds[i]; 2255 2256 // No file written for this user - nothing to do. 2257 AtomicFile file = getSavedStateFile(profileId); 2258 try { 2259 FileInputStream stream = file.openRead(); 2260 version = readProfileStateFromFileLocked(stream, profileId, loadedWidgets); 2261 IoUtils.closeQuietly(stream); 2262 } catch (FileNotFoundException e) { 2263 Slog.w(TAG, "Failed to read state: " + e); 2264 } 2265 } 2266 2267 if (version >= 0) { 2268 // Hooke'm up... 2269 bindLoadedWidgets(loadedWidgets); 2270 2271 // upgrade the database if needed 2272 performUpgradeLocked(version); 2273 } else { 2274 // failed reading, clean up 2275 Slog.w(TAG, "Failed to read state, clearing widgets and hosts."); 2276 mWidgets.clear(); 2277 mHosts.clear(); 2278 final int N = mProviders.size(); 2279 for (int i = 0; i < N; i++) { 2280 mProviders.get(i).widgets.clear(); 2281 } 2282 } 2283 } 2284 2285 private void bindLoadedWidgets(List<LoadedWidgetState> loadedWidgets) { 2286 final int loadedWidgetCount = loadedWidgets.size(); 2287 for (int i = loadedWidgetCount - 1; i >= 0; i--) { 2288 LoadedWidgetState loadedWidget = loadedWidgets.remove(i); 2289 Widget widget = loadedWidget.widget; 2290 2291 widget.provider = findProviderByTag(loadedWidget.providerTag); 2292 if (widget.provider == null) { 2293 // This provider is gone. We just let the host figure out 2294 // that this happened when it fails to load it. 2295 continue; 2296 } 2297 2298 widget.host = findHostByTag(loadedWidget.hostTag); 2299 if (widget.host == null) { 2300 // This host is gone. 2301 continue; 2302 } 2303 2304 widget.provider.widgets.add(widget); 2305 widget.host.widgets.add(widget); 2306 mWidgets.add(widget); 2307 } 2308 } 2309 2310 private Provider findProviderByTag(int tag) { 2311 if (tag < 0) { 2312 return null; 2313 } 2314 final int providerCount = mProviders.size(); 2315 for (int i = 0; i < providerCount; i++) { 2316 Provider provider = mProviders.get(i); 2317 if (provider.tag == tag) { 2318 return provider; 2319 } 2320 } 2321 return null; 2322 } 2323 2324 private Host findHostByTag(int tag) { 2325 if (tag < 0) { 2326 return null; 2327 } 2328 final int hostCount = mHosts.size(); 2329 for (int i = 0; i < hostCount; i++) { 2330 Host host = mHosts.get(i); 2331 if (host.tag == tag) { 2332 return host; 2333 } 2334 } 2335 return null; 2336 } 2337 2338 private void saveStateLocked(int userId) { 2339 tagProvidersAndHosts(); 2340 2341 final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId); 2342 2343 final int profileCount = profileIds.length; 2344 for (int i = 0; i < profileCount; i++) { 2345 final int profileId = profileIds[i]; 2346 2347 AtomicFile file = getSavedStateFile(profileId); 2348 FileOutputStream stream; 2349 try { 2350 stream = file.startWrite(); 2351 if (writeProfileStateToFileLocked(stream, profileId)) { 2352 file.finishWrite(stream); 2353 } else { 2354 file.failWrite(stream); 2355 Slog.w(TAG, "Failed to save state, restoring backup."); 2356 } 2357 } catch (IOException e) { 2358 Slog.w(TAG, "Failed open state file for write: " + e); 2359 } 2360 } 2361 } 2362 2363 private void tagProvidersAndHosts() { 2364 final int providerCount = mProviders.size(); 2365 for (int i = 0; i < providerCount; i++) { 2366 Provider provider = mProviders.get(i); 2367 provider.tag = i; 2368 } 2369 2370 final int hostCount = mHosts.size(); 2371 for (int i = 0; i < hostCount; i++) { 2372 Host host = mHosts.get(i); 2373 host.tag = i; 2374 } 2375 } 2376 2377 private boolean writeProfileStateToFileLocked(FileOutputStream stream, int userId) { 2378 int N; 2379 2380 try { 2381 XmlSerializer out = new FastXmlSerializer(); 2382 out.setOutput(stream, "utf-8"); 2383 out.startDocument(null, true); 2384 out.startTag(null, "gs"); 2385 out.attribute(null, "version", String.valueOf(CURRENT_VERSION)); 2386 2387 N = mProviders.size(); 2388 for (int i = 0; i < N; i++) { 2389 Provider provider = mProviders.get(i); 2390 // Save only providers for the user. 2391 if (provider.getUserId() != userId) { 2392 continue; 2393 } 2394 if (provider.widgets.size() > 0) { 2395 serializeProvider(out, provider); 2396 } 2397 } 2398 2399 N = mHosts.size(); 2400 for (int i = 0; i < N; i++) { 2401 Host host = mHosts.get(i); 2402 // Save only hosts for the user. 2403 if (host.getUserId() != userId) { 2404 continue; 2405 } 2406 serializeHost(out, host); 2407 } 2408 2409 N = mWidgets.size(); 2410 for (int i = 0; i < N; i++) { 2411 Widget widget = mWidgets.get(i); 2412 // Save only widgets hosted by the user. 2413 if (widget.host.getUserId() != userId) { 2414 continue; 2415 } 2416 serializeAppWidget(out, widget); 2417 } 2418 2419 Iterator<Pair<Integer, String>> it = mPackagesWithBindWidgetPermission.iterator(); 2420 while (it.hasNext()) { 2421 Pair<Integer, String> binding = it.next(); 2422 // Save only white listings for the user. 2423 if (binding.first != userId) { 2424 continue; 2425 } 2426 out.startTag(null, "b"); 2427 out.attribute(null, "packageName", binding.second); 2428 out.endTag(null, "b"); 2429 } 2430 2431 out.endTag(null, "gs"); 2432 out.endDocument(); 2433 return true; 2434 } catch (IOException e) { 2435 Slog.w(TAG, "Failed to write state: " + e); 2436 return false; 2437 } 2438 } 2439 2440 private int readProfileStateFromFileLocked(FileInputStream stream, int userId, 2441 List<LoadedWidgetState> outLoadedWidgets) { 2442 int version = -1; 2443 try { 2444 XmlPullParser parser = Xml.newPullParser(); 2445 parser.setInput(stream, null); 2446 2447 int legacyProviderIndex = -1; 2448 int legacyHostIndex = -1; 2449 int type; 2450 do { 2451 type = parser.next(); 2452 if (type == XmlPullParser.START_TAG) { 2453 String tag = parser.getName(); 2454 if ("gs".equals(tag)) { 2455 String attributeValue = parser.getAttributeValue(null, "version"); 2456 try { 2457 version = Integer.parseInt(attributeValue); 2458 } catch (NumberFormatException e) { 2459 version = 0; 2460 } 2461 } else if ("p".equals(tag)) { 2462 legacyProviderIndex++; 2463 // TODO: do we need to check that this package has the same signature 2464 // as before? 2465 String pkg = parser.getAttributeValue(null, "pkg"); 2466 String cl = parser.getAttributeValue(null, "cl"); 2467 2468 pkg = getCanonicalPackageName(pkg, cl, userId); 2469 if (pkg == null) { 2470 continue; 2471 } 2472 2473 final int uid = getUidForPackage(pkg, userId); 2474 if (uid < 0) { 2475 continue; 2476 } 2477 2478 ComponentName componentName = new ComponentName(pkg, cl); 2479 2480 ActivityInfo providerInfo = getProviderInfo(componentName, userId); 2481 if (providerInfo == null) { 2482 continue; 2483 } 2484 2485 ProviderId providerId = new ProviderId(uid, componentName); 2486 Provider provider = lookupProviderLocked(providerId); 2487 2488 if (provider == null && mSafeMode) { 2489 // if we're in safe mode, make a temporary one 2490 provider = new Provider(); 2491 provider.info = new AppWidgetProviderInfo(); 2492 provider.info.provider = providerId.componentName; 2493 provider.info.providerInfo = providerInfo; 2494 provider.zombie = true; 2495 provider.id = providerId; 2496 mProviders.add(provider); 2497 } 2498 2499 String tagAttribute = parser.getAttributeValue(null, "tag"); 2500 final int providerTag = !TextUtils.isEmpty(tagAttribute) 2501 ? Integer.parseInt(tagAttribute, 16) : legacyProviderIndex; 2502 provider.tag = providerTag; 2503 } else if ("h".equals(tag)) { 2504 legacyHostIndex++; 2505 Host host = new Host(); 2506 // TODO: do we need to check that this package has the same signature 2507 // as before? 2508 String pkg = parser.getAttributeValue(null, "pkg"); 2509 2510 final int uid = getUidForPackage(pkg, userId); 2511 if (uid < 0) { 2512 host.zombie = true; 2513 } 2514 2515 if (!host.zombie || mSafeMode) { 2516 // In safe mode, we don't discard the hosts we don't recognize 2517 // so that they're not pruned from our list. Otherwise, we do. 2518 final int hostId = Integer.parseInt(parser.getAttributeValue( 2519 null, "id"), 16); 2520 2521 String tagAttribute = parser.getAttributeValue(null, "tag"); 2522 final int hostTag = !TextUtils.isEmpty(tagAttribute) 2523 ? Integer.parseInt(tagAttribute, 16) : legacyHostIndex; 2524 2525 host.tag = hostTag; 2526 host.id = new HostId(uid, hostId, pkg); 2527 mHosts.add(host); 2528 } 2529 } else if ("b".equals(tag)) { 2530 String packageName = parser.getAttributeValue(null, "packageName"); 2531 final int uid = getUidForPackage(packageName, userId); 2532 if (uid >= 0) { 2533 Pair<Integer, String> packageId = Pair.create(userId, packageName); 2534 mPackagesWithBindWidgetPermission.add(packageId); 2535 } 2536 } else if ("g".equals(tag)) { 2537 Widget widget = new Widget(); 2538 widget.appWidgetId = Integer.parseInt(parser.getAttributeValue( 2539 null, "id"), 16); 2540 setMinAppWidgetIdLocked(userId, widget.appWidgetId + 1); 2541 2542 // restored ID is allowed to be absent 2543 String restoredIdString = parser.getAttributeValue(null, "rid"); 2544 widget.restoredId = (restoredIdString == null) ? 0 2545 : Integer.parseInt(restoredIdString, 16); 2546 2547 Bundle options = new Bundle(); 2548 String minWidthString = parser.getAttributeValue(null, "min_width"); 2549 if (minWidthString != null) { 2550 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 2551 Integer.parseInt(minWidthString, 16)); 2552 } 2553 String minHeightString = parser.getAttributeValue(null, "min_height"); 2554 if (minHeightString != null) { 2555 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 2556 Integer.parseInt(minHeightString, 16)); 2557 } 2558 String maxWidthString = parser.getAttributeValue(null, "max_width"); 2559 if (maxWidthString != null) { 2560 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 2561 Integer.parseInt(maxWidthString, 16)); 2562 } 2563 String maxHeightString = parser.getAttributeValue(null, "max_height"); 2564 if (maxHeightString != null) { 2565 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 2566 Integer.parseInt(maxHeightString, 16)); 2567 } 2568 String categoryString = parser.getAttributeValue(null, "host_category"); 2569 if (categoryString != null) { 2570 options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 2571 Integer.parseInt(categoryString, 16)); 2572 } 2573 widget.options = options; 2574 2575 final int hostTag = Integer.parseInt(parser.getAttributeValue( 2576 null, "h"), 16); 2577 String providerString = parser.getAttributeValue(null, "p"); 2578 final int providerTag = (providerString != null) ? Integer.parseInt( 2579 parser.getAttributeValue(null, "p"), 16) : TAG_UNDEFINED; 2580 2581 // We can match widgets with hosts and providers only after hosts 2582 // and providers for all users have been loaded since the widget 2583 // host and provider can be in different user profiles. 2584 LoadedWidgetState loadedWidgets = new LoadedWidgetState(widget, 2585 hostTag, providerTag); 2586 outLoadedWidgets.add(loadedWidgets); 2587 } 2588 } 2589 } while (type != XmlPullParser.END_DOCUMENT); 2590 } catch (NullPointerException 2591 | NumberFormatException 2592 | XmlPullParserException 2593 | IOException 2594 | IndexOutOfBoundsException e) { 2595 Slog.w(TAG, "failed parsing " + e); 2596 return -1; 2597 } 2598 2599 return version; 2600 } 2601 2602 private void performUpgradeLocked(int fromVersion) { 2603 if (fromVersion < CURRENT_VERSION) { 2604 Slog.v(TAG, "Upgrading widget database from " + fromVersion + " to " 2605 + CURRENT_VERSION); 2606 } 2607 2608 int version = fromVersion; 2609 2610 // Update 1: keyguard moved from package "android" to "com.android.keyguard" 2611 if (version == 0) { 2612 HostId oldHostId = new HostId(Process.myUid(), 2613 KEYGUARD_HOST_ID, OLD_KEYGUARD_HOST_PACKAGE); 2614 2615 Host host = lookupHostLocked(oldHostId); 2616 if (host != null) { 2617 final int uid = getUidForPackage(NEW_KEYGUARD_HOST_PACKAGE, 2618 UserHandle.USER_OWNER); 2619 if (uid >= 0) { 2620 host.id = new HostId(uid, KEYGUARD_HOST_ID, NEW_KEYGUARD_HOST_PACKAGE); 2621 } 2622 } 2623 2624 version = 1; 2625 } 2626 2627 if (version != CURRENT_VERSION) { 2628 throw new IllegalStateException("Failed to upgrade widget database"); 2629 } 2630 } 2631 2632 private static File getStateFile(int userId) { 2633 return new File(Environment.getUserSystemDirectory(userId), STATE_FILENAME); 2634 } 2635 2636 private static AtomicFile getSavedStateFile(int userId) { 2637 File dir = Environment.getUserSystemDirectory(userId); 2638 File settingsFile = getStateFile(userId); 2639 if (!settingsFile.exists() && userId == UserHandle.USER_OWNER) { 2640 if (!dir.exists()) { 2641 dir.mkdirs(); 2642 } 2643 // Migrate old data 2644 File oldFile = new File("/data/system/" + STATE_FILENAME); 2645 // Method doesn't throw an exception on failure. Ignore any errors 2646 // in moving the file (like non-existence) 2647 oldFile.renameTo(settingsFile); 2648 } 2649 return new AtomicFile(settingsFile); 2650 } 2651 2652 private void onUserStopped(int userId) { 2653 synchronized (mLock) { 2654 boolean providersChanged = false; 2655 boolean crossProfileWidgetsChanged = false; 2656 2657 // Remove widgets that have both host and provider in the user. 2658 final int widgetCount = mWidgets.size(); 2659 for (int i = widgetCount - 1; i >= 0; i--) { 2660 Widget widget = mWidgets.get(i); 2661 2662 final boolean hostInUser = widget.host.getUserId() == userId; 2663 final boolean hasProvider = widget.provider != null; 2664 final boolean providerInUser = hasProvider && widget.provider.getUserId() == userId; 2665 2666 // If both host and provider are in the user, just drop the widgets 2667 // as we do not want to make host callbacks and provider broadcasts 2668 // as the host and the provider will be killed. 2669 if (hostInUser && (!hasProvider || providerInUser)) { 2670 mWidgets.remove(i); 2671 widget.host.widgets.remove(widget); 2672 widget.host = null; 2673 if (hasProvider) { 2674 widget.provider.widgets.remove(widget); 2675 widget.provider = null; 2676 } 2677 } 2678 } 2679 2680 // Remove hosts and notify providers in other profiles. 2681 final int hostCount = mHosts.size(); 2682 for (int i = hostCount - 1; i >= 0; i--) { 2683 Host host = mHosts.get(i); 2684 if (host.getUserId() == userId) { 2685 crossProfileWidgetsChanged |= !host.widgets.isEmpty(); 2686 deleteHostLocked(host); 2687 } 2688 } 2689 2690 // Remove the providers and notify hosts in other profiles. 2691 final int providerCount = mProviders.size(); 2692 for (int i = providerCount - 1; i >= 0; i--) { 2693 Provider provider = mProviders.get(i); 2694 if (provider.getUserId() == userId) { 2695 crossProfileWidgetsChanged |= !provider.widgets.isEmpty(); 2696 providersChanged = true; 2697 deleteProviderLocked(provider); 2698 } 2699 } 2700 2701 // Remove grants for this user. 2702 final int grantCount = mPackagesWithBindWidgetPermission.size(); 2703 for (int i = grantCount - 1; i >= 0; i--) { 2704 Pair<Integer, String> packageId = mPackagesWithBindWidgetPermission.valueAt(i); 2705 if (packageId.first == userId) { 2706 mPackagesWithBindWidgetPermission.removeAt(i); 2707 } 2708 } 2709 2710 // Take a note we no longer have state for this user. 2711 final int userIndex = mLoadedUserIds.indexOfKey(userId); 2712 if (userIndex >= 0) { 2713 mLoadedUserIds.removeAt(userIndex); 2714 } 2715 2716 // Remove the widget id counter. 2717 final int nextIdIndex = mNextAppWidgetIds.indexOfKey(userId); 2718 if (nextIdIndex >= 0) { 2719 mNextAppWidgetIds.removeAt(nextIdIndex); 2720 } 2721 2722 // Announce removed provider changes to all hosts in the group. 2723 if (providersChanged) { 2724 scheduleNotifyGroupHostsForProvidersChangedLocked(userId); 2725 } 2726 2727 // Save state if removing a profile changed the group state. 2728 // Nothing will be saved if the group parent was removed. 2729 if (crossProfileWidgetsChanged) { 2730 saveGroupStateAsync(userId); 2731 } 2732 } 2733 } 2734 2735 /** 2736 * Updates all providers with the specified package names, and records any providers that were 2737 * pruned. 2738 * 2739 * @return whether any providers were updated 2740 */ 2741 private boolean updateProvidersForPackageLocked(String packageName, int userId, 2742 Set<ProviderId> removedProviders) { 2743 boolean providersUpdated = false; 2744 2745 HashSet<ProviderId> keep = new HashSet<>(); 2746 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 2747 intent.setPackage(packageName); 2748 List<ResolveInfo> broadcastReceivers = queryIntentReceivers(intent, userId); 2749 2750 // add the missing ones and collect which ones to keep 2751 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 2752 for (int i = 0; i < N; i++) { 2753 ResolveInfo ri = broadcastReceivers.get(i); 2754 ActivityInfo ai = ri.activityInfo; 2755 2756 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 2757 continue; 2758 } 2759 2760 if (packageName.equals(ai.packageName)) { 2761 ProviderId providerId = new ProviderId(ai.applicationInfo.uid, 2762 new ComponentName(ai.packageName, ai.name)); 2763 2764 Provider provider = lookupProviderLocked(providerId); 2765 if (provider == null) { 2766 if (addProviderLocked(ri)) { 2767 keep.add(providerId); 2768 providersUpdated = true; 2769 } 2770 } else { 2771 Provider parsed = parseProviderInfoXml(providerId, ri); 2772 if (parsed != null) { 2773 keep.add(providerId); 2774 // Use the new AppWidgetProviderInfo. 2775 provider.info = parsed.info; 2776 // If it's enabled 2777 final int M = provider.widgets.size(); 2778 if (M > 0) { 2779 int[] appWidgetIds = getWidgetIds(provider.widgets); 2780 // Reschedule for the new updatePeriodMillis (don't worry about handling 2781 // it specially if updatePeriodMillis didn't change because we just sent 2782 // an update, and the next one will be updatePeriodMillis from now). 2783 cancelBroadcasts(provider); 2784 registerForBroadcastsLocked(provider, appWidgetIds); 2785 // If it's currently showing, call back with the new 2786 // AppWidgetProviderInfo. 2787 for (int j = 0; j < M; j++) { 2788 Widget widget = provider.widgets.get(j); 2789 widget.views = null; 2790 scheduleNotifyProviderChangedLocked(widget); 2791 } 2792 // Now that we've told the host, push out an update. 2793 sendUpdateIntentLocked(provider, appWidgetIds); 2794 providersUpdated = true; 2795 } 2796 } 2797 } 2798 } 2799 } 2800 2801 // prune the ones we don't want to keep 2802 N = mProviders.size(); 2803 for (int i = N - 1; i >= 0; i--) { 2804 Provider provider = mProviders.get(i); 2805 if (packageName.equals(provider.info.provider.getPackageName()) 2806 && provider.getUserId() == userId 2807 && !keep.contains(provider.id)) { 2808 if (removedProviders != null) { 2809 removedProviders.add(provider.id); 2810 } 2811 deleteProviderLocked(provider); 2812 providersUpdated = true; 2813 } 2814 } 2815 2816 return providersUpdated; 2817 } 2818 2819 private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) { 2820 boolean removed = false; 2821 2822 int N = mProviders.size(); 2823 for (int i = N - 1; i >= 0; i--) { 2824 Provider provider = mProviders.get(i); 2825 if (pkgName.equals(provider.info.provider.getPackageName()) 2826 && provider.getUserId() == userId) { 2827 deleteProviderLocked(provider); 2828 removed = true; 2829 } 2830 } 2831 2832 // Delete the hosts for this package too 2833 // By now, we have removed any AppWidgets that were in any hosts here, 2834 // so we don't need to worry about sending DISABLE broadcasts to them. 2835 N = mHosts.size(); 2836 for (int i = N - 1; i >= 0; i--) { 2837 Host host = mHosts.get(i); 2838 if (pkgName.equals(host.id.packageName) 2839 && host.getUserId() == userId) { 2840 deleteHostLocked(host); 2841 removed = true; 2842 } 2843 } 2844 2845 return removed; 2846 } 2847 2848 private String getCanonicalPackageName(String packageName, String className, int userId) { 2849 final long identity = Binder.clearCallingIdentity(); 2850 try { 2851 try { 2852 AppGlobals.getPackageManager().getReceiverInfo(new ComponentName(packageName, 2853 className), 0, userId); 2854 return packageName; 2855 } catch (RemoteException re) { 2856 String[] packageNames = mContext.getPackageManager() 2857 .currentToCanonicalPackageNames(new String[]{packageName}); 2858 if (packageNames != null && packageNames.length > 0) { 2859 return packageNames[0]; 2860 } 2861 } 2862 } finally { 2863 Binder.restoreCallingIdentity(identity); 2864 } 2865 return null; 2866 } 2867 2868 private void sendBroadcastAsUser(Intent intent, UserHandle userHandle) { 2869 final long identity = Binder.clearCallingIdentity(); 2870 try { 2871 mContext.sendBroadcastAsUser(intent, userHandle); 2872 } finally { 2873 Binder.restoreCallingIdentity(identity); 2874 } 2875 } 2876 2877 private void bindService(Intent intent, ServiceConnection connection, 2878 UserHandle userHandle) { 2879 final long token = Binder.clearCallingIdentity(); 2880 try { 2881 mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE, 2882 userHandle); 2883 } finally { 2884 Binder.restoreCallingIdentity(token); 2885 } 2886 } 2887 2888 private void unbindService(ServiceConnection connection) { 2889 final long token = Binder.clearCallingIdentity(); 2890 try { 2891 mContext.unbindService(connection); 2892 } finally { 2893 Binder.restoreCallingIdentity(token); 2894 } 2895 } 2896 2897 @Override 2898 public void onCrossProfileWidgetProvidersChanged(int userId, List<String> packages) { 2899 final int parentId = mSecurityPolicy.getProfileParent(userId); 2900 // We care only if the white-listed package is in a profile of 2901 // the group parent as only the parent can add widgets from the 2902 // profile and not the other way around. 2903 if (parentId != userId) { 2904 synchronized (mLock) { 2905 boolean providersChanged = false; 2906 2907 final int packageCount = packages.size(); 2908 for (int i = 0; i < packageCount; i++) { 2909 String packageName = packages.get(i); 2910 providersChanged |= updateProvidersForPackageLocked(packageName, 2911 userId, null); 2912 } 2913 2914 if (providersChanged) { 2915 saveGroupStateAsync(userId); 2916 scheduleNotifyGroupHostsForProvidersChangedLocked(userId); 2917 } 2918 } 2919 } 2920 } 2921 2922 private final class CallbackHandler extends Handler { 2923 public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1; 2924 public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2; 2925 public static final int MSG_NOTIFY_PROVIDERS_CHANGED = 3; 2926 public static final int MSG_NOTIFY_VIEW_DATA_CHANGED = 4; 2927 2928 public CallbackHandler(Looper looper) { 2929 super(looper, null, false); 2930 } 2931 2932 @Override 2933 public void handleMessage(Message message) { 2934 switch (message.what) { 2935 case MSG_NOTIFY_UPDATE_APP_WIDGET: { 2936 SomeArgs args = (SomeArgs) message.obj; 2937 Host host = (Host) args.arg1; 2938 IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; 2939 RemoteViews views = (RemoteViews) args.arg3; 2940 final int appWidgetId = args.argi1; 2941 args.recycle(); 2942 2943 handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views); 2944 } break; 2945 2946 case MSG_NOTIFY_PROVIDER_CHANGED: { 2947 SomeArgs args = (SomeArgs) message.obj; 2948 Host host = (Host) args.arg1; 2949 IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; 2950 AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3; 2951 final int appWidgetId = args.argi1; 2952 args.recycle(); 2953 2954 handleNotifyProviderChanged(host, callbacks, appWidgetId, info); 2955 } break; 2956 2957 case MSG_NOTIFY_PROVIDERS_CHANGED: { 2958 SomeArgs args = (SomeArgs) message.obj; 2959 Host host = (Host) args.arg1; 2960 IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; 2961 args.recycle(); 2962 2963 handleNotifyProvidersChanged(host, callbacks); 2964 } break; 2965 2966 case MSG_NOTIFY_VIEW_DATA_CHANGED: { 2967 SomeArgs args = (SomeArgs) message.obj; 2968 Host host = (Host) args.arg1; 2969 IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; 2970 final int appWidgetId = args.argi1; 2971 final int viewId = args.argi2; 2972 args.recycle(); 2973 2974 handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId); 2975 } break; 2976 } 2977 } 2978 } 2979 2980 private final class SecurityPolicy { 2981 2982 public boolean isEnabledGroupProfile(int profileId) { 2983 final int parentId = UserHandle.getCallingUserId(); 2984 return isParentOrProfile(parentId, profileId) && isProfileEnabled(profileId); 2985 } 2986 2987 public int[] getEnabledGroupProfileIds(int userId) { 2988 final int parentId = getGroupParent(userId); 2989 2990 final List<UserInfo> profiles; 2991 final long identity = Binder.clearCallingIdentity(); 2992 try { 2993 profiles = mUserManager.getProfiles(parentId); 2994 } finally { 2995 Binder.restoreCallingIdentity(identity); 2996 } 2997 2998 int enabledProfileCount = 0; 2999 final int profileCount = profiles.size(); 3000 for (int i = 0; i < profileCount; i++) { 3001 if (profiles.get(i).isEnabled()) { 3002 enabledProfileCount++; 3003 } 3004 } 3005 3006 int enabledProfileIndex = 0; 3007 final int[] profileIds = new int[enabledProfileCount]; 3008 for (int i = 0; i < profileCount; i++) { 3009 UserInfo profile = profiles.get(i); 3010 if (profile.isEnabled()) { 3011 profileIds[enabledProfileIndex] = profile.getUserHandle().getIdentifier(); 3012 enabledProfileIndex++; 3013 } 3014 } 3015 3016 return profileIds; 3017 } 3018 3019 public void enforceServiceExistsAndRequiresBindRemoteViewsPermission( 3020 ComponentName componentName, int userId) { 3021 final long identity = Binder.clearCallingIdentity(); 3022 try { 3023 ServiceInfo serviceInfo = mPackageManager.getServiceInfo(componentName, 3024 PackageManager.GET_PERMISSIONS, userId); 3025 if (serviceInfo == null) { 3026 throw new SecurityException("Service " + componentName 3027 + " not installed for user " + userId); 3028 } 3029 if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(serviceInfo.permission)) { 3030 throw new SecurityException("Service " + componentName 3031 + " in user " + userId + "does not require " 3032 + android.Manifest.permission.BIND_REMOTEVIEWS); 3033 } 3034 } catch (RemoteException re) { 3035 // Local call - shouldn't happen. 3036 } finally { 3037 Binder.restoreCallingIdentity(identity); 3038 } 3039 } 3040 3041 public void enforceModifyAppWidgetBindPermissions(String packageName) { 3042 mContext.enforceCallingPermission( 3043 android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS, 3044 "hasBindAppWidgetPermission packageName=" + packageName); 3045 } 3046 3047 public void enforceCallFromPackage(String packageName) { 3048 mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); 3049 } 3050 3051 public boolean hasCallerBindPermissionOrBindWhiteListedLocked(String packageName) { 3052 try { 3053 mContext.enforceCallingOrSelfPermission( 3054 android.Manifest.permission.BIND_APPWIDGET, null); 3055 } catch (SecurityException se) { 3056 if (!isCallerBindAppWidgetWhiteListedLocked(packageName)) { 3057 return false; 3058 } 3059 } 3060 return true; 3061 } 3062 3063 private boolean isCallerBindAppWidgetWhiteListedLocked(String packageName) { 3064 final int userId = UserHandle.getCallingUserId(); 3065 final int packageUid = getUidForPackage(packageName, userId); 3066 if (packageUid < 0) { 3067 throw new IllegalArgumentException("No package " + packageName 3068 + " for user " + userId); 3069 } 3070 synchronized (mLock) { 3071 ensureGroupStateLoadedLocked(userId); 3072 3073 Pair<Integer, String> packageId = Pair.create(userId, packageName); 3074 if (mPackagesWithBindWidgetPermission.contains(packageId)) { 3075 return true; 3076 } 3077 } 3078 3079 return false; 3080 } 3081 3082 public boolean canAccessAppWidget(Widget widget, int uid, String packageName) { 3083 if (isHostInPackageForUid(widget.host, uid, packageName)) { 3084 // Apps hosting the AppWidget have access to it. 3085 return true; 3086 } 3087 if (isProviderInPackageForUid(widget.provider, uid, packageName)) { 3088 // Apps providing the AppWidget have access to it. 3089 return true; 3090 } 3091 if (isHostAccessingProvider(widget.host, widget.provider, uid, packageName)) { 3092 // Apps hosting the AppWidget get to bind to a remote view service in the provider. 3093 return true; 3094 } 3095 final int userId = UserHandle.getUserId(uid); 3096 if ((widget.host.getUserId() == userId || (widget.provider != null 3097 && widget.provider.getUserId() == userId)) 3098 && mContext.checkCallingPermission(android.Manifest.permission.BIND_APPWIDGET) 3099 == PackageManager.PERMISSION_GRANTED) { 3100 // Apps that run in the same user as either the host or the provider and 3101 // have the bind widget permission have access to the widget. 3102 return true; 3103 } 3104 return false; 3105 } 3106 3107 private boolean isParentOrProfile(int parentId, int profileId) { 3108 if (parentId == profileId) { 3109 return true; 3110 } 3111 return getProfileParent(profileId) == parentId; 3112 } 3113 3114 public boolean isProviderInCallerOrInProfileAndWhitelListed(String packageName, 3115 int profileId) { 3116 final int callerId = UserHandle.getCallingUserId(); 3117 if (profileId == callerId) { 3118 return true; 3119 } 3120 final int parentId = getProfileParent(profileId); 3121 if (parentId != callerId) { 3122 return false; 3123 } 3124 return isProviderWhitelListed(packageName, profileId); 3125 } 3126 3127 public boolean isProviderWhitelListed(String packageName, int profileId) { 3128 DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService( 3129 DevicePolicyManagerInternal.class); 3130 3131 // If the policy manager is not available on the device we deny it all. 3132 if (devicePolicyManager == null) { 3133 return false; 3134 } 3135 3136 List<String> crossProfilePackages = devicePolicyManager 3137 .getCrossProfileWidgetProviders(profileId); 3138 3139 return crossProfilePackages.contains(packageName); 3140 } 3141 3142 public int getProfileParent(int profileId) { 3143 final long identity = Binder.clearCallingIdentity(); 3144 try { 3145 UserInfo parent = mUserManager.getProfileParent(profileId); 3146 if (parent != null) { 3147 return parent.getUserHandle().getIdentifier(); 3148 } 3149 } finally { 3150 Binder.restoreCallingIdentity(identity); 3151 } 3152 return UNKNOWN_USER_ID; 3153 } 3154 3155 public int getGroupParent(int profileId) { 3156 final int parentId = mSecurityPolicy.getProfileParent(profileId); 3157 return (parentId != UNKNOWN_USER_ID) ? parentId : profileId; 3158 } 3159 3160 public boolean isHostInPackageForUid(Host host, int uid, String packageName) { 3161 return host.id.uid == uid && host.id.packageName.equals(packageName); 3162 } 3163 3164 public boolean isProviderInPackageForUid(Provider provider, int uid, 3165 String packageName) { 3166 // Packages providing the AppWidget have access to it. 3167 return provider != null && provider.id.uid == uid 3168 && provider.id.componentName.getPackageName().equals(packageName); 3169 } 3170 3171 public boolean isHostAccessingProvider(Host host, Provider provider, int uid, 3172 String packageName) { 3173 // The host creates a package context to bind to remote views service in the provider. 3174 return host.id.uid == uid && provider != null 3175 && provider.id.componentName.getPackageName().equals(packageName); 3176 } 3177 3178 private boolean isProfileEnabled(int profileId) { 3179 final long identity = Binder.clearCallingIdentity(); 3180 try { 3181 UserInfo userInfo = mUserManager.getUserInfo(profileId); 3182 if (userInfo == null || !userInfo.isEnabled()) { 3183 return false; 3184 } 3185 } finally { 3186 Binder.restoreCallingIdentity(identity); 3187 } 3188 return true; 3189 } 3190 } 3191 3192 private static final class Provider { 3193 ProviderId id; 3194 AppWidgetProviderInfo info; 3195 ArrayList<Widget> widgets = new ArrayList<>(); 3196 PendingIntent broadcast; 3197 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 3198 3199 int tag = TAG_UNDEFINED; // for use while saving state (the index) 3200 3201 public int getUserId() { 3202 return UserHandle.getUserId(id.uid); 3203 } 3204 3205 public boolean isInPackageForUser(String packageName, int userId) { 3206 return getUserId() == userId 3207 && id.componentName.getPackageName().equals(packageName); 3208 } 3209 3210 // is there an instance of this provider hosted by the given app? 3211 public boolean hostedByPackageForUser(String packageName, int userId) { 3212 final int N = widgets.size(); 3213 for (int i = 0; i < N; i++) { 3214 Widget widget = widgets.get(i); 3215 if (packageName.equals(widget.host.id.packageName) 3216 && widget.host.getUserId() == userId) { 3217 return true; 3218 } 3219 } 3220 return false; 3221 } 3222 3223 @Override 3224 public String toString() { 3225 return "Provider{" + id + (zombie ? " Z" : "") + '}'; 3226 } 3227 } 3228 3229 private static final class ProviderId { 3230 final int uid; 3231 final ComponentName componentName; 3232 3233 private ProviderId(int uid, ComponentName componentName) { 3234 this.uid = uid; 3235 this.componentName = componentName; 3236 } 3237 3238 @Override 3239 public boolean equals(Object obj) { 3240 if (this == obj) { 3241 return true; 3242 } 3243 if (obj == null) { 3244 return false; 3245 } 3246 if (getClass() != obj.getClass()) { 3247 return false; 3248 } 3249 ProviderId other = (ProviderId) obj; 3250 if (uid != other.uid) { 3251 return false; 3252 } 3253 if (componentName == null) { 3254 if (other.componentName != null) { 3255 return false; 3256 } 3257 } else if (!componentName.equals(other.componentName)) { 3258 return false; 3259 } 3260 return true; 3261 } 3262 3263 @Override 3264 public int hashCode() { 3265 int result = uid; 3266 result = 31 * result + ((componentName != null) 3267 ? componentName.hashCode() : 0); 3268 return result; 3269 } 3270 3271 @Override 3272 public String toString() { 3273 return "ProviderId{user:" + UserHandle.getUserId(uid) + ", app:" 3274 + UserHandle.getAppId(uid) + ", cmp:" + componentName + '}'; 3275 } 3276 } 3277 3278 private static final class Host { 3279 HostId id; 3280 ArrayList<Widget> widgets = new ArrayList<>(); 3281 IAppWidgetHost callbacks; 3282 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 3283 3284 int tag = TAG_UNDEFINED; // for use while saving state (the index) 3285 3286 public int getUserId() { 3287 return UserHandle.getUserId(id.uid); 3288 } 3289 3290 public boolean isInPackageForUser(String packageName, int userId) { 3291 return getUserId() == userId && id.packageName.equals(packageName); 3292 } 3293 3294 private boolean hostsPackageForUser(String pkg, int userId) { 3295 final int N = widgets.size(); 3296 for (int i = 0; i < N; i++) { 3297 Provider provider = widgets.get(i).provider; 3298 if (provider != null && provider.getUserId() == userId && provider.info != null 3299 && pkg.equals(provider.info.provider.getPackageName())) { 3300 return true; 3301 } 3302 } 3303 return false; 3304 } 3305 3306 @Override 3307 public String toString() { 3308 return "Host{" + id + (zombie ? " Z" : "") + '}'; 3309 } 3310 } 3311 3312 private static final class HostId { 3313 final int uid; 3314 final int hostId; 3315 final String packageName; 3316 3317 public HostId(int uid, int hostId, String packageName) { 3318 this.uid = uid; 3319 this.hostId = hostId; 3320 this.packageName = packageName; 3321 } 3322 3323 @Override 3324 public boolean equals(Object obj) { 3325 if (this == obj) { 3326 return true; 3327 } 3328 if (obj == null) { 3329 return false; 3330 } 3331 if (getClass() != obj.getClass()) { 3332 return false; 3333 } 3334 HostId other = (HostId) obj; 3335 if (uid != other.uid) { 3336 return false; 3337 } 3338 if (hostId != other.hostId) { 3339 return false; 3340 } 3341 if (packageName == null) { 3342 if (other.packageName != null) { 3343 return false; 3344 } 3345 } else if (!packageName.equals(other.packageName)) { 3346 return false; 3347 } 3348 return true; 3349 } 3350 3351 @Override 3352 public int hashCode() { 3353 int result = uid; 3354 result = 31 * result + hostId; 3355 result = 31 * result + ((packageName != null) 3356 ? packageName.hashCode() : 0); 3357 return result; 3358 } 3359 3360 @Override 3361 public String toString() { 3362 return "HostId{user:" + UserHandle.getUserId(uid) + ", app:" 3363 + UserHandle.getAppId(uid) + ", hostId:" + hostId 3364 + ", pkg:" + packageName + '}'; 3365 } 3366 } 3367 3368 private static final class Widget { 3369 int appWidgetId; 3370 int restoredId; // tracking & remapping any restored state 3371 Provider provider; 3372 RemoteViews views; 3373 Bundle options; 3374 Host host; 3375 3376 @Override 3377 public String toString() { 3378 return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}'; 3379 } 3380 } 3381 3382 /** 3383 * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This 3384 * needs to be a static inner class since a reference to the ServiceConnection is held globally 3385 * and may lead us to leak AppWidgetService instances (if there were more than one). 3386 */ 3387 private static final class ServiceConnectionProxy implements ServiceConnection { 3388 private final IRemoteViewsAdapterConnection mConnectionCb; 3389 3390 ServiceConnectionProxy(IBinder connectionCb) { 3391 mConnectionCb = IRemoteViewsAdapterConnection.Stub 3392 .asInterface(connectionCb); 3393 } 3394 3395 public void onServiceConnected(ComponentName name, IBinder service) { 3396 try { 3397 mConnectionCb.onServiceConnected(service); 3398 } catch (RemoteException re) { 3399 Slog.e(TAG, "Error passing service interface", re); 3400 } 3401 } 3402 3403 public void onServiceDisconnected(ComponentName name) { 3404 disconnect(); 3405 } 3406 3407 public void disconnect() { 3408 try { 3409 mConnectionCb.onServiceDisconnected(); 3410 } catch (RemoteException re) { 3411 Slog.e(TAG, "Error clearing service interface", re); 3412 } 3413 } 3414 } 3415 3416 private class LoadedWidgetState { 3417 final Widget widget; 3418 final int hostTag; 3419 final int providerTag; 3420 3421 public LoadedWidgetState(Widget widget, int hostTag, int providerTag) { 3422 this.widget = widget; 3423 this.hostTag = hostTag; 3424 this.providerTag = providerTag; 3425 } 3426 } 3427 3428 private final class SaveStateRunnable implements Runnable { 3429 final int mUserId; 3430 3431 public SaveStateRunnable(int userId) { 3432 mUserId = userId; 3433 } 3434 3435 @Override 3436 public void run() { 3437 synchronized (mLock) { 3438 ensureGroupStateLoadedLocked(mUserId); 3439 saveStateLocked(mUserId); 3440 } 3441 } 3442 } 3443 3444 /** 3445 * This class encapsulates the backup and restore logic for a user group state. 3446 */ 3447 private final class BackupRestoreController { 3448 private static final String TAG = "BackupRestoreController"; 3449 3450 private static final boolean DEBUG = true; 3451 3452 // Version of backed-up widget state. 3453 private static final int WIDGET_STATE_VERSION = 2; 3454 3455 // We need to make sure to wipe the pre-restore widget state only once for 3456 // a given package. Keep track of what we've done so far here; the list is 3457 // cleared at the start of every system restore pass, but preserved through 3458 // any install-time restore operations. 3459 private final HashSet<String> mPrunedApps = new HashSet<>(); 3460 3461 private final HashMap<Provider, ArrayList<RestoreUpdateRecord>> mUpdatesByProvider = 3462 new HashMap<>(); 3463 private final HashMap<Host, ArrayList<RestoreUpdateRecord>> mUpdatesByHost = 3464 new HashMap<>(); 3465 3466 public List<String> getWidgetParticipants(int userId) { 3467 if (DEBUG) { 3468 Slog.i(TAG, "Getting widget participants for user: " + userId); 3469 } 3470 3471 HashSet<String> packages = new HashSet<>(); 3472 synchronized (mLock) { 3473 final int N = mWidgets.size(); 3474 for (int i = 0; i < N; i++) { 3475 Widget widget = mWidgets.get(i); 3476 3477 // Skip cross-user widgets. 3478 if (!isProviderAndHostInUser(widget, userId)) { 3479 continue; 3480 } 3481 3482 packages.add(widget.host.id.packageName); 3483 Provider provider = widget.provider; 3484 if (provider != null) { 3485 packages.add(provider.id.componentName.getPackageName()); 3486 } 3487 } 3488 } 3489 return new ArrayList<>(packages); 3490 } 3491 3492 public byte[] getWidgetState(String backedupPackage, int userId) { 3493 if (DEBUG) { 3494 Slog.i(TAG, "Getting widget state for user: " + userId); 3495 } 3496 3497 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 3498 synchronized (mLock) { 3499 // Preflight: if this app neither hosts nor provides any live widgets 3500 // we have no work to do. 3501 if (!packageNeedsWidgetBackupLocked(backedupPackage, userId)) { 3502 return null; 3503 } 3504 3505 try { 3506 XmlSerializer out = new FastXmlSerializer(); 3507 out.setOutput(stream, "utf-8"); 3508 out.startDocument(null, true); 3509 out.startTag(null, "ws"); // widget state 3510 out.attribute(null, "version", String.valueOf(WIDGET_STATE_VERSION)); 3511 out.attribute(null, "pkg", backedupPackage); 3512 3513 // Remember all the providers that are currently hosted or published 3514 // by this package: that is, all of the entities related to this app 3515 // which will need to be told about id remapping. 3516 int index = 0; 3517 int N = mProviders.size(); 3518 for (int i = 0; i < N; i++) { 3519 Provider provider = mProviders.get(i); 3520 3521 if (!provider.widgets.isEmpty() 3522 && (provider.isInPackageForUser(backedupPackage, userId) 3523 || provider.hostedByPackageForUser(backedupPackage, userId))) { 3524 provider.tag = index; 3525 serializeProvider(out, provider); 3526 index++; 3527 } 3528 } 3529 3530 N = mHosts.size(); 3531 index = 0; 3532 for (int i = 0; i < N; i++) { 3533 Host host = mHosts.get(i); 3534 3535 if (!host.widgets.isEmpty() 3536 && (host.isInPackageForUser(backedupPackage, userId) 3537 || host.hostsPackageForUser(backedupPackage, userId))) { 3538 host.tag = index; 3539 serializeHost(out, host); 3540 index++; 3541 } 3542 } 3543 3544 // All widget instances involving this package, 3545 // either as host or as provider 3546 N = mWidgets.size(); 3547 for (int i = 0; i < N; i++) { 3548 Widget widget = mWidgets.get(i); 3549 3550 Provider provider = widget.provider; 3551 if (widget.host.isInPackageForUser(backedupPackage, userId) 3552 || (provider != null 3553 && provider.isInPackageForUser(backedupPackage, userId))) { 3554 serializeAppWidget(out, widget); 3555 } 3556 } 3557 3558 out.endTag(null, "ws"); 3559 out.endDocument(); 3560 } catch (IOException e) { 3561 Slog.w(TAG, "Unable to save widget state for " + backedupPackage); 3562 return null; 3563 } 3564 } 3565 3566 return stream.toByteArray(); 3567 } 3568 3569 public void restoreStarting(int userId) { 3570 if (DEBUG) { 3571 Slog.i(TAG, "Restore starting for user: " + userId); 3572 } 3573 3574 synchronized (mLock) { 3575 // We're starting a new "system" restore operation, so any widget restore 3576 // state that we see from here on is intended to replace the current 3577 // widget configuration of any/all of the affected apps. 3578 mPrunedApps.clear(); 3579 mUpdatesByProvider.clear(); 3580 mUpdatesByHost.clear(); 3581 } 3582 } 3583 3584 public void restoreWidgetState(String packageName, byte[] restoredState, int userId) { 3585 if (DEBUG) { 3586 Slog.i(TAG, "Restoring widget state for user:" + userId 3587 + " package: " + packageName); 3588 } 3589 3590 ByteArrayInputStream stream = new ByteArrayInputStream(restoredState); 3591 try { 3592 // Providers mentioned in the widget dataset by ordinal 3593 ArrayList<Provider> restoredProviders = new ArrayList<>(); 3594 3595 // Hosts mentioned in the widget dataset by ordinal 3596 ArrayList<Host> restoredHosts = new ArrayList<>(); 3597 3598 XmlPullParser parser = Xml.newPullParser(); 3599 parser.setInput(stream, null); 3600 3601 synchronized (mLock) { 3602 int type; 3603 do { 3604 type = parser.next(); 3605 if (type == XmlPullParser.START_TAG) { 3606 final String tag = parser.getName(); 3607 if ("ws".equals(tag)) { 3608 String version = parser.getAttributeValue(null, "version"); 3609 3610 final int versionNumber = Integer.parseInt(version); 3611 if (versionNumber > WIDGET_STATE_VERSION) { 3612 Slog.w(TAG, "Unable to process state version " + version); 3613 return; 3614 } 3615 3616 // TODO: fix up w.r.t. canonical vs current package names 3617 String pkg = parser.getAttributeValue(null, "pkg"); 3618 if (!packageName.equals(pkg)) { 3619 Slog.w(TAG, "Package mismatch in ws"); 3620 return; 3621 } 3622 } else if ("p".equals(tag)) { 3623 String pkg = parser.getAttributeValue(null, "pkg"); 3624 String cl = parser.getAttributeValue(null, "cl"); 3625 3626 // hostedProviders index will match 'p' attribute in widget's 3627 // entry in the xml file being restored 3628 // If there's no live entry for this provider, add an inactive one 3629 // so that widget IDs referring to them can be properly allocated 3630 3631 // Backup and resotre only for the parent profile. 3632 ComponentName componentName = new ComponentName(pkg, cl); 3633 3634 Provider p = findProviderLocked(componentName, userId); 3635 if (p == null) { 3636 p = new Provider(); 3637 p.id = new ProviderId(UNKNOWN_UID, componentName); 3638 p.info = new AppWidgetProviderInfo(); 3639 p.info.provider = componentName; 3640 p.zombie = true; 3641 mProviders.add(p); 3642 } 3643 if (DEBUG) { 3644 Slog.i(TAG, " provider " + p.id); 3645 } 3646 restoredProviders.add(p); 3647 } else if ("h".equals(tag)) { 3648 // The host app may not yet exist on the device. If it's here we 3649 // just use the existing Host entry, otherwise we create a 3650 // placeholder whose uid will be fixed up at PACKAGE_ADDED time. 3651 String pkg = parser.getAttributeValue(null, "pkg"); 3652 3653 final int uid = getUidForPackage(pkg, userId); 3654 final int hostId = Integer.parseInt( 3655 parser.getAttributeValue(null, "id"), 16); 3656 3657 HostId id = new HostId(uid, hostId, pkg); 3658 Host h = lookupOrAddHostLocked(id); 3659 restoredHosts.add(h); 3660 3661 if (DEBUG) { 3662 Slog.i(TAG, " host[" + restoredHosts.size() 3663 + "]: {" + h.id + "}"); 3664 } 3665 } else if ("g".equals(tag)) { 3666 int restoredId = Integer.parseInt( 3667 parser.getAttributeValue(null, "id"), 16); 3668 int hostIndex = Integer.parseInt( 3669 parser.getAttributeValue(null, "h"), 16); 3670 Host host = restoredHosts.get(hostIndex); 3671 Provider p = null; 3672 String prov = parser.getAttributeValue(null, "p"); 3673 if (prov != null) { 3674 // could have been null if the app had allocated an id 3675 // but not yet established a binding under that id 3676 int which = Integer.parseInt(prov, 16); 3677 p = restoredProviders.get(which); 3678 } 3679 3680 // We'll be restoring widget state for both the host and 3681 // provider sides of this widget ID, so make sure we are 3682 // beginning from a clean slate on both fronts. 3683 pruneWidgetStateLocked(host.id.packageName, userId); 3684 if (p != null) { 3685 pruneWidgetStateLocked(p.id.componentName.getPackageName(), 3686 userId); 3687 } 3688 3689 // Have we heard about this ancestral widget instance before? 3690 Widget id = findRestoredWidgetLocked(restoredId, host, p); 3691 if (id == null) { 3692 id = new Widget(); 3693 id.appWidgetId = incrementAndGetAppWidgetIdLocked(userId); 3694 id.restoredId = restoredId; 3695 id.options = parseWidgetIdOptions(parser); 3696 id.host = host; 3697 id.host.widgets.add(id); 3698 id.provider = p; 3699 if (id.provider != null) { 3700 id.provider.widgets.add(id); 3701 } 3702 if (DEBUG) { 3703 Slog.i(TAG, "New restored id " + restoredId 3704 + " now " + id); 3705 } 3706 mWidgets.add(id); 3707 } 3708 if (id.provider.info != null) { 3709 stashProviderRestoreUpdateLocked(id.provider, 3710 restoredId, id.appWidgetId); 3711 } else { 3712 Slog.w(TAG, "Missing provider for restored widget " + id); 3713 } 3714 stashHostRestoreUpdateLocked(id.host, restoredId, id.appWidgetId); 3715 3716 if (DEBUG) { 3717 Slog.i(TAG, " instance: " + restoredId 3718 + " -> " + id.appWidgetId 3719 + " :: p=" + id.provider); 3720 } 3721 } 3722 } 3723 } while (type != XmlPullParser.END_DOCUMENT); 3724 3725 // We've updated our own bookkeeping. We'll need to notify the hosts and 3726 // providers about the changes, but we can't do that yet because the restore 3727 // target is not necessarily fully live at this moment. Set aside the 3728 // information for now; the backup manager will call us once more at the 3729 // end of the process when all of the targets are in a known state, and we 3730 // will update at that point. 3731 } 3732 } catch (XmlPullParserException | IOException e) { 3733 Slog.w(TAG, "Unable to restore widget state for " + packageName); 3734 } finally { 3735 saveGroupStateAsync(userId); 3736 } 3737 } 3738 3739 // Called once following the conclusion of a restore operation. This is when we 3740 // send out updates to apps involved in widget-state restore telling them about 3741 // the new widget ID space. 3742 public void restoreFinished(int userId) { 3743 if (DEBUG) { 3744 Slog.i(TAG, "restoreFinished for " + userId); 3745 } 3746 3747 final UserHandle userHandle = new UserHandle(userId); 3748 synchronized (mLock) { 3749 // Build the providers' broadcasts and send them off 3750 Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries 3751 = mUpdatesByProvider.entrySet(); 3752 for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) { 3753 // For each provider there's a list of affected IDs 3754 Provider provider = e.getKey(); 3755 ArrayList<RestoreUpdateRecord> updates = e.getValue(); 3756 final int pending = countPendingUpdates(updates); 3757 if (DEBUG) { 3758 Slog.i(TAG, "Provider " + provider + " pending: " + pending); 3759 } 3760 if (pending > 0) { 3761 int[] oldIds = new int[pending]; 3762 int[] newIds = new int[pending]; 3763 final int N = updates.size(); 3764 int nextPending = 0; 3765 for (int i = 0; i < N; i++) { 3766 RestoreUpdateRecord r = updates.get(i); 3767 if (!r.notified) { 3768 r.notified = true; 3769 oldIds[nextPending] = r.oldId; 3770 newIds[nextPending] = r.newId; 3771 nextPending++; 3772 if (DEBUG) { 3773 Slog.i(TAG, " " + r.oldId + " => " + r.newId); 3774 } 3775 } 3776 } 3777 sendWidgetRestoreBroadcastLocked( 3778 AppWidgetManager.ACTION_APPWIDGET_RESTORED, 3779 provider, null, oldIds, newIds, userHandle); 3780 } 3781 } 3782 3783 // same thing per host 3784 Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries 3785 = mUpdatesByHost.entrySet(); 3786 for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) { 3787 Host host = e.getKey(); 3788 if (host.id.uid != UNKNOWN_UID) { 3789 ArrayList<RestoreUpdateRecord> updates = e.getValue(); 3790 final int pending = countPendingUpdates(updates); 3791 if (DEBUG) { 3792 Slog.i(TAG, "Host " + host + " pending: " + pending); 3793 } 3794 if (pending > 0) { 3795 int[] oldIds = new int[pending]; 3796 int[] newIds = new int[pending]; 3797 final int N = updates.size(); 3798 int nextPending = 0; 3799 for (int i = 0; i < N; i++) { 3800 RestoreUpdateRecord r = updates.get(i); 3801 if (!r.notified) { 3802 r.notified = true; 3803 oldIds[nextPending] = r.oldId; 3804 newIds[nextPending] = r.newId; 3805 nextPending++; 3806 if (DEBUG) { 3807 Slog.i(TAG, " " + r.oldId + " => " + r.newId); 3808 } 3809 } 3810 } 3811 sendWidgetRestoreBroadcastLocked( 3812 AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED, 3813 null, host, oldIds, newIds, userHandle); 3814 } 3815 } 3816 } 3817 } 3818 } 3819 3820 private Provider findProviderLocked(ComponentName componentName, int userId) { 3821 final int providerCount = mProviders.size(); 3822 for (int i = 0; i < providerCount; i++) { 3823 Provider provider = mProviders.get(i); 3824 if (provider.getUserId() == userId 3825 && provider.id.componentName.equals(componentName)) { 3826 return provider; 3827 } 3828 } 3829 return null; 3830 } 3831 3832 private Widget findRestoredWidgetLocked(int restoredId, Host host, Provider p) { 3833 if (DEBUG) { 3834 Slog.i(TAG, "Find restored widget: id=" + restoredId 3835 + " host=" + host + " provider=" + p); 3836 } 3837 3838 if (p == null || host == null) { 3839 return null; 3840 } 3841 3842 final int N = mWidgets.size(); 3843 for (int i = 0; i < N; i++) { 3844 Widget widget = mWidgets.get(i); 3845 if (widget.restoredId == restoredId 3846 && widget.host.id.equals(host.id) 3847 && widget.provider.id.equals(p.id)) { 3848 if (DEBUG) { 3849 Slog.i(TAG, " Found at " + i + " : " + widget); 3850 } 3851 return widget; 3852 } 3853 } 3854 return null; 3855 } 3856 3857 private boolean packageNeedsWidgetBackupLocked(String packageName, int userId) { 3858 int N = mWidgets.size(); 3859 for (int i = 0; i < N; i++) { 3860 Widget widget = mWidgets.get(i); 3861 3862 // Skip cross-user widgets. 3863 if (!isProviderAndHostInUser(widget, userId)) { 3864 continue; 3865 } 3866 3867 if (widget.host.isInPackageForUser(packageName, userId)) { 3868 // this package is hosting widgets, so it knows widget IDs. 3869 return true; 3870 } 3871 3872 Provider provider = widget.provider; 3873 if (provider != null && provider.isInPackageForUser(packageName, userId)) { 3874 // someone is hosting this app's widgets, so it knows widget IDs. 3875 return true; 3876 } 3877 } 3878 return false; 3879 } 3880 3881 private void stashProviderRestoreUpdateLocked(Provider provider, int oldId, int newId) { 3882 ArrayList<RestoreUpdateRecord> r = mUpdatesByProvider.get(provider); 3883 if (r == null) { 3884 r = new ArrayList<>(); 3885 mUpdatesByProvider.put(provider, r); 3886 } else { 3887 // don't duplicate 3888 if (alreadyStashed(r, oldId, newId)) { 3889 if (DEBUG) { 3890 Slog.i(TAG, "ID remap " + oldId + " -> " + newId 3891 + " already stashed for " + provider); 3892 } 3893 return; 3894 } 3895 } 3896 r.add(new RestoreUpdateRecord(oldId, newId)); 3897 } 3898 3899 private boolean alreadyStashed(ArrayList<RestoreUpdateRecord> stash, 3900 final int oldId, final int newId) { 3901 final int N = stash.size(); 3902 for (int i = 0; i < N; i++) { 3903 RestoreUpdateRecord r = stash.get(i); 3904 if (r.oldId == oldId && r.newId == newId) { 3905 return true; 3906 } 3907 } 3908 return false; 3909 } 3910 3911 private void stashHostRestoreUpdateLocked(Host host, int oldId, int newId) { 3912 ArrayList<RestoreUpdateRecord> r = mUpdatesByHost.get(host); 3913 if (r == null) { 3914 r = new ArrayList<>(); 3915 mUpdatesByHost.put(host, r); 3916 } else { 3917 if (alreadyStashed(r, oldId, newId)) { 3918 if (DEBUG) { 3919 Slog.i(TAG, "ID remap " + oldId + " -> " + newId 3920 + " already stashed for " + host); 3921 } 3922 return; 3923 } 3924 } 3925 r.add(new RestoreUpdateRecord(oldId, newId)); 3926 } 3927 3928 private void sendWidgetRestoreBroadcastLocked(String action, Provider provider, 3929 Host host, int[] oldIds, int[] newIds, UserHandle userHandle) { 3930 Intent intent = new Intent(action); 3931 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS, oldIds); 3932 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, newIds); 3933 if (provider != null) { 3934 intent.setComponent(provider.info.provider); 3935 sendBroadcastAsUser(intent, userHandle); 3936 } 3937 if (host != null) { 3938 intent.setComponent(null); 3939 intent.setPackage(host.id.packageName); 3940 intent.putExtra(AppWidgetManager.EXTRA_HOST_ID, host.id.hostId); 3941 sendBroadcastAsUser(intent, userHandle); 3942 } 3943 } 3944 3945 // We're restoring widget state for 'pkg', so we start by wiping (a) all widget 3946 // instances that are hosted by that app, and (b) all instances in other hosts 3947 // for which 'pkg' is the provider. We assume that we'll be restoring all of 3948 // these hosts & providers, so will be reconstructing a correct live state. 3949 private void pruneWidgetStateLocked(String pkg, int userId) { 3950 if (!mPrunedApps.contains(pkg)) { 3951 if (DEBUG) { 3952 Slog.i(TAG, "pruning widget state for restoring package " + pkg); 3953 } 3954 for (int i = mWidgets.size() - 1; i >= 0; i--) { 3955 Widget widget = mWidgets.get(i); 3956 3957 Host host = widget.host; 3958 Provider provider = widget.provider; 3959 3960 if (host.hostsPackageForUser(pkg, userId) 3961 || (provider != null && provider.isInPackageForUser(pkg, userId))) { 3962 // 'pkg' is either the host or the provider for this instances, 3963 // so we tear it down in anticipation of it (possibly) being 3964 // reconstructed due to the restore 3965 host.widgets.remove(widget); 3966 provider.widgets.remove(widget); 3967 unbindAppWidgetRemoteViewsServicesLocked(widget); 3968 mWidgets.remove(i); 3969 } 3970 } 3971 mPrunedApps.add(pkg); 3972 } else { 3973 if (DEBUG) { 3974 Slog.i(TAG, "already pruned " + pkg + ", continuing normally"); 3975 } 3976 } 3977 } 3978 3979 private boolean isProviderAndHostInUser(Widget widget, int userId) { 3980 // Backup only widgets hosted or provided by the owner profile. 3981 return widget.host.getUserId() == userId && (widget.provider == null 3982 || widget.provider.getUserId() == userId); 3983 } 3984 3985 private Bundle parseWidgetIdOptions(XmlPullParser parser) { 3986 Bundle options = new Bundle(); 3987 String minWidthString = parser.getAttributeValue(null, "min_width"); 3988 if (minWidthString != null) { 3989 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 3990 Integer.parseInt(minWidthString, 16)); 3991 } 3992 String minHeightString = parser.getAttributeValue(null, "min_height"); 3993 if (minHeightString != null) { 3994 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 3995 Integer.parseInt(minHeightString, 16)); 3996 } 3997 String maxWidthString = parser.getAttributeValue(null, "max_width"); 3998 if (maxWidthString != null) { 3999 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 4000 Integer.parseInt(maxWidthString, 16)); 4001 } 4002 String maxHeightString = parser.getAttributeValue(null, "max_height"); 4003 if (maxHeightString != null) { 4004 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 4005 Integer.parseInt(maxHeightString, 16)); 4006 } 4007 String categoryString = parser.getAttributeValue(null, "host_category"); 4008 if (categoryString != null) { 4009 options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 4010 Integer.parseInt(categoryString, 16)); 4011 } 4012 return options; 4013 } 4014 4015 private int countPendingUpdates(ArrayList<RestoreUpdateRecord> updates) { 4016 int pending = 0; 4017 final int N = updates.size(); 4018 for (int i = 0; i < N; i++) { 4019 RestoreUpdateRecord r = updates.get(i); 4020 if (!r.notified) { 4021 pending++; 4022 } 4023 } 4024 return pending; 4025 } 4026 4027 // Accumulate a list of updates that affect the given provider for a final 4028 // coalesced notification broadcast once restore is over. 4029 private class RestoreUpdateRecord { 4030 public int oldId; 4031 public int newId; 4032 public boolean notified; 4033 4034 public RestoreUpdateRecord(int theOldId, int theNewId) { 4035 oldId = theOldId; 4036 newId = theNewId; 4037 notified = false; 4038 } 4039 } 4040 } 4041}