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