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