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