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