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 clearProvidersAndHostsTagsLocked(); 438 439 loadGroupWidgetProvidersLocked(newProfileIds); 440 loadGroupStateLocked(newProfileIds); 441 } 442 443 @Override 444 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 445 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, 446 "Permission Denial: can't dump from from pid=" 447 + Binder.getCallingPid() 448 + ", uid=" + Binder.getCallingUid()); 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 restoredProviderId = new ProviderId(UNKNOWN_UID, componentName); 1843 existing = lookupProviderLocked(restoredProviderId); 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.id = providerId; 1850 existing.zombie = false; 1851 existing.info = provider.info; // the real one filled out from the ResolveInfo 1852 if (DEBUG) { 1853 Slog.i(TAG, "Provider placeholder now reified: " + existing); 1854 } 1855 } 1856 } else { 1857 mProviders.add(provider); 1858 } 1859 return true; 1860 } 1861 1862 return false; 1863 } 1864 1865 private void deleteProviderLocked(Provider provider) { 1866 int N = provider.widgets.size(); 1867 for (int i = N - 1; i >= 0; i--) { 1868 Widget widget = provider.widgets.remove(i); 1869 // Call back with empty RemoteViews 1870 updateAppWidgetInstanceLocked(widget, null, false); 1871 // clear out references to this appWidgetId 1872 widget.host.widgets.remove(widget); 1873 mWidgets.remove(widget); 1874 widget.provider = null; 1875 pruneHostLocked(widget.host); 1876 widget.host = null; 1877 } 1878 mProviders.remove(provider); 1879 1880 // no need to send the DISABLE broadcast, since the receiver is gone anyway 1881 cancelBroadcasts(provider); 1882 } 1883 1884 private void sendEnableIntentLocked(Provider p) { 1885 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); 1886 intent.setComponent(p.info.provider); 1887 sendBroadcastAsUser(intent, p.info.getProfile()); 1888 } 1889 1890 private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds) { 1891 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1892 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 1893 intent.setComponent(provider.info.provider); 1894 sendBroadcastAsUser(intent, provider.info.getProfile()); 1895 } 1896 1897 private void sendDeletedIntentLocked(Widget widget) { 1898 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); 1899 intent.setComponent(widget.provider.info.provider); 1900 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId); 1901 sendBroadcastAsUser(intent, widget.provider.info.getProfile()); 1902 } 1903 1904 private void sendDisabledIntentLocked(Provider provider) { 1905 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); 1906 intent.setComponent(provider.info.provider); 1907 sendBroadcastAsUser(intent, provider.info.getProfile()); 1908 } 1909 1910 public void sendOptionsChangedIntentLocked(Widget widget) { 1911 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED); 1912 intent.setComponent(widget.provider.info.provider); 1913 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId); 1914 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, widget.options); 1915 sendBroadcastAsUser(intent, widget.provider.info.getProfile()); 1916 } 1917 1918 private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) { 1919 if (provider.info.updatePeriodMillis > 0) { 1920 // if this is the first instance, set the alarm. otherwise, 1921 // rely on the fact that we've already set it and that 1922 // PendingIntent.getBroadcast will update the extras. 1923 boolean alreadyRegistered = provider.broadcast != null; 1924 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 1925 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); 1926 intent.setComponent(provider.info.provider); 1927 long token = Binder.clearCallingIdentity(); 1928 try { 1929 provider.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent, 1930 PendingIntent.FLAG_UPDATE_CURRENT, provider.info.getProfile()); 1931 } finally { 1932 Binder.restoreCallingIdentity(token); 1933 } 1934 if (!alreadyRegistered) { 1935 long period = provider.info.updatePeriodMillis; 1936 if (period < MIN_UPDATE_PERIOD) { 1937 period = MIN_UPDATE_PERIOD; 1938 } 1939 mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1940 SystemClock.elapsedRealtime() + period, period, provider.broadcast); 1941 } 1942 } 1943 } 1944 1945 private static int[] getWidgetIds(ArrayList<Widget> widgets) { 1946 int instancesSize = widgets.size(); 1947 int appWidgetIds[] = new int[instancesSize]; 1948 for (int i = 0; i < instancesSize; i++) { 1949 appWidgetIds[i] = widgets.get(i).appWidgetId; 1950 } 1951 return appWidgetIds; 1952 } 1953 1954 private static void dumpProvider(Provider provider, int index, PrintWriter pw) { 1955 AppWidgetProviderInfo info = provider.info; 1956 pw.print(" ["); pw.print(index); pw.print("] provider "); 1957 pw.println(provider.id); 1958 pw.print(" min=("); pw.print(info.minWidth); 1959 pw.print("x"); pw.print(info.minHeight); 1960 pw.print(") minResize=("); pw.print(info.minResizeWidth); 1961 pw.print("x"); pw.print(info.minResizeHeight); 1962 pw.print(") updatePeriodMillis="); 1963 pw.print(info.updatePeriodMillis); 1964 pw.print(" resizeMode="); 1965 pw.print(info.resizeMode); 1966 pw.print(info.widgetCategory); 1967 pw.print(" autoAdvanceViewId="); 1968 pw.print(info.autoAdvanceViewId); 1969 pw.print(" initialLayout=#"); 1970 pw.print(Integer.toHexString(info.initialLayout)); 1971 pw.print(" initialKeyguardLayout=#"); 1972 pw.print(Integer.toHexString(info.initialKeyguardLayout)); 1973 pw.print(" zombie="); pw.println(provider.zombie); 1974 } 1975 1976 private static void dumpHost(Host host, int index, PrintWriter pw) { 1977 pw.print(" ["); pw.print(index); pw.print("] hostId="); 1978 pw.println(host.id); 1979 pw.print(" callbacks="); pw.println(host.callbacks); 1980 pw.print(" widgets.size="); pw.print(host.widgets.size()); 1981 pw.print(" zombie="); pw.println(host.zombie); 1982 } 1983 1984 private static void dumpGrant(Pair<Integer, String> grant, int index, PrintWriter pw) { 1985 pw.print(" ["); pw.print(index); pw.print(']'); 1986 pw.print(" user="); pw.print(grant.first); 1987 pw.print(" package="); pw.println(grant.second); 1988 } 1989 1990 private static void dumpWidget(Widget widget, int index, PrintWriter pw) { 1991 pw.print(" ["); pw.print(index); pw.print("] id="); 1992 pw.println(widget.appWidgetId); 1993 pw.print(" host="); 1994 pw.println(widget.host.id); 1995 if (widget.provider != null) { 1996 pw.print(" provider="); pw.println(widget.provider.id); 1997 } 1998 if (widget.host != null) { 1999 pw.print(" host.callbacks="); pw.println(widget.host.callbacks); 2000 } 2001 if (widget.views != null) { 2002 pw.print(" views="); pw.println(widget.views); 2003 } 2004 } 2005 2006 private static void serializeProvider(XmlSerializer out, Provider p) throws IOException { 2007 out.startTag(null, "p"); 2008 out.attribute(null, "pkg", p.info.provider.getPackageName()); 2009 out.attribute(null, "cl", p.info.provider.getClassName()); 2010 out.attribute(null, "tag", Integer.toHexString(p.tag)); 2011 out.endTag(null, "p"); 2012 } 2013 2014 private static void serializeHost(XmlSerializer out, Host host) throws IOException { 2015 out.startTag(null, "h"); 2016 out.attribute(null, "pkg", host.id.packageName); 2017 out.attribute(null, "id", Integer.toHexString(host.id.hostId)); 2018 out.attribute(null, "tag", Integer.toHexString(host.tag)); 2019 out.endTag(null, "h"); 2020 } 2021 2022 private static void serializeAppWidget(XmlSerializer out, Widget widget) throws IOException { 2023 out.startTag(null, "g"); 2024 out.attribute(null, "id", Integer.toHexString(widget.appWidgetId)); 2025 out.attribute(null, "rid", Integer.toHexString(widget.restoredId)); 2026 out.attribute(null, "h", Integer.toHexString(widget.host.tag)); 2027 if (widget.provider != null) { 2028 out.attribute(null, "p", Integer.toHexString(widget.provider.tag)); 2029 } 2030 if (widget.options != null) { 2031 out.attribute(null, "min_width", Integer.toHexString(widget.options.getInt( 2032 AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH))); 2033 out.attribute(null, "min_height", Integer.toHexString(widget.options.getInt( 2034 AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT))); 2035 out.attribute(null, "max_width", Integer.toHexString(widget.options.getInt( 2036 AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH))); 2037 out.attribute(null, "max_height", Integer.toHexString(widget.options.getInt( 2038 AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT))); 2039 out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt( 2040 AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))); 2041 } 2042 out.endTag(null, "g"); 2043 } 2044 2045 @Override 2046 public List<String> getWidgetParticipants(int userId) { 2047 return mBackupRestoreController.getWidgetParticipants(userId); 2048 } 2049 2050 @Override 2051 public byte[] getWidgetState(String packageName, int userId) { 2052 return mBackupRestoreController.getWidgetState(packageName, userId); 2053 } 2054 2055 @Override 2056 public void restoreStarting(int userId) { 2057 mBackupRestoreController.restoreStarting(userId); 2058 } 2059 2060 @Override 2061 public void restoreWidgetState(String packageName, byte[] restoredState, int userId) { 2062 mBackupRestoreController.restoreWidgetState(packageName, restoredState, userId); 2063 } 2064 2065 @Override 2066 public void restoreFinished(int userId) { 2067 mBackupRestoreController.restoreFinished(userId); 2068 } 2069 2070 @SuppressWarnings("deprecation") 2071 private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri) { 2072 Provider provider = null; 2073 2074 ActivityInfo activityInfo = ri.activityInfo; 2075 XmlResourceParser parser = null; 2076 try { 2077 parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(), 2078 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); 2079 if (parser == null) { 2080 Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER 2081 + " meta-data for " + "AppWidget provider '" + providerId + '\''); 2082 return null; 2083 } 2084 2085 AttributeSet attrs = Xml.asAttributeSet(parser); 2086 2087 int type; 2088 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 2089 && type != XmlPullParser.START_TAG) { 2090 // drain whitespace, comments, etc. 2091 } 2092 2093 String nodeName = parser.getName(); 2094 if (!"appwidget-provider".equals(nodeName)) { 2095 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for" 2096 + " AppWidget provider " + providerId.componentName 2097 + " for user " + providerId.uid); 2098 return null; 2099 } 2100 2101 provider = new Provider(); 2102 provider.id = providerId; 2103 AppWidgetProviderInfo info = provider.info = new AppWidgetProviderInfo(); 2104 info.provider = providerId.componentName; 2105 info.providerInfo = activityInfo; 2106 2107 final Resources resources; 2108 final long identity = Binder.clearCallingIdentity(); 2109 try { 2110 resources = mContext.getPackageManager() 2111 .getResourcesForApplicationAsUser(activityInfo.packageName, 2112 UserHandle.getUserId(providerId.uid)); 2113 } finally { 2114 Binder.restoreCallingIdentity(identity); 2115 } 2116 2117 TypedArray sa = resources.obtainAttributes(attrs, 2118 com.android.internal.R.styleable.AppWidgetProviderInfo); 2119 2120 // These dimensions has to be resolved in the application's context. 2121 // We simply send back the raw complex data, which will be 2122 // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}. 2123 TypedValue value = sa 2124 .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth); 2125 info.minWidth = value != null ? value.data : 0; 2126 value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight); 2127 info.minHeight = value != null ? value.data : 0; 2128 value = sa.peekValue( 2129 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth); 2130 info.minResizeWidth = value != null ? value.data : info.minWidth; 2131 value = sa.peekValue( 2132 com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight); 2133 info.minResizeHeight = value != null ? value.data : info.minHeight; 2134 info.updatePeriodMillis = sa.getInt( 2135 com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0); 2136 info.initialLayout = sa.getResourceId( 2137 com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0); 2138 info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable. 2139 AppWidgetProviderInfo_initialKeyguardLayout, 0); 2140 2141 String className = sa 2142 .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure); 2143 if (className != null) { 2144 info.configure = new ComponentName(providerId.componentName.getPackageName(), 2145 className); 2146 } 2147 info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString(); 2148 info.icon = ri.getIconResource(); 2149 info.previewImage = sa.getResourceId( 2150 com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); 2151 info.autoAdvanceViewId = sa.getResourceId( 2152 com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1); 2153 info.resizeMode = sa.getInt( 2154 com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode, 2155 AppWidgetProviderInfo.RESIZE_NONE); 2156 info.widgetCategory = sa.getInt( 2157 com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory, 2158 AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN); 2159 2160 sa.recycle(); 2161 } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) { 2162 // Ok to catch Exception here, because anything going wrong because 2163 // of what a client process passes to us should not be fatal for the 2164 // system process. 2165 Slog.w(TAG, "XML parsing failed for AppWidget provider " 2166 + providerId.componentName + " for user " + providerId.uid, e); 2167 return null; 2168 } finally { 2169 if (parser != null) { 2170 parser.close(); 2171 } 2172 } 2173 return provider; 2174 } 2175 2176 private int getUidForPackage(String packageName, int userId) { 2177 PackageInfo pkgInfo = null; 2178 2179 final long identity = Binder.clearCallingIdentity(); 2180 try { 2181 pkgInfo = mPackageManager.getPackageInfo(packageName, 0, userId); 2182 } catch (RemoteException re) { 2183 // Shouldn't happen, local call 2184 } finally { 2185 Binder.restoreCallingIdentity(identity); 2186 } 2187 2188 if (pkgInfo == null || pkgInfo.applicationInfo == null) { 2189 return -1; 2190 } 2191 2192 return pkgInfo.applicationInfo.uid; 2193 } 2194 2195 private ActivityInfo getProviderInfo(ComponentName componentName, int userId) { 2196 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 2197 intent.setComponent(componentName); 2198 2199 List<ResolveInfo> receivers = queryIntentReceivers(intent, userId); 2200 // We are setting component, so there is only one or none. 2201 if (!receivers.isEmpty()) { 2202 return receivers.get(0).activityInfo; 2203 } 2204 2205 return null; 2206 } 2207 2208 private List<ResolveInfo> queryIntentReceivers(Intent intent, int userId) { 2209 final long identity = Binder.clearCallingIdentity(); 2210 try { 2211 int flags = PackageManager.GET_META_DATA; 2212 2213 // Widgets referencing shared libraries need to have their 2214 // dependencies loaded. 2215 flags |= PackageManager.GET_SHARED_LIBRARY_FILES; 2216 2217 return mPackageManager.queryIntentReceivers(intent, 2218 intent.resolveTypeIfNeeded(mContext.getContentResolver()), 2219 flags, userId); 2220 } catch (RemoteException re) { 2221 return Collections.emptyList(); 2222 } finally { 2223 Binder.restoreCallingIdentity(identity); 2224 } 2225 } 2226 2227 private void onUserStarted(int userId) { 2228 synchronized (mLock) { 2229 ensureGroupStateLoadedLocked(userId); 2230 2231 final int N = mProviders.size(); 2232 for (int i = 0; i < N; i++) { 2233 Provider provider = mProviders.get(i); 2234 2235 // Send broadcast only to the providers of the user. 2236 if (provider.getUserId() != userId) { 2237 continue; 2238 } 2239 2240 if (provider.widgets.size() > 0) { 2241 sendEnableIntentLocked(provider); 2242 int[] appWidgetIds = getWidgetIds(provider.widgets); 2243 sendUpdateIntentLocked(provider, appWidgetIds); 2244 registerForBroadcastsLocked(provider, appWidgetIds); 2245 } 2246 } 2247 } 2248 } 2249 2250 // only call from initialization -- it assumes that the data structures are all empty 2251 private void loadGroupStateLocked(int[] profileIds) { 2252 // We can bind the widgets to host and providers only after 2253 // reading the host and providers for all users since a widget 2254 // can have a host and a provider in different users. 2255 List<LoadedWidgetState> loadedWidgets = new ArrayList<>(); 2256 2257 int version = 0; 2258 2259 final int profileIdCount = profileIds.length; 2260 for (int i = 0; i < profileIdCount; i++) { 2261 final int profileId = profileIds[i]; 2262 2263 // No file written for this user - nothing to do. 2264 AtomicFile file = getSavedStateFile(profileId); 2265 try { 2266 FileInputStream stream = file.openRead(); 2267 version = readProfileStateFromFileLocked(stream, profileId, loadedWidgets); 2268 IoUtils.closeQuietly(stream); 2269 } catch (FileNotFoundException e) { 2270 Slog.w(TAG, "Failed to read state: " + e); 2271 } 2272 } 2273 2274 if (version >= 0) { 2275 // Hooke'm up... 2276 bindLoadedWidgets(loadedWidgets); 2277 2278 // upgrade the database if needed 2279 performUpgradeLocked(version); 2280 } else { 2281 // failed reading, clean up 2282 Slog.w(TAG, "Failed to read state, clearing widgets and hosts."); 2283 mWidgets.clear(); 2284 mHosts.clear(); 2285 final int N = mProviders.size(); 2286 for (int i = 0; i < N; i++) { 2287 mProviders.get(i).widgets.clear(); 2288 } 2289 } 2290 } 2291 2292 private void bindLoadedWidgets(List<LoadedWidgetState> loadedWidgets) { 2293 final int loadedWidgetCount = loadedWidgets.size(); 2294 for (int i = loadedWidgetCount - 1; i >= 0; i--) { 2295 LoadedWidgetState loadedWidget = loadedWidgets.remove(i); 2296 Widget widget = loadedWidget.widget; 2297 2298 widget.provider = findProviderByTag(loadedWidget.providerTag); 2299 if (widget.provider == null) { 2300 // This provider is gone. We just let the host figure out 2301 // that this happened when it fails to load it. 2302 continue; 2303 } 2304 2305 widget.host = findHostByTag(loadedWidget.hostTag); 2306 if (widget.host == null) { 2307 // This host is gone. 2308 continue; 2309 } 2310 2311 widget.provider.widgets.add(widget); 2312 widget.host.widgets.add(widget); 2313 mWidgets.add(widget); 2314 } 2315 } 2316 2317 private Provider findProviderByTag(int tag) { 2318 if (tag < 0) { 2319 return null; 2320 } 2321 final int providerCount = mProviders.size(); 2322 for (int i = 0; i < providerCount; i++) { 2323 Provider provider = mProviders.get(i); 2324 if (provider.tag == tag) { 2325 return provider; 2326 } 2327 } 2328 return null; 2329 } 2330 2331 private Host findHostByTag(int tag) { 2332 if (tag < 0) { 2333 return null; 2334 } 2335 final int hostCount = mHosts.size(); 2336 for (int i = 0; i < hostCount; i++) { 2337 Host host = mHosts.get(i); 2338 if (host.tag == tag) { 2339 return host; 2340 } 2341 } 2342 return null; 2343 } 2344 2345 private void saveStateLocked(int userId) { 2346 tagProvidersAndHosts(); 2347 2348 final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId); 2349 2350 final int profileCount = profileIds.length; 2351 for (int i = 0; i < profileCount; i++) { 2352 final int profileId = profileIds[i]; 2353 2354 AtomicFile file = getSavedStateFile(profileId); 2355 FileOutputStream stream; 2356 try { 2357 stream = file.startWrite(); 2358 if (writeProfileStateToFileLocked(stream, profileId)) { 2359 file.finishWrite(stream); 2360 } else { 2361 file.failWrite(stream); 2362 Slog.w(TAG, "Failed to save state, restoring backup."); 2363 } 2364 } catch (IOException e) { 2365 Slog.w(TAG, "Failed open state file for write: " + e); 2366 } 2367 } 2368 } 2369 2370 private void tagProvidersAndHosts() { 2371 final int providerCount = mProviders.size(); 2372 for (int i = 0; i < providerCount; i++) { 2373 Provider provider = mProviders.get(i); 2374 provider.tag = i; 2375 } 2376 2377 final int hostCount = mHosts.size(); 2378 for (int i = 0; i < hostCount; i++) { 2379 Host host = mHosts.get(i); 2380 host.tag = i; 2381 } 2382 } 2383 2384 private void clearProvidersAndHostsTagsLocked() { 2385 final int providerCount = mProviders.size(); 2386 for (int i = 0; i < providerCount; i++) { 2387 Provider provider = mProviders.get(i); 2388 provider.tag = TAG_UNDEFINED; 2389 } 2390 2391 final int hostCount = mHosts.size(); 2392 for (int i = 0; i < hostCount; i++) { 2393 Host host = mHosts.get(i); 2394 host.tag = TAG_UNDEFINED; 2395 } 2396 } 2397 2398 private boolean writeProfileStateToFileLocked(FileOutputStream stream, int userId) { 2399 int N; 2400 2401 try { 2402 XmlSerializer out = new FastXmlSerializer(); 2403 out.setOutput(stream, "utf-8"); 2404 out.startDocument(null, true); 2405 out.startTag(null, "gs"); 2406 out.attribute(null, "version", String.valueOf(CURRENT_VERSION)); 2407 2408 N = mProviders.size(); 2409 for (int i = 0; i < N; i++) { 2410 Provider provider = mProviders.get(i); 2411 // Save only providers for the user. 2412 if (provider.getUserId() != userId) { 2413 continue; 2414 } 2415 if (provider.widgets.size() > 0) { 2416 serializeProvider(out, provider); 2417 } 2418 } 2419 2420 N = mHosts.size(); 2421 for (int i = 0; i < N; i++) { 2422 Host host = mHosts.get(i); 2423 // Save only hosts for the user. 2424 if (host.getUserId() != userId) { 2425 continue; 2426 } 2427 serializeHost(out, host); 2428 } 2429 2430 N = mWidgets.size(); 2431 for (int i = 0; i < N; i++) { 2432 Widget widget = mWidgets.get(i); 2433 // Save only widgets hosted by the user. 2434 if (widget.host.getUserId() != userId) { 2435 continue; 2436 } 2437 serializeAppWidget(out, widget); 2438 } 2439 2440 Iterator<Pair<Integer, String>> it = mPackagesWithBindWidgetPermission.iterator(); 2441 while (it.hasNext()) { 2442 Pair<Integer, String> binding = it.next(); 2443 // Save only white listings for the user. 2444 if (binding.first != userId) { 2445 continue; 2446 } 2447 out.startTag(null, "b"); 2448 out.attribute(null, "packageName", binding.second); 2449 out.endTag(null, "b"); 2450 } 2451 2452 out.endTag(null, "gs"); 2453 out.endDocument(); 2454 return true; 2455 } catch (IOException e) { 2456 Slog.w(TAG, "Failed to write state: " + e); 2457 return false; 2458 } 2459 } 2460 2461 private int readProfileStateFromFileLocked(FileInputStream stream, int userId, 2462 List<LoadedWidgetState> outLoadedWidgets) { 2463 int version = -1; 2464 try { 2465 XmlPullParser parser = Xml.newPullParser(); 2466 parser.setInput(stream, null); 2467 2468 int legacyProviderIndex = -1; 2469 int legacyHostIndex = -1; 2470 int type; 2471 do { 2472 type = parser.next(); 2473 if (type == XmlPullParser.START_TAG) { 2474 String tag = parser.getName(); 2475 if ("gs".equals(tag)) { 2476 String attributeValue = parser.getAttributeValue(null, "version"); 2477 try { 2478 version = Integer.parseInt(attributeValue); 2479 } catch (NumberFormatException e) { 2480 version = 0; 2481 } 2482 } else if ("p".equals(tag)) { 2483 legacyProviderIndex++; 2484 // TODO: do we need to check that this package has the same signature 2485 // as before? 2486 String pkg = parser.getAttributeValue(null, "pkg"); 2487 String cl = parser.getAttributeValue(null, "cl"); 2488 2489 pkg = getCanonicalPackageName(pkg, cl, userId); 2490 if (pkg == null) { 2491 continue; 2492 } 2493 2494 final int uid = getUidForPackage(pkg, userId); 2495 if (uid < 0) { 2496 continue; 2497 } 2498 2499 ComponentName componentName = new ComponentName(pkg, cl); 2500 2501 ActivityInfo providerInfo = getProviderInfo(componentName, userId); 2502 if (providerInfo == null) { 2503 continue; 2504 } 2505 2506 ProviderId providerId = new ProviderId(uid, componentName); 2507 Provider provider = lookupProviderLocked(providerId); 2508 2509 if (provider == null && mSafeMode) { 2510 // if we're in safe mode, make a temporary one 2511 provider = new Provider(); 2512 provider.info = new AppWidgetProviderInfo(); 2513 provider.info.provider = providerId.componentName; 2514 provider.info.providerInfo = providerInfo; 2515 provider.zombie = true; 2516 provider.id = providerId; 2517 mProviders.add(provider); 2518 } 2519 2520 String tagAttribute = parser.getAttributeValue(null, "tag"); 2521 final int providerTag = !TextUtils.isEmpty(tagAttribute) 2522 ? Integer.parseInt(tagAttribute, 16) : legacyProviderIndex; 2523 provider.tag = providerTag; 2524 } else if ("h".equals(tag)) { 2525 legacyHostIndex++; 2526 Host host = new Host(); 2527 // TODO: do we need to check that this package has the same signature 2528 // as before? 2529 String pkg = parser.getAttributeValue(null, "pkg"); 2530 2531 final int uid = getUidForPackage(pkg, userId); 2532 if (uid < 0) { 2533 host.zombie = true; 2534 } 2535 2536 if (!host.zombie || mSafeMode) { 2537 // In safe mode, we don't discard the hosts we don't recognize 2538 // so that they're not pruned from our list. Otherwise, we do. 2539 final int hostId = Integer.parseInt(parser.getAttributeValue( 2540 null, "id"), 16); 2541 2542 String tagAttribute = parser.getAttributeValue(null, "tag"); 2543 final int hostTag = !TextUtils.isEmpty(tagAttribute) 2544 ? Integer.parseInt(tagAttribute, 16) : legacyHostIndex; 2545 2546 host.tag = hostTag; 2547 host.id = new HostId(uid, hostId, pkg); 2548 mHosts.add(host); 2549 } 2550 } else if ("b".equals(tag)) { 2551 String packageName = parser.getAttributeValue(null, "packageName"); 2552 final int uid = getUidForPackage(packageName, userId); 2553 if (uid >= 0) { 2554 Pair<Integer, String> packageId = Pair.create(userId, packageName); 2555 mPackagesWithBindWidgetPermission.add(packageId); 2556 } 2557 } else if ("g".equals(tag)) { 2558 Widget widget = new Widget(); 2559 widget.appWidgetId = Integer.parseInt(parser.getAttributeValue( 2560 null, "id"), 16); 2561 setMinAppWidgetIdLocked(userId, widget.appWidgetId + 1); 2562 2563 // restored ID is allowed to be absent 2564 String restoredIdString = parser.getAttributeValue(null, "rid"); 2565 widget.restoredId = (restoredIdString == null) ? 0 2566 : Integer.parseInt(restoredIdString, 16); 2567 2568 Bundle options = new Bundle(); 2569 String minWidthString = parser.getAttributeValue(null, "min_width"); 2570 if (minWidthString != null) { 2571 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 2572 Integer.parseInt(minWidthString, 16)); 2573 } 2574 String minHeightString = parser.getAttributeValue(null, "min_height"); 2575 if (minHeightString != null) { 2576 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 2577 Integer.parseInt(minHeightString, 16)); 2578 } 2579 String maxWidthString = parser.getAttributeValue(null, "max_width"); 2580 if (maxWidthString != null) { 2581 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 2582 Integer.parseInt(maxWidthString, 16)); 2583 } 2584 String maxHeightString = parser.getAttributeValue(null, "max_height"); 2585 if (maxHeightString != null) { 2586 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 2587 Integer.parseInt(maxHeightString, 16)); 2588 } 2589 String categoryString = parser.getAttributeValue(null, "host_category"); 2590 if (categoryString != null) { 2591 options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 2592 Integer.parseInt(categoryString, 16)); 2593 } 2594 widget.options = options; 2595 2596 final int hostTag = Integer.parseInt(parser.getAttributeValue( 2597 null, "h"), 16); 2598 String providerString = parser.getAttributeValue(null, "p"); 2599 final int providerTag = (providerString != null) ? Integer.parseInt( 2600 parser.getAttributeValue(null, "p"), 16) : TAG_UNDEFINED; 2601 2602 // We can match widgets with hosts and providers only after hosts 2603 // and providers for all users have been loaded since the widget 2604 // host and provider can be in different user profiles. 2605 LoadedWidgetState loadedWidgets = new LoadedWidgetState(widget, 2606 hostTag, providerTag); 2607 outLoadedWidgets.add(loadedWidgets); 2608 } 2609 } 2610 } while (type != XmlPullParser.END_DOCUMENT); 2611 } catch (NullPointerException 2612 | NumberFormatException 2613 | XmlPullParserException 2614 | IOException 2615 | IndexOutOfBoundsException e) { 2616 Slog.w(TAG, "failed parsing " + e); 2617 return -1; 2618 } 2619 2620 return version; 2621 } 2622 2623 private void performUpgradeLocked(int fromVersion) { 2624 if (fromVersion < CURRENT_VERSION) { 2625 Slog.v(TAG, "Upgrading widget database from " + fromVersion + " to " 2626 + CURRENT_VERSION); 2627 } 2628 2629 int version = fromVersion; 2630 2631 // Update 1: keyguard moved from package "android" to "com.android.keyguard" 2632 if (version == 0) { 2633 HostId oldHostId = new HostId(Process.myUid(), 2634 KEYGUARD_HOST_ID, OLD_KEYGUARD_HOST_PACKAGE); 2635 2636 Host host = lookupHostLocked(oldHostId); 2637 if (host != null) { 2638 final int uid = getUidForPackage(NEW_KEYGUARD_HOST_PACKAGE, 2639 UserHandle.USER_OWNER); 2640 if (uid >= 0) { 2641 host.id = new HostId(uid, KEYGUARD_HOST_ID, NEW_KEYGUARD_HOST_PACKAGE); 2642 } 2643 } 2644 2645 version = 1; 2646 } 2647 2648 if (version != CURRENT_VERSION) { 2649 throw new IllegalStateException("Failed to upgrade widget database"); 2650 } 2651 } 2652 2653 private static File getStateFile(int userId) { 2654 return new File(Environment.getUserSystemDirectory(userId), STATE_FILENAME); 2655 } 2656 2657 private static AtomicFile getSavedStateFile(int userId) { 2658 File dir = Environment.getUserSystemDirectory(userId); 2659 File settingsFile = getStateFile(userId); 2660 if (!settingsFile.exists() && userId == UserHandle.USER_OWNER) { 2661 if (!dir.exists()) { 2662 dir.mkdirs(); 2663 } 2664 // Migrate old data 2665 File oldFile = new File("/data/system/" + STATE_FILENAME); 2666 // Method doesn't throw an exception on failure. Ignore any errors 2667 // in moving the file (like non-existence) 2668 oldFile.renameTo(settingsFile); 2669 } 2670 return new AtomicFile(settingsFile); 2671 } 2672 2673 private void onUserStopped(int userId) { 2674 synchronized (mLock) { 2675 boolean providersChanged = false; 2676 boolean crossProfileWidgetsChanged = false; 2677 2678 // Remove widgets that have both host and provider in the user. 2679 final int widgetCount = mWidgets.size(); 2680 for (int i = widgetCount - 1; i >= 0; i--) { 2681 Widget widget = mWidgets.get(i); 2682 2683 final boolean hostInUser = widget.host.getUserId() == userId; 2684 final boolean hasProvider = widget.provider != null; 2685 final boolean providerInUser = hasProvider && widget.provider.getUserId() == userId; 2686 2687 // If both host and provider are in the user, just drop the widgets 2688 // as we do not want to make host callbacks and provider broadcasts 2689 // as the host and the provider will be killed. 2690 if (hostInUser && (!hasProvider || providerInUser)) { 2691 mWidgets.remove(i); 2692 widget.host.widgets.remove(widget); 2693 widget.host = null; 2694 if (hasProvider) { 2695 widget.provider.widgets.remove(widget); 2696 widget.provider = null; 2697 } 2698 } 2699 } 2700 2701 // Remove hosts and notify providers in other profiles. 2702 final int hostCount = mHosts.size(); 2703 for (int i = hostCount - 1; i >= 0; i--) { 2704 Host host = mHosts.get(i); 2705 if (host.getUserId() == userId) { 2706 crossProfileWidgetsChanged |= !host.widgets.isEmpty(); 2707 deleteHostLocked(host); 2708 } 2709 } 2710 2711 // Remove the providers and notify hosts in other profiles. 2712 final int providerCount = mProviders.size(); 2713 for (int i = providerCount - 1; i >= 0; i--) { 2714 Provider provider = mProviders.get(i); 2715 if (provider.getUserId() == userId) { 2716 crossProfileWidgetsChanged |= !provider.widgets.isEmpty(); 2717 providersChanged = true; 2718 deleteProviderLocked(provider); 2719 } 2720 } 2721 2722 // Remove grants for this user. 2723 final int grantCount = mPackagesWithBindWidgetPermission.size(); 2724 for (int i = grantCount - 1; i >= 0; i--) { 2725 Pair<Integer, String> packageId = mPackagesWithBindWidgetPermission.valueAt(i); 2726 if (packageId.first == userId) { 2727 mPackagesWithBindWidgetPermission.removeAt(i); 2728 } 2729 } 2730 2731 // Take a note we no longer have state for this user. 2732 final int userIndex = mLoadedUserIds.indexOfKey(userId); 2733 if (userIndex >= 0) { 2734 mLoadedUserIds.removeAt(userIndex); 2735 } 2736 2737 // Remove the widget id counter. 2738 final int nextIdIndex = mNextAppWidgetIds.indexOfKey(userId); 2739 if (nextIdIndex >= 0) { 2740 mNextAppWidgetIds.removeAt(nextIdIndex); 2741 } 2742 2743 // Announce removed provider changes to all hosts in the group. 2744 if (providersChanged) { 2745 scheduleNotifyGroupHostsForProvidersChangedLocked(userId); 2746 } 2747 2748 // Save state if removing a profile changed the group state. 2749 // Nothing will be saved if the group parent was removed. 2750 if (crossProfileWidgetsChanged) { 2751 saveGroupStateAsync(userId); 2752 } 2753 } 2754 } 2755 2756 /** 2757 * Updates all providers with the specified package names, and records any providers that were 2758 * pruned. 2759 * 2760 * @return whether any providers were updated 2761 */ 2762 private boolean updateProvidersForPackageLocked(String packageName, int userId, 2763 Set<ProviderId> removedProviders) { 2764 boolean providersUpdated = false; 2765 2766 HashSet<ProviderId> keep = new HashSet<>(); 2767 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); 2768 intent.setPackage(packageName); 2769 List<ResolveInfo> broadcastReceivers = queryIntentReceivers(intent, userId); 2770 2771 // add the missing ones and collect which ones to keep 2772 int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); 2773 for (int i = 0; i < N; i++) { 2774 ResolveInfo ri = broadcastReceivers.get(i); 2775 ActivityInfo ai = ri.activityInfo; 2776 2777 if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { 2778 continue; 2779 } 2780 2781 if (packageName.equals(ai.packageName)) { 2782 ProviderId providerId = new ProviderId(ai.applicationInfo.uid, 2783 new ComponentName(ai.packageName, ai.name)); 2784 2785 Provider provider = lookupProviderLocked(providerId); 2786 if (provider == null) { 2787 if (addProviderLocked(ri)) { 2788 keep.add(providerId); 2789 providersUpdated = true; 2790 } 2791 } else { 2792 Provider parsed = parseProviderInfoXml(providerId, ri); 2793 if (parsed != null) { 2794 keep.add(providerId); 2795 // Use the new AppWidgetProviderInfo. 2796 provider.info = parsed.info; 2797 // If it's enabled 2798 final int M = provider.widgets.size(); 2799 if (M > 0) { 2800 int[] appWidgetIds = getWidgetIds(provider.widgets); 2801 // Reschedule for the new updatePeriodMillis (don't worry about handling 2802 // it specially if updatePeriodMillis didn't change because we just sent 2803 // an update, and the next one will be updatePeriodMillis from now). 2804 cancelBroadcasts(provider); 2805 registerForBroadcastsLocked(provider, appWidgetIds); 2806 // If it's currently showing, call back with the new 2807 // AppWidgetProviderInfo. 2808 for (int j = 0; j < M; j++) { 2809 Widget widget = provider.widgets.get(j); 2810 widget.views = null; 2811 scheduleNotifyProviderChangedLocked(widget); 2812 } 2813 // Now that we've told the host, push out an update. 2814 sendUpdateIntentLocked(provider, appWidgetIds); 2815 providersUpdated = true; 2816 } 2817 } 2818 } 2819 } 2820 } 2821 2822 // prune the ones we don't want to keep 2823 N = mProviders.size(); 2824 for (int i = N - 1; i >= 0; i--) { 2825 Provider provider = mProviders.get(i); 2826 if (packageName.equals(provider.info.provider.getPackageName()) 2827 && provider.getUserId() == userId 2828 && !keep.contains(provider.id)) { 2829 if (removedProviders != null) { 2830 removedProviders.add(provider.id); 2831 } 2832 deleteProviderLocked(provider); 2833 providersUpdated = true; 2834 } 2835 } 2836 2837 return providersUpdated; 2838 } 2839 2840 private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) { 2841 boolean removed = false; 2842 2843 int N = mProviders.size(); 2844 for (int i = N - 1; i >= 0; i--) { 2845 Provider provider = mProviders.get(i); 2846 if (pkgName.equals(provider.info.provider.getPackageName()) 2847 && provider.getUserId() == userId) { 2848 deleteProviderLocked(provider); 2849 removed = true; 2850 } 2851 } 2852 2853 // Delete the hosts for this package too 2854 // By now, we have removed any AppWidgets that were in any hosts here, 2855 // so we don't need to worry about sending DISABLE broadcasts to them. 2856 N = mHosts.size(); 2857 for (int i = N - 1; i >= 0; i--) { 2858 Host host = mHosts.get(i); 2859 if (pkgName.equals(host.id.packageName) 2860 && host.getUserId() == userId) { 2861 deleteHostLocked(host); 2862 removed = true; 2863 } 2864 } 2865 2866 return removed; 2867 } 2868 2869 private String getCanonicalPackageName(String packageName, String className, int userId) { 2870 final long identity = Binder.clearCallingIdentity(); 2871 try { 2872 try { 2873 AppGlobals.getPackageManager().getReceiverInfo(new ComponentName(packageName, 2874 className), 0, userId); 2875 return packageName; 2876 } catch (RemoteException re) { 2877 String[] packageNames = mContext.getPackageManager() 2878 .currentToCanonicalPackageNames(new String[]{packageName}); 2879 if (packageNames != null && packageNames.length > 0) { 2880 return packageNames[0]; 2881 } 2882 } 2883 } finally { 2884 Binder.restoreCallingIdentity(identity); 2885 } 2886 return null; 2887 } 2888 2889 private void sendBroadcastAsUser(Intent intent, UserHandle userHandle) { 2890 final long identity = Binder.clearCallingIdentity(); 2891 try { 2892 mContext.sendBroadcastAsUser(intent, userHandle); 2893 } finally { 2894 Binder.restoreCallingIdentity(identity); 2895 } 2896 } 2897 2898 private void bindService(Intent intent, ServiceConnection connection, 2899 UserHandle userHandle) { 2900 final long token = Binder.clearCallingIdentity(); 2901 try { 2902 mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE, 2903 userHandle); 2904 } finally { 2905 Binder.restoreCallingIdentity(token); 2906 } 2907 } 2908 2909 private void unbindService(ServiceConnection connection) { 2910 final long token = Binder.clearCallingIdentity(); 2911 try { 2912 mContext.unbindService(connection); 2913 } finally { 2914 Binder.restoreCallingIdentity(token); 2915 } 2916 } 2917 2918 @Override 2919 public void onCrossProfileWidgetProvidersChanged(int userId, List<String> packages) { 2920 final int parentId = mSecurityPolicy.getProfileParent(userId); 2921 // We care only if the white-listed package is in a profile of 2922 // the group parent as only the parent can add widgets from the 2923 // profile and not the other way around. 2924 if (parentId != userId) { 2925 synchronized (mLock) { 2926 boolean providersChanged = false; 2927 2928 final int packageCount = packages.size(); 2929 for (int i = 0; i < packageCount; i++) { 2930 String packageName = packages.get(i); 2931 providersChanged |= updateProvidersForPackageLocked(packageName, 2932 userId, null); 2933 } 2934 2935 if (providersChanged) { 2936 saveGroupStateAsync(userId); 2937 scheduleNotifyGroupHostsForProvidersChangedLocked(userId); 2938 } 2939 } 2940 } 2941 } 2942 2943 private final class CallbackHandler extends Handler { 2944 public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1; 2945 public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2; 2946 public static final int MSG_NOTIFY_PROVIDERS_CHANGED = 3; 2947 public static final int MSG_NOTIFY_VIEW_DATA_CHANGED = 4; 2948 2949 public CallbackHandler(Looper looper) { 2950 super(looper, null, false); 2951 } 2952 2953 @Override 2954 public void handleMessage(Message message) { 2955 switch (message.what) { 2956 case MSG_NOTIFY_UPDATE_APP_WIDGET: { 2957 SomeArgs args = (SomeArgs) message.obj; 2958 Host host = (Host) args.arg1; 2959 IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; 2960 RemoteViews views = (RemoteViews) args.arg3; 2961 final int appWidgetId = args.argi1; 2962 args.recycle(); 2963 2964 handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views); 2965 } break; 2966 2967 case MSG_NOTIFY_PROVIDER_CHANGED: { 2968 SomeArgs args = (SomeArgs) message.obj; 2969 Host host = (Host) args.arg1; 2970 IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; 2971 AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3; 2972 final int appWidgetId = args.argi1; 2973 args.recycle(); 2974 2975 handleNotifyProviderChanged(host, callbacks, appWidgetId, info); 2976 } break; 2977 2978 case MSG_NOTIFY_PROVIDERS_CHANGED: { 2979 SomeArgs args = (SomeArgs) message.obj; 2980 Host host = (Host) args.arg1; 2981 IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; 2982 args.recycle(); 2983 2984 handleNotifyProvidersChanged(host, callbacks); 2985 } break; 2986 2987 case MSG_NOTIFY_VIEW_DATA_CHANGED: { 2988 SomeArgs args = (SomeArgs) message.obj; 2989 Host host = (Host) args.arg1; 2990 IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; 2991 final int appWidgetId = args.argi1; 2992 final int viewId = args.argi2; 2993 args.recycle(); 2994 2995 handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId); 2996 } break; 2997 } 2998 } 2999 } 3000 3001 private final class SecurityPolicy { 3002 3003 public boolean isEnabledGroupProfile(int profileId) { 3004 final int parentId = UserHandle.getCallingUserId(); 3005 return isParentOrProfile(parentId, profileId) && isProfileEnabled(profileId); 3006 } 3007 3008 public int[] getEnabledGroupProfileIds(int userId) { 3009 final int parentId = getGroupParent(userId); 3010 3011 final List<UserInfo> profiles; 3012 final long identity = Binder.clearCallingIdentity(); 3013 try { 3014 profiles = mUserManager.getProfiles(parentId); 3015 } finally { 3016 Binder.restoreCallingIdentity(identity); 3017 } 3018 3019 int enabledProfileCount = 0; 3020 final int profileCount = profiles.size(); 3021 for (int i = 0; i < profileCount; i++) { 3022 if (profiles.get(i).isEnabled()) { 3023 enabledProfileCount++; 3024 } 3025 } 3026 3027 int enabledProfileIndex = 0; 3028 final int[] profileIds = new int[enabledProfileCount]; 3029 for (int i = 0; i < profileCount; i++) { 3030 UserInfo profile = profiles.get(i); 3031 if (profile.isEnabled()) { 3032 profileIds[enabledProfileIndex] = profile.getUserHandle().getIdentifier(); 3033 enabledProfileIndex++; 3034 } 3035 } 3036 3037 return profileIds; 3038 } 3039 3040 public void enforceServiceExistsAndRequiresBindRemoteViewsPermission( 3041 ComponentName componentName, int userId) { 3042 final long identity = Binder.clearCallingIdentity(); 3043 try { 3044 ServiceInfo serviceInfo = mPackageManager.getServiceInfo(componentName, 3045 PackageManager.GET_PERMISSIONS, userId); 3046 if (serviceInfo == null) { 3047 throw new SecurityException("Service " + componentName 3048 + " not installed for user " + userId); 3049 } 3050 if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(serviceInfo.permission)) { 3051 throw new SecurityException("Service " + componentName 3052 + " in user " + userId + "does not require " 3053 + android.Manifest.permission.BIND_REMOTEVIEWS); 3054 } 3055 } catch (RemoteException re) { 3056 // Local call - shouldn't happen. 3057 } finally { 3058 Binder.restoreCallingIdentity(identity); 3059 } 3060 } 3061 3062 public void enforceModifyAppWidgetBindPermissions(String packageName) { 3063 mContext.enforceCallingPermission( 3064 android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS, 3065 "hasBindAppWidgetPermission packageName=" + packageName); 3066 } 3067 3068 public void enforceCallFromPackage(String packageName) { 3069 mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); 3070 } 3071 3072 public boolean hasCallerBindPermissionOrBindWhiteListedLocked(String packageName) { 3073 try { 3074 mContext.enforceCallingOrSelfPermission( 3075 android.Manifest.permission.BIND_APPWIDGET, null); 3076 } catch (SecurityException se) { 3077 if (!isCallerBindAppWidgetWhiteListedLocked(packageName)) { 3078 return false; 3079 } 3080 } 3081 return true; 3082 } 3083 3084 private boolean isCallerBindAppWidgetWhiteListedLocked(String packageName) { 3085 final int userId = UserHandle.getCallingUserId(); 3086 final int packageUid = getUidForPackage(packageName, userId); 3087 if (packageUid < 0) { 3088 throw new IllegalArgumentException("No package " + packageName 3089 + " for user " + userId); 3090 } 3091 synchronized (mLock) { 3092 ensureGroupStateLoadedLocked(userId); 3093 3094 Pair<Integer, String> packageId = Pair.create(userId, packageName); 3095 if (mPackagesWithBindWidgetPermission.contains(packageId)) { 3096 return true; 3097 } 3098 } 3099 3100 return false; 3101 } 3102 3103 public boolean canAccessAppWidget(Widget widget, int uid, String packageName) { 3104 if (isHostInPackageForUid(widget.host, uid, packageName)) { 3105 // Apps hosting the AppWidget have access to it. 3106 return true; 3107 } 3108 if (isProviderInPackageForUid(widget.provider, uid, packageName)) { 3109 // Apps providing the AppWidget have access to it. 3110 return true; 3111 } 3112 if (isHostAccessingProvider(widget.host, widget.provider, uid, packageName)) { 3113 // Apps hosting the AppWidget get to bind to a remote view service in the provider. 3114 return true; 3115 } 3116 final int userId = UserHandle.getUserId(uid); 3117 if ((widget.host.getUserId() == userId || (widget.provider != null 3118 && widget.provider.getUserId() == userId)) 3119 && mContext.checkCallingPermission(android.Manifest.permission.BIND_APPWIDGET) 3120 == PackageManager.PERMISSION_GRANTED) { 3121 // Apps that run in the same user as either the host or the provider and 3122 // have the bind widget permission have access to the widget. 3123 return true; 3124 } 3125 return false; 3126 } 3127 3128 private boolean isParentOrProfile(int parentId, int profileId) { 3129 if (parentId == profileId) { 3130 return true; 3131 } 3132 return getProfileParent(profileId) == parentId; 3133 } 3134 3135 public boolean isProviderInCallerOrInProfileAndWhitelListed(String packageName, 3136 int profileId) { 3137 final int callerId = UserHandle.getCallingUserId(); 3138 if (profileId == callerId) { 3139 return true; 3140 } 3141 final int parentId = getProfileParent(profileId); 3142 if (parentId != callerId) { 3143 return false; 3144 } 3145 return isProviderWhitelListed(packageName, profileId); 3146 } 3147 3148 public boolean isProviderWhitelListed(String packageName, int profileId) { 3149 DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService( 3150 DevicePolicyManagerInternal.class); 3151 3152 // If the policy manager is not available on the device we deny it all. 3153 if (devicePolicyManager == null) { 3154 return false; 3155 } 3156 3157 List<String> crossProfilePackages = devicePolicyManager 3158 .getCrossProfileWidgetProviders(profileId); 3159 3160 return crossProfilePackages.contains(packageName); 3161 } 3162 3163 public int getProfileParent(int profileId) { 3164 final long identity = Binder.clearCallingIdentity(); 3165 try { 3166 UserInfo parent = mUserManager.getProfileParent(profileId); 3167 if (parent != null) { 3168 return parent.getUserHandle().getIdentifier(); 3169 } 3170 } finally { 3171 Binder.restoreCallingIdentity(identity); 3172 } 3173 return UNKNOWN_USER_ID; 3174 } 3175 3176 public int getGroupParent(int profileId) { 3177 final int parentId = mSecurityPolicy.getProfileParent(profileId); 3178 return (parentId != UNKNOWN_USER_ID) ? parentId : profileId; 3179 } 3180 3181 public boolean isHostInPackageForUid(Host host, int uid, String packageName) { 3182 return host.id.uid == uid && host.id.packageName.equals(packageName); 3183 } 3184 3185 public boolean isProviderInPackageForUid(Provider provider, int uid, 3186 String packageName) { 3187 // Packages providing the AppWidget have access to it. 3188 return provider != null && provider.id.uid == uid 3189 && provider.id.componentName.getPackageName().equals(packageName); 3190 } 3191 3192 public boolean isHostAccessingProvider(Host host, Provider provider, int uid, 3193 String packageName) { 3194 // The host creates a package context to bind to remote views service in the provider. 3195 return host.id.uid == uid && provider != null 3196 && provider.id.componentName.getPackageName().equals(packageName); 3197 } 3198 3199 private boolean isProfileEnabled(int profileId) { 3200 final long identity = Binder.clearCallingIdentity(); 3201 try { 3202 UserInfo userInfo = mUserManager.getUserInfo(profileId); 3203 if (userInfo == null || !userInfo.isEnabled()) { 3204 return false; 3205 } 3206 } finally { 3207 Binder.restoreCallingIdentity(identity); 3208 } 3209 return true; 3210 } 3211 } 3212 3213 private static final class Provider { 3214 ProviderId id; 3215 AppWidgetProviderInfo info; 3216 ArrayList<Widget> widgets = new ArrayList<>(); 3217 PendingIntent broadcast; 3218 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 3219 3220 int tag = TAG_UNDEFINED; // for use while saving state (the index) 3221 3222 public int getUserId() { 3223 return UserHandle.getUserId(id.uid); 3224 } 3225 3226 public boolean isInPackageForUser(String packageName, int userId) { 3227 return getUserId() == userId 3228 && id.componentName.getPackageName().equals(packageName); 3229 } 3230 3231 // is there an instance of this provider hosted by the given app? 3232 public boolean hostedByPackageForUser(String packageName, int userId) { 3233 final int N = widgets.size(); 3234 for (int i = 0; i < N; i++) { 3235 Widget widget = widgets.get(i); 3236 if (packageName.equals(widget.host.id.packageName) 3237 && widget.host.getUserId() == userId) { 3238 return true; 3239 } 3240 } 3241 return false; 3242 } 3243 3244 @Override 3245 public String toString() { 3246 return "Provider{" + id + (zombie ? " Z" : "") + '}'; 3247 } 3248 } 3249 3250 private static final class ProviderId { 3251 final int uid; 3252 final ComponentName componentName; 3253 3254 private ProviderId(int uid, ComponentName componentName) { 3255 this.uid = uid; 3256 this.componentName = componentName; 3257 } 3258 3259 @Override 3260 public boolean equals(Object obj) { 3261 if (this == obj) { 3262 return true; 3263 } 3264 if (obj == null) { 3265 return false; 3266 } 3267 if (getClass() != obj.getClass()) { 3268 return false; 3269 } 3270 ProviderId other = (ProviderId) obj; 3271 if (uid != other.uid) { 3272 return false; 3273 } 3274 if (componentName == null) { 3275 if (other.componentName != null) { 3276 return false; 3277 } 3278 } else if (!componentName.equals(other.componentName)) { 3279 return false; 3280 } 3281 return true; 3282 } 3283 3284 @Override 3285 public int hashCode() { 3286 int result = uid; 3287 result = 31 * result + ((componentName != null) 3288 ? componentName.hashCode() : 0); 3289 return result; 3290 } 3291 3292 @Override 3293 public String toString() { 3294 return "ProviderId{user:" + UserHandle.getUserId(uid) + ", app:" 3295 + UserHandle.getAppId(uid) + ", cmp:" + componentName + '}'; 3296 } 3297 } 3298 3299 private static final class Host { 3300 HostId id; 3301 ArrayList<Widget> widgets = new ArrayList<>(); 3302 IAppWidgetHost callbacks; 3303 boolean zombie; // if we're in safe mode, don't prune this just because nobody references it 3304 3305 int tag = TAG_UNDEFINED; // for use while saving state (the index) 3306 3307 public int getUserId() { 3308 return UserHandle.getUserId(id.uid); 3309 } 3310 3311 public boolean isInPackageForUser(String packageName, int userId) { 3312 return getUserId() == userId && id.packageName.equals(packageName); 3313 } 3314 3315 private boolean hostsPackageForUser(String pkg, int userId) { 3316 final int N = widgets.size(); 3317 for (int i = 0; i < N; i++) { 3318 Provider provider = widgets.get(i).provider; 3319 if (provider != null && provider.getUserId() == userId && provider.info != null 3320 && pkg.equals(provider.info.provider.getPackageName())) { 3321 return true; 3322 } 3323 } 3324 return false; 3325 } 3326 3327 @Override 3328 public String toString() { 3329 return "Host{" + id + (zombie ? " Z" : "") + '}'; 3330 } 3331 } 3332 3333 private static final class HostId { 3334 final int uid; 3335 final int hostId; 3336 final String packageName; 3337 3338 public HostId(int uid, int hostId, String packageName) { 3339 this.uid = uid; 3340 this.hostId = hostId; 3341 this.packageName = packageName; 3342 } 3343 3344 @Override 3345 public boolean equals(Object obj) { 3346 if (this == obj) { 3347 return true; 3348 } 3349 if (obj == null) { 3350 return false; 3351 } 3352 if (getClass() != obj.getClass()) { 3353 return false; 3354 } 3355 HostId other = (HostId) obj; 3356 if (uid != other.uid) { 3357 return false; 3358 } 3359 if (hostId != other.hostId) { 3360 return false; 3361 } 3362 if (packageName == null) { 3363 if (other.packageName != null) { 3364 return false; 3365 } 3366 } else if (!packageName.equals(other.packageName)) { 3367 return false; 3368 } 3369 return true; 3370 } 3371 3372 @Override 3373 public int hashCode() { 3374 int result = uid; 3375 result = 31 * result + hostId; 3376 result = 31 * result + ((packageName != null) 3377 ? packageName.hashCode() : 0); 3378 return result; 3379 } 3380 3381 @Override 3382 public String toString() { 3383 return "HostId{user:" + UserHandle.getUserId(uid) + ", app:" 3384 + UserHandle.getAppId(uid) + ", hostId:" + hostId 3385 + ", pkg:" + packageName + '}'; 3386 } 3387 } 3388 3389 private static final class Widget { 3390 int appWidgetId; 3391 int restoredId; // tracking & remapping any restored state 3392 Provider provider; 3393 RemoteViews views; 3394 Bundle options; 3395 Host host; 3396 3397 @Override 3398 public String toString() { 3399 return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}'; 3400 } 3401 } 3402 3403 /** 3404 * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This 3405 * needs to be a static inner class since a reference to the ServiceConnection is held globally 3406 * and may lead us to leak AppWidgetService instances (if there were more than one). 3407 */ 3408 private static final class ServiceConnectionProxy implements ServiceConnection { 3409 private final IRemoteViewsAdapterConnection mConnectionCb; 3410 3411 ServiceConnectionProxy(IBinder connectionCb) { 3412 mConnectionCb = IRemoteViewsAdapterConnection.Stub 3413 .asInterface(connectionCb); 3414 } 3415 3416 public void onServiceConnected(ComponentName name, IBinder service) { 3417 try { 3418 mConnectionCb.onServiceConnected(service); 3419 } catch (RemoteException re) { 3420 Slog.e(TAG, "Error passing service interface", re); 3421 } 3422 } 3423 3424 public void onServiceDisconnected(ComponentName name) { 3425 disconnect(); 3426 } 3427 3428 public void disconnect() { 3429 try { 3430 mConnectionCb.onServiceDisconnected(); 3431 } catch (RemoteException re) { 3432 Slog.e(TAG, "Error clearing service interface", re); 3433 } 3434 } 3435 } 3436 3437 private class LoadedWidgetState { 3438 final Widget widget; 3439 final int hostTag; 3440 final int providerTag; 3441 3442 public LoadedWidgetState(Widget widget, int hostTag, int providerTag) { 3443 this.widget = widget; 3444 this.hostTag = hostTag; 3445 this.providerTag = providerTag; 3446 } 3447 } 3448 3449 private final class SaveStateRunnable implements Runnable { 3450 final int mUserId; 3451 3452 public SaveStateRunnable(int userId) { 3453 mUserId = userId; 3454 } 3455 3456 @Override 3457 public void run() { 3458 synchronized (mLock) { 3459 ensureGroupStateLoadedLocked(mUserId); 3460 saveStateLocked(mUserId); 3461 } 3462 } 3463 } 3464 3465 /** 3466 * This class encapsulates the backup and restore logic for a user group state. 3467 */ 3468 private final class BackupRestoreController { 3469 private static final String TAG = "BackupRestoreController"; 3470 3471 private static final boolean DEBUG = true; 3472 3473 // Version of backed-up widget state. 3474 private static final int WIDGET_STATE_VERSION = 2; 3475 3476 // We need to make sure to wipe the pre-restore widget state only once for 3477 // a given package. Keep track of what we've done so far here; the list is 3478 // cleared at the start of every system restore pass, but preserved through 3479 // any install-time restore operations. 3480 private final HashSet<String> mPrunedApps = new HashSet<>(); 3481 3482 private final HashMap<Provider, ArrayList<RestoreUpdateRecord>> mUpdatesByProvider = 3483 new HashMap<>(); 3484 private final HashMap<Host, ArrayList<RestoreUpdateRecord>> mUpdatesByHost = 3485 new HashMap<>(); 3486 3487 public List<String> getWidgetParticipants(int userId) { 3488 if (DEBUG) { 3489 Slog.i(TAG, "Getting widget participants for user: " + userId); 3490 } 3491 3492 HashSet<String> packages = new HashSet<>(); 3493 synchronized (mLock) { 3494 final int N = mWidgets.size(); 3495 for (int i = 0; i < N; i++) { 3496 Widget widget = mWidgets.get(i); 3497 3498 // Skip cross-user widgets. 3499 if (!isProviderAndHostInUser(widget, userId)) { 3500 continue; 3501 } 3502 3503 packages.add(widget.host.id.packageName); 3504 Provider provider = widget.provider; 3505 if (provider != null) { 3506 packages.add(provider.id.componentName.getPackageName()); 3507 } 3508 } 3509 } 3510 return new ArrayList<>(packages); 3511 } 3512 3513 public byte[] getWidgetState(String backedupPackage, int userId) { 3514 if (DEBUG) { 3515 Slog.i(TAG, "Getting widget state for user: " + userId); 3516 } 3517 3518 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 3519 synchronized (mLock) { 3520 // Preflight: if this app neither hosts nor provides any live widgets 3521 // we have no work to do. 3522 if (!packageNeedsWidgetBackupLocked(backedupPackage, userId)) { 3523 return null; 3524 } 3525 3526 try { 3527 XmlSerializer out = new FastXmlSerializer(); 3528 out.setOutput(stream, "utf-8"); 3529 out.startDocument(null, true); 3530 out.startTag(null, "ws"); // widget state 3531 out.attribute(null, "version", String.valueOf(WIDGET_STATE_VERSION)); 3532 out.attribute(null, "pkg", backedupPackage); 3533 3534 // Remember all the providers that are currently hosted or published 3535 // by this package: that is, all of the entities related to this app 3536 // which will need to be told about id remapping. 3537 int index = 0; 3538 int N = mProviders.size(); 3539 for (int i = 0; i < N; i++) { 3540 Provider provider = mProviders.get(i); 3541 3542 if (!provider.widgets.isEmpty() 3543 && (provider.isInPackageForUser(backedupPackage, userId) 3544 || provider.hostedByPackageForUser(backedupPackage, userId))) { 3545 provider.tag = index; 3546 serializeProvider(out, provider); 3547 index++; 3548 } 3549 } 3550 3551 N = mHosts.size(); 3552 index = 0; 3553 for (int i = 0; i < N; i++) { 3554 Host host = mHosts.get(i); 3555 3556 if (!host.widgets.isEmpty() 3557 && (host.isInPackageForUser(backedupPackage, userId) 3558 || host.hostsPackageForUser(backedupPackage, userId))) { 3559 host.tag = index; 3560 serializeHost(out, host); 3561 index++; 3562 } 3563 } 3564 3565 // All widget instances involving this package, 3566 // either as host or as provider 3567 N = mWidgets.size(); 3568 for (int i = 0; i < N; i++) { 3569 Widget widget = mWidgets.get(i); 3570 3571 Provider provider = widget.provider; 3572 if (widget.host.isInPackageForUser(backedupPackage, userId) 3573 || (provider != null 3574 && provider.isInPackageForUser(backedupPackage, userId))) { 3575 serializeAppWidget(out, widget); 3576 } 3577 } 3578 3579 out.endTag(null, "ws"); 3580 out.endDocument(); 3581 } catch (IOException e) { 3582 Slog.w(TAG, "Unable to save widget state for " + backedupPackage); 3583 return null; 3584 } 3585 } 3586 3587 return stream.toByteArray(); 3588 } 3589 3590 public void restoreStarting(int userId) { 3591 if (DEBUG) { 3592 Slog.i(TAG, "Restore starting for user: " + userId); 3593 } 3594 3595 synchronized (mLock) { 3596 // We're starting a new "system" restore operation, so any widget restore 3597 // state that we see from here on is intended to replace the current 3598 // widget configuration of any/all of the affected apps. 3599 mPrunedApps.clear(); 3600 mUpdatesByProvider.clear(); 3601 mUpdatesByHost.clear(); 3602 } 3603 } 3604 3605 public void restoreWidgetState(String packageName, byte[] restoredState, int userId) { 3606 if (DEBUG) { 3607 Slog.i(TAG, "Restoring widget state for user:" + userId 3608 + " package: " + packageName); 3609 } 3610 3611 ByteArrayInputStream stream = new ByteArrayInputStream(restoredState); 3612 try { 3613 // Providers mentioned in the widget dataset by ordinal 3614 ArrayList<Provider> restoredProviders = new ArrayList<>(); 3615 3616 // Hosts mentioned in the widget dataset by ordinal 3617 ArrayList<Host> restoredHosts = new ArrayList<>(); 3618 3619 XmlPullParser parser = Xml.newPullParser(); 3620 parser.setInput(stream, null); 3621 3622 synchronized (mLock) { 3623 int type; 3624 do { 3625 type = parser.next(); 3626 if (type == XmlPullParser.START_TAG) { 3627 final String tag = parser.getName(); 3628 if ("ws".equals(tag)) { 3629 String version = parser.getAttributeValue(null, "version"); 3630 3631 final int versionNumber = Integer.parseInt(version); 3632 if (versionNumber > WIDGET_STATE_VERSION) { 3633 Slog.w(TAG, "Unable to process state version " + version); 3634 return; 3635 } 3636 3637 // TODO: fix up w.r.t. canonical vs current package names 3638 String pkg = parser.getAttributeValue(null, "pkg"); 3639 if (!packageName.equals(pkg)) { 3640 Slog.w(TAG, "Package mismatch in ws"); 3641 return; 3642 } 3643 } else if ("p".equals(tag)) { 3644 String pkg = parser.getAttributeValue(null, "pkg"); 3645 String cl = parser.getAttributeValue(null, "cl"); 3646 3647 // hostedProviders index will match 'p' attribute in widget's 3648 // entry in the xml file being restored 3649 // If there's no live entry for this provider, add an inactive one 3650 // so that widget IDs referring to them can be properly allocated 3651 3652 // Backup and resotre only for the parent profile. 3653 ComponentName componentName = new ComponentName(pkg, cl); 3654 3655 Provider p = findProviderLocked(componentName, userId); 3656 if (p == null) { 3657 p = new Provider(); 3658 p.id = new ProviderId(UNKNOWN_UID, componentName); 3659 p.info = new AppWidgetProviderInfo(); 3660 p.info.provider = componentName; 3661 p.zombie = true; 3662 mProviders.add(p); 3663 } 3664 if (DEBUG) { 3665 Slog.i(TAG, " provider " + p.id); 3666 } 3667 restoredProviders.add(p); 3668 } else if ("h".equals(tag)) { 3669 // The host app may not yet exist on the device. If it's here we 3670 // just use the existing Host entry, otherwise we create a 3671 // placeholder whose uid will be fixed up at PACKAGE_ADDED time. 3672 String pkg = parser.getAttributeValue(null, "pkg"); 3673 3674 final int uid = getUidForPackage(pkg, userId); 3675 final int hostId = Integer.parseInt( 3676 parser.getAttributeValue(null, "id"), 16); 3677 3678 HostId id = new HostId(uid, hostId, pkg); 3679 Host h = lookupOrAddHostLocked(id); 3680 restoredHosts.add(h); 3681 3682 if (DEBUG) { 3683 Slog.i(TAG, " host[" + restoredHosts.size() 3684 + "]: {" + h.id + "}"); 3685 } 3686 } else if ("g".equals(tag)) { 3687 int restoredId = Integer.parseInt( 3688 parser.getAttributeValue(null, "id"), 16); 3689 int hostIndex = Integer.parseInt( 3690 parser.getAttributeValue(null, "h"), 16); 3691 Host host = restoredHosts.get(hostIndex); 3692 Provider p = null; 3693 String prov = parser.getAttributeValue(null, "p"); 3694 if (prov != null) { 3695 // could have been null if the app had allocated an id 3696 // but not yet established a binding under that id 3697 int which = Integer.parseInt(prov, 16); 3698 p = restoredProviders.get(which); 3699 } 3700 3701 // We'll be restoring widget state for both the host and 3702 // provider sides of this widget ID, so make sure we are 3703 // beginning from a clean slate on both fronts. 3704 pruneWidgetStateLocked(host.id.packageName, userId); 3705 if (p != null) { 3706 pruneWidgetStateLocked(p.id.componentName.getPackageName(), 3707 userId); 3708 } 3709 3710 // Have we heard about this ancestral widget instance before? 3711 Widget id = findRestoredWidgetLocked(restoredId, host, p); 3712 if (id == null) { 3713 id = new Widget(); 3714 id.appWidgetId = incrementAndGetAppWidgetIdLocked(userId); 3715 id.restoredId = restoredId; 3716 id.options = parseWidgetIdOptions(parser); 3717 id.host = host; 3718 id.host.widgets.add(id); 3719 id.provider = p; 3720 if (id.provider != null) { 3721 id.provider.widgets.add(id); 3722 } 3723 if (DEBUG) { 3724 Slog.i(TAG, "New restored id " + restoredId 3725 + " now " + id); 3726 } 3727 mWidgets.add(id); 3728 } 3729 if (id.provider.info != null) { 3730 stashProviderRestoreUpdateLocked(id.provider, 3731 restoredId, id.appWidgetId); 3732 } else { 3733 Slog.w(TAG, "Missing provider for restored widget " + id); 3734 } 3735 stashHostRestoreUpdateLocked(id.host, restoredId, id.appWidgetId); 3736 3737 if (DEBUG) { 3738 Slog.i(TAG, " instance: " + restoredId 3739 + " -> " + id.appWidgetId 3740 + " :: p=" + id.provider); 3741 } 3742 } 3743 } 3744 } while (type != XmlPullParser.END_DOCUMENT); 3745 3746 // We've updated our own bookkeeping. We'll need to notify the hosts and 3747 // providers about the changes, but we can't do that yet because the restore 3748 // target is not necessarily fully live at this moment. Set aside the 3749 // information for now; the backup manager will call us once more at the 3750 // end of the process when all of the targets are in a known state, and we 3751 // will update at that point. 3752 } 3753 } catch (XmlPullParserException | IOException e) { 3754 Slog.w(TAG, "Unable to restore widget state for " + packageName); 3755 } finally { 3756 saveGroupStateAsync(userId); 3757 } 3758 } 3759 3760 // Called once following the conclusion of a restore operation. This is when we 3761 // send out updates to apps involved in widget-state restore telling them about 3762 // the new widget ID space. 3763 public void restoreFinished(int userId) { 3764 if (DEBUG) { 3765 Slog.i(TAG, "restoreFinished for " + userId); 3766 } 3767 3768 final UserHandle userHandle = new UserHandle(userId); 3769 synchronized (mLock) { 3770 // Build the providers' broadcasts and send them off 3771 Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries 3772 = mUpdatesByProvider.entrySet(); 3773 for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) { 3774 // For each provider there's a list of affected IDs 3775 Provider provider = e.getKey(); 3776 ArrayList<RestoreUpdateRecord> updates = e.getValue(); 3777 final int pending = countPendingUpdates(updates); 3778 if (DEBUG) { 3779 Slog.i(TAG, "Provider " + provider + " pending: " + pending); 3780 } 3781 if (pending > 0) { 3782 int[] oldIds = new int[pending]; 3783 int[] newIds = new int[pending]; 3784 final int N = updates.size(); 3785 int nextPending = 0; 3786 for (int i = 0; i < N; i++) { 3787 RestoreUpdateRecord r = updates.get(i); 3788 if (!r.notified) { 3789 r.notified = true; 3790 oldIds[nextPending] = r.oldId; 3791 newIds[nextPending] = r.newId; 3792 nextPending++; 3793 if (DEBUG) { 3794 Slog.i(TAG, " " + r.oldId + " => " + r.newId); 3795 } 3796 } 3797 } 3798 sendWidgetRestoreBroadcastLocked( 3799 AppWidgetManager.ACTION_APPWIDGET_RESTORED, 3800 provider, null, oldIds, newIds, userHandle); 3801 } 3802 } 3803 3804 // same thing per host 3805 Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries 3806 = mUpdatesByHost.entrySet(); 3807 for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) { 3808 Host host = e.getKey(); 3809 if (host.id.uid != UNKNOWN_UID) { 3810 ArrayList<RestoreUpdateRecord> updates = e.getValue(); 3811 final int pending = countPendingUpdates(updates); 3812 if (DEBUG) { 3813 Slog.i(TAG, "Host " + host + " pending: " + pending); 3814 } 3815 if (pending > 0) { 3816 int[] oldIds = new int[pending]; 3817 int[] newIds = new int[pending]; 3818 final int N = updates.size(); 3819 int nextPending = 0; 3820 for (int i = 0; i < N; i++) { 3821 RestoreUpdateRecord r = updates.get(i); 3822 if (!r.notified) { 3823 r.notified = true; 3824 oldIds[nextPending] = r.oldId; 3825 newIds[nextPending] = r.newId; 3826 nextPending++; 3827 if (DEBUG) { 3828 Slog.i(TAG, " " + r.oldId + " => " + r.newId); 3829 } 3830 } 3831 } 3832 sendWidgetRestoreBroadcastLocked( 3833 AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED, 3834 null, host, oldIds, newIds, userHandle); 3835 } 3836 } 3837 } 3838 } 3839 } 3840 3841 private Provider findProviderLocked(ComponentName componentName, int userId) { 3842 final int providerCount = mProviders.size(); 3843 for (int i = 0; i < providerCount; i++) { 3844 Provider provider = mProviders.get(i); 3845 if (provider.getUserId() == userId 3846 && provider.id.componentName.equals(componentName)) { 3847 return provider; 3848 } 3849 } 3850 return null; 3851 } 3852 3853 private Widget findRestoredWidgetLocked(int restoredId, Host host, Provider p) { 3854 if (DEBUG) { 3855 Slog.i(TAG, "Find restored widget: id=" + restoredId 3856 + " host=" + host + " provider=" + p); 3857 } 3858 3859 if (p == null || host == null) { 3860 return null; 3861 } 3862 3863 final int N = mWidgets.size(); 3864 for (int i = 0; i < N; i++) { 3865 Widget widget = mWidgets.get(i); 3866 if (widget.restoredId == restoredId 3867 && widget.host.id.equals(host.id) 3868 && widget.provider.id.equals(p.id)) { 3869 if (DEBUG) { 3870 Slog.i(TAG, " Found at " + i + " : " + widget); 3871 } 3872 return widget; 3873 } 3874 } 3875 return null; 3876 } 3877 3878 private boolean packageNeedsWidgetBackupLocked(String packageName, int userId) { 3879 int N = mWidgets.size(); 3880 for (int i = 0; i < N; i++) { 3881 Widget widget = mWidgets.get(i); 3882 3883 // Skip cross-user widgets. 3884 if (!isProviderAndHostInUser(widget, userId)) { 3885 continue; 3886 } 3887 3888 if (widget.host.isInPackageForUser(packageName, userId)) { 3889 // this package is hosting widgets, so it knows widget IDs. 3890 return true; 3891 } 3892 3893 Provider provider = widget.provider; 3894 if (provider != null && provider.isInPackageForUser(packageName, userId)) { 3895 // someone is hosting this app's widgets, so it knows widget IDs. 3896 return true; 3897 } 3898 } 3899 return false; 3900 } 3901 3902 private void stashProviderRestoreUpdateLocked(Provider provider, int oldId, int newId) { 3903 ArrayList<RestoreUpdateRecord> r = mUpdatesByProvider.get(provider); 3904 if (r == null) { 3905 r = new ArrayList<>(); 3906 mUpdatesByProvider.put(provider, r); 3907 } else { 3908 // don't duplicate 3909 if (alreadyStashed(r, oldId, newId)) { 3910 if (DEBUG) { 3911 Slog.i(TAG, "ID remap " + oldId + " -> " + newId 3912 + " already stashed for " + provider); 3913 } 3914 return; 3915 } 3916 } 3917 r.add(new RestoreUpdateRecord(oldId, newId)); 3918 } 3919 3920 private boolean alreadyStashed(ArrayList<RestoreUpdateRecord> stash, 3921 final int oldId, final int newId) { 3922 final int N = stash.size(); 3923 for (int i = 0; i < N; i++) { 3924 RestoreUpdateRecord r = stash.get(i); 3925 if (r.oldId == oldId && r.newId == newId) { 3926 return true; 3927 } 3928 } 3929 return false; 3930 } 3931 3932 private void stashHostRestoreUpdateLocked(Host host, int oldId, int newId) { 3933 ArrayList<RestoreUpdateRecord> r = mUpdatesByHost.get(host); 3934 if (r == null) { 3935 r = new ArrayList<>(); 3936 mUpdatesByHost.put(host, r); 3937 } else { 3938 if (alreadyStashed(r, oldId, newId)) { 3939 if (DEBUG) { 3940 Slog.i(TAG, "ID remap " + oldId + " -> " + newId 3941 + " already stashed for " + host); 3942 } 3943 return; 3944 } 3945 } 3946 r.add(new RestoreUpdateRecord(oldId, newId)); 3947 } 3948 3949 private void sendWidgetRestoreBroadcastLocked(String action, Provider provider, 3950 Host host, int[] oldIds, int[] newIds, UserHandle userHandle) { 3951 Intent intent = new Intent(action); 3952 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS, oldIds); 3953 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, newIds); 3954 if (provider != null) { 3955 intent.setComponent(provider.info.provider); 3956 sendBroadcastAsUser(intent, userHandle); 3957 } 3958 if (host != null) { 3959 intent.setComponent(null); 3960 intent.setPackage(host.id.packageName); 3961 intent.putExtra(AppWidgetManager.EXTRA_HOST_ID, host.id.hostId); 3962 sendBroadcastAsUser(intent, userHandle); 3963 } 3964 } 3965 3966 // We're restoring widget state for 'pkg', so we start by wiping (a) all widget 3967 // instances that are hosted by that app, and (b) all instances in other hosts 3968 // for which 'pkg' is the provider. We assume that we'll be restoring all of 3969 // these hosts & providers, so will be reconstructing a correct live state. 3970 private void pruneWidgetStateLocked(String pkg, int userId) { 3971 if (!mPrunedApps.contains(pkg)) { 3972 if (DEBUG) { 3973 Slog.i(TAG, "pruning widget state for restoring package " + pkg); 3974 } 3975 for (int i = mWidgets.size() - 1; i >= 0; i--) { 3976 Widget widget = mWidgets.get(i); 3977 3978 Host host = widget.host; 3979 Provider provider = widget.provider; 3980 3981 if (host.hostsPackageForUser(pkg, userId) 3982 || (provider != null && provider.isInPackageForUser(pkg, userId))) { 3983 // 'pkg' is either the host or the provider for this instances, 3984 // so we tear it down in anticipation of it (possibly) being 3985 // reconstructed due to the restore 3986 host.widgets.remove(widget); 3987 provider.widgets.remove(widget); 3988 unbindAppWidgetRemoteViewsServicesLocked(widget); 3989 mWidgets.remove(i); 3990 } 3991 } 3992 mPrunedApps.add(pkg); 3993 } else { 3994 if (DEBUG) { 3995 Slog.i(TAG, "already pruned " + pkg + ", continuing normally"); 3996 } 3997 } 3998 } 3999 4000 private boolean isProviderAndHostInUser(Widget widget, int userId) { 4001 // Backup only widgets hosted or provided by the owner profile. 4002 return widget.host.getUserId() == userId && (widget.provider == null 4003 || widget.provider.getUserId() == userId); 4004 } 4005 4006 private Bundle parseWidgetIdOptions(XmlPullParser parser) { 4007 Bundle options = new Bundle(); 4008 String minWidthString = parser.getAttributeValue(null, "min_width"); 4009 if (minWidthString != null) { 4010 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 4011 Integer.parseInt(minWidthString, 16)); 4012 } 4013 String minHeightString = parser.getAttributeValue(null, "min_height"); 4014 if (minHeightString != null) { 4015 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 4016 Integer.parseInt(minHeightString, 16)); 4017 } 4018 String maxWidthString = parser.getAttributeValue(null, "max_width"); 4019 if (maxWidthString != null) { 4020 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 4021 Integer.parseInt(maxWidthString, 16)); 4022 } 4023 String maxHeightString = parser.getAttributeValue(null, "max_height"); 4024 if (maxHeightString != null) { 4025 options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 4026 Integer.parseInt(maxHeightString, 16)); 4027 } 4028 String categoryString = parser.getAttributeValue(null, "host_category"); 4029 if (categoryString != null) { 4030 options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, 4031 Integer.parseInt(categoryString, 16)); 4032 } 4033 return options; 4034 } 4035 4036 private int countPendingUpdates(ArrayList<RestoreUpdateRecord> updates) { 4037 int pending = 0; 4038 final int N = updates.size(); 4039 for (int i = 0; i < N; i++) { 4040 RestoreUpdateRecord r = updates.get(i); 4041 if (!r.notified) { 4042 pending++; 4043 } 4044 } 4045 return pending; 4046 } 4047 4048 // Accumulate a list of updates that affect the given provider for a final 4049 // coalesced notification broadcast once restore is over. 4050 private class RestoreUpdateRecord { 4051 public int oldId; 4052 public int newId; 4053 public boolean notified; 4054 4055 public RestoreUpdateRecord(int theOldId, int theNewId) { 4056 oldId = theOldId; 4057 newId = theNewId; 4058 notified = false; 4059 } 4060 } 4061 } 4062} 4063