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