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