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