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