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