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