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