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