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