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