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