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