• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
23 
24 import android.annotation.UserIdInt;
25 import android.app.ActivityManager;
26 import android.app.AlarmManager;
27 import android.app.AppGlobals;
28 import android.app.AppOpsManager;
29 import android.app.IApplicationThread;
30 import android.app.IServiceConnection;
31 import android.app.KeyguardManager;
32 import android.app.PendingIntent;
33 import android.app.admin.DevicePolicyManagerInternal;
34 import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
35 import android.appwidget.AppWidgetManager;
36 import android.appwidget.AppWidgetManagerInternal;
37 import android.appwidget.AppWidgetProviderInfo;
38 import android.appwidget.PendingHostUpdate;
39 import android.content.BroadcastReceiver;
40 import android.content.ComponentName;
41 import android.content.Context;
42 import android.content.Intent;
43 import android.content.Intent.FilterComparison;
44 import android.content.IntentFilter;
45 import android.content.IntentSender;
46 import android.content.ServiceConnection;
47 import android.content.pm.ActivityInfo;
48 import android.content.pm.ApplicationInfo;
49 import android.content.pm.IPackageManager;
50 import android.content.pm.LauncherApps;
51 import android.content.pm.PackageInfo;
52 import android.content.pm.PackageManager;
53 import android.content.pm.PackageManager.NameNotFoundException;
54 import android.content.pm.PackageManagerInternal;
55 import android.content.pm.ParceledListSlice;
56 import android.content.pm.ResolveInfo;
57 import android.content.pm.ServiceInfo;
58 import android.content.pm.ShortcutServiceInternal;
59 import android.content.pm.SuspendDialogInfo;
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 
AppWidgetServiceImpl(Context context)249     AppWidgetServiceImpl(Context context) {
250         mContext = context;
251     }
252 
onStart()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 
computeMaximumWidgetBitmapMemory()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 
registerBroadcastReceiver()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 
registerOnCrossProfileProvidersChangedListener()322     private void registerOnCrossProfileProvidersChangedListener() {
323         // The device policy is an optional component.
324         if (mDevicePolicyManagerInternal != null) {
325             mDevicePolicyManagerInternal.addOnCrossProfileWidgetProvidersChangeListener(this);
326         }
327     }
328 
setSafeMode(boolean safeMode)329     public void setSafeMode(boolean safeMode) {
330         mSafeMode = safeMode;
331     }
332 
onConfigurationChanged()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 
onPackageBroadcastReceived(Intent intent, int userId)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      */
reloadWidgetsMaskedStateForGroup(int userId)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 
reloadWidgetsMaskedState(int userId)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      */
updateWidgetPackageSuspensionMaskedState(Intent intent, boolean suspended, int profileId)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 
createMaskedWidgetBitmap(String providerPackage, int providerUserId)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 
createMaskedWidgetRemoteViews(Bitmap icon, boolean showBadge, PendingIntent onClickIntent)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      */
maskWidgetsViewsLocked(Provider provider, Widget targetWidget)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 SuspendDialogInfo dialogInfo = mPackageManagerInternal
634                             .getSuspendedDialogInfo(providerPackage, providerUserId);
635                     onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(
636                             providerPackage, suspendingPackage, dialogInfo, 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 
unmaskWidgetsViewsLocked(Provider provider)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 
resolveHostUidLocked(String pkg, int uid)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 
ensureGroupStateLoadedLocked(int userId)693     private void ensureGroupStateLoadedLocked(int userId) {
694         ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ true );
695     }
696 
ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked)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 
isUserRunningAndUnlocked(@serIdInt int userId)743     private boolean isUserRunningAndUnlocked(@UserIdInt int userId) {
744         return mUserManager.isUserUnlockingOrUnlocked(userId);
745     }
746 
747     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)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 
dumpProto(FileDescriptor fd)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 
dumpProtoWidget(ProtoOutputStream proto, Widget widget)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 
dumpInternal(PrintWriter pw)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
startListening(IAppWidgetHost callbacks, String callingPackage, int hostId, int[] appWidgetIds)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
stopListening(String callingPackage, int hostId)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
allocateAppWidgetId(String callingPackage, int hostId)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
deleteAppWidgetId(String callingPackage, int appWidgetId)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
hasBindAppWidgetPermission(String packageName, int grantId)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
setBindAppWidgetPermission(String packageName, int grantId, boolean grantPermission)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
createAppWidgetConfigIntentSender(String callingPackage, int appWidgetId, final int intentFlags)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
bindAppWidgetId(String callingPackage, int appWidgetId, int providerProfileId, ComponentName providerComponent, Bundle options)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
getAppWidgetIds(ComponentName componentName)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
getAppWidgetIdsForHost(String callingPackage, int hostId)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
bindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent, IApplicationThread caller, IBinder activtiyToken, IServiceConnection connection, int flags)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
deleteHost(String callingPackage, int hostId)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
deleteAllHosts()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
getAppWidgetInfo(String callingPackage, int appWidgetId)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
getAppWidgetViews(String callingPackage, int appWidgetId)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
updateAppWidgetOptions(String callingPackage, int appWidgetId, Bundle options)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
getAppWidgetOptions(String callingPackage, int appWidgetId)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
updateAppWidgetIds(String callingPackage, int[] appWidgetIds, RemoteViews views)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
partiallyUpdateAppWidgetIds(String callingPackage, int[] appWidgetIds, RemoteViews views)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
notifyAppWidgetViewDataChanged(String callingPackage, int[] appWidgetIds, int viewId)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
updateAppWidgetProvider(ComponentName componentName, RemoteViews views)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
updateAppWidgetProviderInfo(ComponentName componentName, String metadataKey)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
isRequestPinAppWidgetSupported()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
requestPinAppWidget(String callingPackage, ComponentName componentName, Bundle extras, IntentSender resultSender)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
getInstalledProvidersForProfile(int categoryFilter, int profileId, String packageName)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 
updateAppWidgetIds(String callingPackage, int[] appWidgetIds, RemoteViews views, boolean partially)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 
incrementAndGetAppWidgetIdLocked(int userId)1771     private int incrementAndGetAppWidgetIdLocked(int userId) {
1772         final int appWidgetId = peekNextAppWidgetIdLocked(userId) + 1;
1773         mNextAppWidgetIds.put(userId, appWidgetId);
1774         return appWidgetId;
1775     }
1776 
setMinAppWidgetIdLocked(int userId, int minWidgetId)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 
peekNextAppWidgetIdLocked(int userId)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 
lookupOrAddHostLocked(HostId id)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 
deleteHostLocked(Host host)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 
deleteAppWidgetLocked(Widget widget)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                     cancelBroadcastsLocked(provider);
1839 
1840                     // send the broacast saying that the provider is not in use any more
1841                     sendDisabledIntentLocked(provider);
1842                 }
1843             }
1844         }
1845     }
1846 
cancelBroadcastsLocked(Provider provider)1847     private void cancelBroadcastsLocked(Provider provider) {
1848         if (DEBUG) {
1849             Slog.i(TAG, "cancelBroadcastsLocked() for " + provider);
1850         }
1851         if (provider.broadcast != null) {
1852             final PendingIntent broadcast = provider.broadcast;
1853             mSaveStateHandler.post(() -> {
1854                     mAlarmManager.cancel(broadcast);
1855                     broadcast.cancel();
1856             });
1857             provider.broadcast = null;
1858         }
1859     }
1860 
1861     // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
destroyRemoteViewsService(final Intent intent, Widget widget)1862     private void destroyRemoteViewsService(final Intent intent, Widget widget) {
1863         final ServiceConnection conn = new ServiceConnection() {
1864             @Override
1865             public void onServiceConnected(ComponentName name, IBinder service) {
1866                 final IRemoteViewsFactory cb = IRemoteViewsFactory.Stub.asInterface(service);
1867                 try {
1868                     cb.onDestroy(intent);
1869                 } catch (RemoteException re) {
1870                     Slog.e(TAG, "Error calling remove view factory", re);
1871                 }
1872                 mContext.unbindService(this);
1873             }
1874 
1875             @Override
1876             public void onServiceDisconnected(ComponentName name) {
1877                 // Do nothing
1878             }
1879         };
1880 
1881         // Bind to the service and remove the static intent->factory mapping in the
1882         // RemoteViewsService.
1883         final long token = Binder.clearCallingIdentity();
1884         try {
1885             mContext.bindServiceAsUser(intent, conn,
1886                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
1887                     widget.provider.info.getProfile());
1888         } finally {
1889             Binder.restoreCallingIdentity(token);
1890         }
1891     }
1892 
1893     // Adds to the ref-count for a given RemoteViewsService intent
incrementAppWidgetServiceRefCount(int appWidgetId, Pair<Integer, FilterComparison> serviceId)1894     private void incrementAppWidgetServiceRefCount(int appWidgetId,
1895             Pair<Integer, FilterComparison> serviceId) {
1896         final HashSet<Integer> appWidgetIds;
1897         if (mRemoteViewsServicesAppWidgets.containsKey(serviceId)) {
1898             appWidgetIds = mRemoteViewsServicesAppWidgets.get(serviceId);
1899         } else {
1900             appWidgetIds = new HashSet<>();
1901             mRemoteViewsServicesAppWidgets.put(serviceId, appWidgetIds);
1902         }
1903         appWidgetIds.add(appWidgetId);
1904     }
1905 
1906     // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
1907     // the ref-count reaches zero.
decrementAppWidgetServiceRefCount(Widget widget)1908     private void decrementAppWidgetServiceRefCount(Widget widget) {
1909         Iterator<Pair<Integer, FilterComparison>> it = mRemoteViewsServicesAppWidgets
1910                 .keySet().iterator();
1911         while (it.hasNext()) {
1912             final Pair<Integer, FilterComparison> key = it.next();
1913             final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
1914             if (ids.remove(widget.appWidgetId)) {
1915                 // If we have removed the last app widget referencing this service, then we
1916                 // should destroy it and remove it from this set
1917                 if (ids.isEmpty()) {
1918                     destroyRemoteViewsService(key.second.getIntent(), widget);
1919                     it.remove();
1920                 }
1921             }
1922         }
1923     }
1924 
saveGroupStateAsync(int groupId)1925     private void saveGroupStateAsync(int groupId) {
1926         mSaveStateHandler.post(new SaveStateRunnable(groupId));
1927     }
1928 
updateAppWidgetInstanceLocked(Widget widget, RemoteViews views, boolean isPartialUpdate)1929     private void updateAppWidgetInstanceLocked(Widget widget, RemoteViews views,
1930             boolean isPartialUpdate) {
1931         if (widget != null && widget.provider != null
1932                 && !widget.provider.zombie && !widget.host.zombie) {
1933 
1934             if (isPartialUpdate && widget.views != null) {
1935                 // For a partial update, we merge the new RemoteViews with the old.
1936                 widget.views.mergeRemoteViews(views);
1937             } else {
1938                 // For a full update we replace the RemoteViews completely.
1939                 widget.views = views;
1940             }
1941             int memoryUsage;
1942             if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) &&
1943                     (widget.views != null) &&
1944                     ((memoryUsage = widget.views.estimateMemoryUsage()) > mMaxWidgetBitmapMemory)) {
1945                 widget.views = null;
1946                 throw new IllegalArgumentException("RemoteViews for widget update exceeds"
1947                         + " maximum bitmap memory usage (used: " + memoryUsage
1948                         + ", max: " + mMaxWidgetBitmapMemory + ")");
1949             }
1950             scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
1951         }
1952     }
1953 
scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId)1954     private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) {
1955         if (viewId == ID_VIEWS_UPDATE || viewId == ID_PROVIDER_CHANGED) {
1956             // A view id should never collide with these constants but a developer can call this
1957             // method with a wrong id. In that case, ignore the call.
1958             return;
1959         }
1960         long requestId = UPDATE_COUNTER.incrementAndGet();
1961         if (widget != null) {
1962             widget.updateSequenceNos.put(viewId, requestId);
1963         }
1964         if (widget == null || widget.host == null || widget.host.zombie
1965                 || widget.host.callbacks == null || widget.provider == null
1966                 || widget.provider.zombie) {
1967             return;
1968         }
1969 
1970         SomeArgs args = SomeArgs.obtain();
1971         args.arg1 = widget.host;
1972         args.arg2 = widget.host.callbacks;
1973         args.arg3 = requestId;
1974         args.argi1 = widget.appWidgetId;
1975         args.argi2 = viewId;
1976 
1977         mCallbackHandler.obtainMessage(
1978                 CallbackHandler.MSG_NOTIFY_VIEW_DATA_CHANGED,
1979                 args).sendToTarget();
1980     }
1981 
1982 
handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks, int appWidgetId, int viewId, long requestId)1983     private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
1984             int appWidgetId, int viewId, long requestId) {
1985         try {
1986             callbacks.viewDataChanged(appWidgetId, viewId);
1987             host.lastWidgetUpdateSequenceNo = requestId;
1988         } catch (RemoteException re) {
1989             // It failed; remove the callback. No need to prune because
1990             // we know that this host is still referenced by this instance.
1991             callbacks = null;
1992         }
1993 
1994         // If the host is unavailable, then we call the associated
1995         // RemoteViewsFactory.onDataSetChanged() directly
1996         synchronized (mLock) {
1997             if (callbacks == null) {
1998                 host.callbacks = null;
1999 
2000                 Set<Pair<Integer, FilterComparison>> keys = mRemoteViewsServicesAppWidgets.keySet();
2001                 for (Pair<Integer, FilterComparison> key : keys) {
2002                     if (mRemoteViewsServicesAppWidgets.get(key).contains(appWidgetId)) {
2003                         final ServiceConnection connection = new ServiceConnection() {
2004                             @Override
2005                             public void onServiceConnected(ComponentName name, IBinder service) {
2006                                 IRemoteViewsFactory cb = IRemoteViewsFactory.Stub
2007                                         .asInterface(service);
2008                                 try {
2009                                     cb.onDataSetChangedAsync();
2010                                 } catch (RemoteException e) {
2011                                     Slog.e(TAG, "Error calling onDataSetChangedAsync()", e);
2012                                 }
2013                                 mContext.unbindService(this);
2014                             }
2015 
2016                             @Override
2017                             public void onServiceDisconnected(android.content.ComponentName name) {
2018                                 // Do nothing
2019                             }
2020                         };
2021 
2022                         final int userId = UserHandle.getUserId(key.first);
2023                         Intent intent = key.second.getIntent();
2024 
2025                         // Bind to the service and call onDataSetChanged()
2026                         bindService(intent, connection, new UserHandle(userId));
2027                     }
2028                 }
2029             }
2030         }
2031     }
2032 
scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews)2033     private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
2034         long requestId = UPDATE_COUNTER.incrementAndGet();
2035         if (widget != null) {
2036             widget.updateSequenceNos.put(ID_VIEWS_UPDATE, requestId);
2037         }
2038         if (widget == null || widget.provider == null || widget.provider.zombie
2039                 || widget.host.callbacks == null || widget.host.zombie) {
2040             return;
2041         }
2042 
2043         SomeArgs args = SomeArgs.obtain();
2044         args.arg1 = widget.host;
2045         args.arg2 = widget.host.callbacks;
2046         args.arg3 = (updateViews != null) ? updateViews.clone() : null;
2047         args.arg4 = requestId;
2048         args.argi1 = widget.appWidgetId;
2049 
2050         mCallbackHandler.obtainMessage(
2051                 CallbackHandler.MSG_NOTIFY_UPDATE_APP_WIDGET,
2052                 args).sendToTarget();
2053     }
2054 
handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks, int appWidgetId, RemoteViews views, long requestId)2055     private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
2056             int appWidgetId, RemoteViews views, long requestId) {
2057         try {
2058             callbacks.updateAppWidget(appWidgetId, views);
2059             host.lastWidgetUpdateSequenceNo = requestId;
2060         } catch (RemoteException re) {
2061             synchronized (mLock) {
2062                 Slog.e(TAG, "Widget host dead: " + host.id, re);
2063                 host.callbacks = null;
2064             }
2065         }
2066     }
2067 
scheduleNotifyProviderChangedLocked(Widget widget)2068     private void scheduleNotifyProviderChangedLocked(Widget widget) {
2069         long requestId = UPDATE_COUNTER.incrementAndGet();
2070         if (widget != null) {
2071             // When the provider changes, reset everything else.
2072             widget.updateSequenceNos.clear();
2073             widget.updateSequenceNos.append(ID_PROVIDER_CHANGED, requestId);
2074         }
2075         if (widget == null || widget.provider == null || widget.provider.zombie
2076                 || widget.host.callbacks == null || widget.host.zombie) {
2077             return;
2078         }
2079 
2080         SomeArgs args = SomeArgs.obtain();
2081         args.arg1 = widget.host;
2082         args.arg2 = widget.host.callbacks;
2083         args.arg3 = widget.provider.info;
2084         args.arg4 = requestId;
2085         args.argi1 = widget.appWidgetId;
2086 
2087         mCallbackHandler.obtainMessage(
2088                 CallbackHandler.MSG_NOTIFY_PROVIDER_CHANGED,
2089                 args).sendToTarget();
2090     }
2091 
handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks, int appWidgetId, AppWidgetProviderInfo info, long requestId)2092     private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
2093             int appWidgetId, AppWidgetProviderInfo info, long requestId) {
2094         try {
2095             callbacks.providerChanged(appWidgetId, info);
2096             host.lastWidgetUpdateSequenceNo = requestId;
2097         } catch (RemoteException re) {
2098             synchronized (mLock){
2099                 Slog.e(TAG, "Widget host dead: " + host.id, re);
2100                 host.callbacks = null;
2101             }
2102         }
2103     }
2104 
scheduleNotifyGroupHostsForProvidersChangedLocked(int userId)2105     private void scheduleNotifyGroupHostsForProvidersChangedLocked(int userId) {
2106         final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
2107 
2108         final int N = mHosts.size();
2109         for (int i = N - 1; i >= 0; i--) {
2110             Host host = mHosts.get(i);
2111 
2112             boolean hostInGroup = false;
2113             final int M = profileIds.length;
2114             for (int j = 0; j < M; j++) {
2115                 final int profileId = profileIds[j];
2116                 if (host.getUserId() == profileId) {
2117                     hostInGroup = true;
2118                     break;
2119                 }
2120             }
2121 
2122             if (!hostInGroup) {
2123                 continue;
2124             }
2125 
2126             if (host == null || host.zombie || host.callbacks == null) {
2127                 continue;
2128             }
2129 
2130             SomeArgs args = SomeArgs.obtain();
2131             args.arg1 = host;
2132             args.arg2 = host.callbacks;
2133 
2134             mCallbackHandler.obtainMessage(
2135                     CallbackHandler.MSG_NOTIFY_PROVIDERS_CHANGED,
2136                     args).sendToTarget();
2137         }
2138     }
2139 
handleNotifyProvidersChanged(Host host, IAppWidgetHost callbacks)2140     private void handleNotifyProvidersChanged(Host host, IAppWidgetHost callbacks) {
2141         try {
2142             callbacks.providersChanged();
2143         } catch (RemoteException re) {
2144             synchronized (mLock) {
2145                 Slog.e(TAG, "Widget host dead: " + host.id, re);
2146                 host.callbacks = null;
2147             }
2148         }
2149     }
2150 
isLocalBinder()2151     private static boolean isLocalBinder() {
2152         return Process.myPid() == Binder.getCallingPid();
2153     }
2154 
cloneIfLocalBinder(RemoteViews rv)2155     private static RemoteViews cloneIfLocalBinder(RemoteViews rv) {
2156         if (isLocalBinder() && rv != null) {
2157             return rv.clone();
2158         }
2159         return rv;
2160     }
2161 
cloneIfLocalBinder(AppWidgetProviderInfo info)2162     private static AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) {
2163         if (isLocalBinder() && info != null) {
2164             return info.clone();
2165         }
2166         return info;
2167     }
2168 
cloneIfLocalBinder(Bundle bundle)2169     private static Bundle cloneIfLocalBinder(Bundle bundle) {
2170         // Note: this is only a shallow copy. For now this will be fine, but it could be problematic
2171         // if we start adding objects to the options. Further, it would only be an issue if keyguard
2172         // used such options.
2173         if (isLocalBinder() && bundle != null) {
2174             return (Bundle) bundle.clone();
2175         }
2176         return bundle;
2177     }
2178 
lookupWidgetLocked(int appWidgetId, int uid, String packageName)2179     private Widget lookupWidgetLocked(int appWidgetId, int uid, String packageName) {
2180         final int N = mWidgets.size();
2181         for (int i = 0; i < N; i++) {
2182             Widget widget = mWidgets.get(i);
2183             if (widget.appWidgetId == appWidgetId
2184                     && mSecurityPolicy.canAccessAppWidget(widget, uid, packageName)) {
2185                 return widget;
2186             }
2187         }
2188         return null;
2189     }
2190 
lookupProviderLocked(ProviderId id)2191     private Provider lookupProviderLocked(ProviderId id) {
2192         final int N = mProviders.size();
2193         for (int i = 0; i < N; i++) {
2194             Provider provider = mProviders.get(i);
2195             if (provider.id.equals(id)) {
2196                 return provider;
2197             }
2198         }
2199         return null;
2200     }
2201 
lookupHostLocked(HostId hostId)2202     private Host lookupHostLocked(HostId hostId) {
2203         final int N = mHosts.size();
2204         for (int i = 0; i < N; i++) {
2205             Host host = mHosts.get(i);
2206             if (host.id.equals(hostId)) {
2207                 return host;
2208             }
2209         }
2210         return null;
2211     }
2212 
pruneHostLocked(Host host)2213     private void pruneHostLocked(Host host) {
2214         if (host.widgets.size() == 0 && host.callbacks == null) {
2215             if (DEBUG) {
2216                 Slog.i(TAG, "Pruning host " + host.id);
2217             }
2218             mHosts.remove(host);
2219         }
2220     }
2221 
loadGroupWidgetProvidersLocked(int[] profileIds)2222     private void loadGroupWidgetProvidersLocked(int[] profileIds) {
2223         List<ResolveInfo> allReceivers = null;
2224         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
2225 
2226         final int profileCount = profileIds.length;
2227         for (int i = 0; i < profileCount; i++) {
2228             final int profileId = profileIds[i];
2229 
2230             List<ResolveInfo> receivers = queryIntentReceivers(intent, profileId);
2231             if (receivers != null && !receivers.isEmpty()) {
2232                 if (allReceivers == null) {
2233                     allReceivers = new ArrayList<>();
2234                 }
2235                 allReceivers.addAll(receivers);
2236             }
2237         }
2238 
2239         final int N = (allReceivers == null) ? 0 : allReceivers.size();
2240         for (int i = 0; i < N; i++) {
2241             ResolveInfo receiver = allReceivers.get(i);
2242             addProviderLocked(receiver);
2243         }
2244     }
2245 
addProviderLocked(ResolveInfo ri)2246     private boolean addProviderLocked(ResolveInfo ri) {
2247         if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
2248             return false;
2249         }
2250 
2251         if (!ri.activityInfo.isEnabled()) {
2252             return false;
2253         }
2254 
2255         ComponentName componentName = new ComponentName(ri.activityInfo.packageName,
2256                 ri.activityInfo.name);
2257         ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName);
2258 
2259         Provider provider = parseProviderInfoXml(providerId, ri, null);
2260         if (provider != null) {
2261             // we might have an inactive entry for this provider already due to
2262             // a preceding restore operation.  if so, fix it up in place; otherwise
2263             // just add this new one.
2264             Provider existing = lookupProviderLocked(providerId);
2265 
2266             // If the provider was not found it may be because it was restored and
2267             // we did not know its UID so let us find if there is such one.
2268             if (existing == null) {
2269                 ProviderId restoredProviderId = new ProviderId(UNKNOWN_UID, componentName);
2270                 existing = lookupProviderLocked(restoredProviderId);
2271             }
2272 
2273             if (existing != null) {
2274                 if (existing.zombie && !mSafeMode) {
2275                     // it's a placeholder that was set up during an app restore
2276                     existing.id = providerId;
2277                     existing.zombie = false;
2278                     existing.info = provider.info; // the real one filled out from the ResolveInfo
2279                     if (DEBUG) {
2280                         Slog.i(TAG, "Provider placeholder now reified: " + existing);
2281                     }
2282                 }
2283             } else {
2284                 mProviders.add(provider);
2285             }
2286             return true;
2287         }
2288 
2289         return false;
2290     }
2291 
2292     // Remove widgets for provider that are hosted in userId.
deleteWidgetsLocked(Provider provider, int userId)2293     private void deleteWidgetsLocked(Provider provider, int userId) {
2294         final int N = provider.widgets.size();
2295         for (int i = N - 1; i >= 0; i--) {
2296             Widget widget = provider.widgets.get(i);
2297             if (userId == UserHandle.USER_ALL
2298                     || userId == widget.host.getUserId()) {
2299                 provider.widgets.remove(i);
2300                 // Call back with empty RemoteViews
2301                 updateAppWidgetInstanceLocked(widget, null, false);
2302                 // clear out references to this appWidgetId
2303                 widget.host.widgets.remove(widget);
2304                 removeWidgetLocked(widget);
2305                 widget.provider = null;
2306                 pruneHostLocked(widget.host);
2307                 widget.host = null;
2308             }
2309         }
2310     }
2311 
deleteProviderLocked(Provider provider)2312     private void deleteProviderLocked(Provider provider) {
2313         deleteWidgetsLocked(provider, UserHandle.USER_ALL);
2314         mProviders.remove(provider);
2315 
2316         // no need to send the DISABLE broadcast, since the receiver is gone anyway
2317         cancelBroadcastsLocked(provider);
2318     }
2319 
sendEnableIntentLocked(Provider p)2320     private void sendEnableIntentLocked(Provider p) {
2321         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
2322         intent.setComponent(p.info.provider);
2323         sendBroadcastAsUser(intent, p.info.getProfile());
2324     }
2325 
sendUpdateIntentLocked(Provider provider, int[] appWidgetIds)2326     private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds) {
2327         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
2328         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
2329         intent.setComponent(provider.info.provider);
2330         sendBroadcastAsUser(intent, provider.info.getProfile());
2331     }
2332 
sendDeletedIntentLocked(Widget widget)2333     private void sendDeletedIntentLocked(Widget widget) {
2334         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
2335         intent.setComponent(widget.provider.info.provider);
2336         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
2337         sendBroadcastAsUser(intent, widget.provider.info.getProfile());
2338     }
2339 
sendDisabledIntentLocked(Provider provider)2340     private void sendDisabledIntentLocked(Provider provider) {
2341         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
2342         intent.setComponent(provider.info.provider);
2343         sendBroadcastAsUser(intent, provider.info.getProfile());
2344     }
2345 
sendOptionsChangedIntentLocked(Widget widget)2346     public void sendOptionsChangedIntentLocked(Widget widget) {
2347         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED);
2348         intent.setComponent(widget.provider.info.provider);
2349         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
2350         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, widget.options);
2351         sendBroadcastAsUser(intent, widget.provider.info.getProfile());
2352     }
2353 
registerForBroadcastsLocked(Provider provider, int[] appWidgetIds)2354     private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) {
2355         if (provider.info.updatePeriodMillis > 0) {
2356             // if this is the first instance, set the alarm. otherwise,
2357             // rely on the fact that we've already set it and that
2358             // PendingIntent.getBroadcast will update the extras.
2359             boolean alreadyRegistered = provider.broadcast != null;
2360             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
2361             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
2362             intent.setComponent(provider.info.provider);
2363             long token = Binder.clearCallingIdentity();
2364             try {
2365                 provider.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
2366                         PendingIntent.FLAG_UPDATE_CURRENT, provider.info.getProfile());
2367             } finally {
2368                 Binder.restoreCallingIdentity(token);
2369             }
2370             if (!alreadyRegistered) {
2371                 // Set the alarm outside of our locks; we've latched the first-time
2372                 // invariant and established the PendingIntent safely.
2373                 final long period = Math.max(provider.info.updatePeriodMillis, MIN_UPDATE_PERIOD);
2374                 final PendingIntent broadcast = provider.broadcast;
2375                 mSaveStateHandler.post(() ->
2376                     mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2377                             SystemClock.elapsedRealtime() + period, period, broadcast)
2378                 );
2379             }
2380         }
2381     }
2382 
getWidgetIds(ArrayList<Widget> widgets)2383     private static int[] getWidgetIds(ArrayList<Widget> widgets) {
2384         int instancesSize = widgets.size();
2385         int appWidgetIds[] = new int[instancesSize];
2386         for (int i = 0; i < instancesSize; i++) {
2387             appWidgetIds[i] = widgets.get(i).appWidgetId;
2388         }
2389         return appWidgetIds;
2390     }
2391 
dumpProvider(Provider provider, int index, PrintWriter pw)2392     private static void dumpProvider(Provider provider, int index, PrintWriter pw) {
2393         AppWidgetProviderInfo info = provider.info;
2394         pw.print("  ["); pw.print(index); pw.print("] provider ");
2395         pw.println(provider.id);
2396         pw.print("    min=("); pw.print(info.minWidth);
2397         pw.print("x"); pw.print(info.minHeight);
2398         pw.print(")   minResize=("); pw.print(info.minResizeWidth);
2399         pw.print("x"); pw.print(info.minResizeHeight);
2400         pw.print(") updatePeriodMillis=");
2401         pw.print(info.updatePeriodMillis);
2402         pw.print(" resizeMode=");
2403         pw.print(info.resizeMode);
2404         pw.print(" widgetCategory=");
2405         pw.print(info.widgetCategory);
2406         pw.print(" autoAdvanceViewId=");
2407         pw.print(info.autoAdvanceViewId);
2408         pw.print(" initialLayout=#");
2409         pw.print(Integer.toHexString(info.initialLayout));
2410         pw.print(" initialKeyguardLayout=#");
2411         pw.print(Integer.toHexString(info.initialKeyguardLayout));
2412         pw.print(" zombie="); pw.println(provider.zombie);
2413     }
2414 
dumpHost(Host host, int index, PrintWriter pw)2415     private static void dumpHost(Host host, int index, PrintWriter pw) {
2416         pw.print("  ["); pw.print(index); pw.print("] hostId=");
2417         pw.println(host.id);
2418         pw.print("    callbacks="); pw.println(host.callbacks);
2419         pw.print("    widgets.size="); pw.print(host.widgets.size());
2420         pw.print(" zombie="); pw.println(host.zombie);
2421     }
2422 
dumpGrant(Pair<Integer, String> grant, int index, PrintWriter pw)2423     private static void dumpGrant(Pair<Integer, String> grant, int index, PrintWriter pw) {
2424         pw.print("  ["); pw.print(index); pw.print(']');
2425         pw.print(" user="); pw.print(grant.first);
2426         pw.print(" package="); pw.println(grant.second);
2427     }
2428 
dumpWidget(Widget widget, int index, PrintWriter pw)2429     private static void dumpWidget(Widget widget, int index, PrintWriter pw) {
2430         pw.print("  ["); pw.print(index); pw.print("] id=");
2431         pw.println(widget.appWidgetId);
2432         pw.print("    host=");
2433         pw.println(widget.host.id);
2434         if (widget.provider != null) {
2435             pw.print("    provider="); pw.println(widget.provider.id);
2436         }
2437         if (widget.host != null) {
2438             pw.print("    host.callbacks="); pw.println(widget.host.callbacks);
2439         }
2440         if (widget.views != null) {
2441             pw.print("    views="); pw.println(widget.views);
2442         }
2443     }
2444 
serializeProvider(XmlSerializer out, Provider p)2445     private static void serializeProvider(XmlSerializer out, Provider p) throws IOException {
2446         out.startTag(null, "p");
2447         out.attribute(null, "pkg", p.info.provider.getPackageName());
2448         out.attribute(null, "cl", p.info.provider.getClassName());
2449         out.attribute(null, "tag", Integer.toHexString(p.tag));
2450         if (!TextUtils.isEmpty(p.infoTag)) {
2451             out.attribute(null, "info_tag", p.infoTag);
2452         }
2453         out.endTag(null, "p");
2454     }
2455 
serializeHost(XmlSerializer out, Host host)2456     private static void serializeHost(XmlSerializer out, Host host) throws IOException {
2457         out.startTag(null, "h");
2458         out.attribute(null, "pkg", host.id.packageName);
2459         out.attribute(null, "id", Integer.toHexString(host.id.hostId));
2460         out.attribute(null, "tag", Integer.toHexString(host.tag));
2461         out.endTag(null, "h");
2462     }
2463 
serializeAppWidget(XmlSerializer out, Widget widget)2464     private static void serializeAppWidget(XmlSerializer out, Widget widget) throws IOException {
2465         out.startTag(null, "g");
2466         out.attribute(null, "id", Integer.toHexString(widget.appWidgetId));
2467         out.attribute(null, "rid", Integer.toHexString(widget.restoredId));
2468         out.attribute(null, "h", Integer.toHexString(widget.host.tag));
2469         if (widget.provider != null) {
2470             out.attribute(null, "p", Integer.toHexString(widget.provider.tag));
2471         }
2472         if (widget.options != null) {
2473             int minWidth = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
2474             int minHeight = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
2475             int maxWidth = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
2476             int maxHeight = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
2477             out.attribute(null, "min_width", Integer.toHexString((minWidth > 0) ? minWidth : 0));
2478             out.attribute(null, "min_height", Integer.toHexString((minHeight > 0) ? minHeight : 0));
2479             out.attribute(null, "max_width", Integer.toHexString((maxWidth > 0) ? maxWidth : 0));
2480             out.attribute(null, "max_height", Integer.toHexString((maxHeight > 0) ? maxHeight : 0));
2481             out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt(
2482                     AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)));
2483         }
2484         out.endTag(null, "g");
2485     }
2486 
2487     @Override
getWidgetParticipants(int userId)2488     public List<String> getWidgetParticipants(int userId) {
2489         return mBackupRestoreController.getWidgetParticipants(userId);
2490     }
2491 
2492     @Override
getWidgetState(String packageName, int userId)2493     public byte[] getWidgetState(String packageName, int userId) {
2494         return mBackupRestoreController.getWidgetState(packageName, userId);
2495     }
2496 
2497     @Override
restoreStarting(int userId)2498     public void restoreStarting(int userId) {
2499         mBackupRestoreController.restoreStarting(userId);
2500     }
2501 
2502     @Override
restoreWidgetState(String packageName, byte[] restoredState, int userId)2503     public void restoreWidgetState(String packageName, byte[] restoredState, int userId) {
2504         mBackupRestoreController.restoreWidgetState(packageName, restoredState, userId);
2505     }
2506 
2507     @Override
restoreFinished(int userId)2508     public void restoreFinished(int userId) {
2509         mBackupRestoreController.restoreFinished(userId);
2510     }
2511 
2512     @SuppressWarnings("deprecation")
parseProviderInfoXml(ProviderId providerId, ResolveInfo ri, Provider oldProvider)2513     private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri,
2514             Provider oldProvider) {
2515         AppWidgetProviderInfo info = null;
2516         if (oldProvider != null && !TextUtils.isEmpty(oldProvider.infoTag)) {
2517             info = parseAppWidgetProviderInfo(providerId, ri.activityInfo, oldProvider.infoTag);
2518         }
2519         if (info == null) {
2520             info = parseAppWidgetProviderInfo(providerId, ri.activityInfo,
2521                     AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
2522         }
2523         if (info == null) {
2524             return null;
2525         }
2526 
2527         Provider provider = new Provider();
2528         provider.id = providerId;
2529         provider.info = info;
2530         return provider;
2531     }
2532 
parseAppWidgetProviderInfo( ProviderId providerId, ActivityInfo activityInfo, String metadataKey)2533     private AppWidgetProviderInfo parseAppWidgetProviderInfo(
2534             ProviderId providerId, ActivityInfo activityInfo, String metadataKey) {
2535         try (XmlResourceParser parser =
2536                      activityInfo.loadXmlMetaData(mContext.getPackageManager(), metadataKey)) {
2537             if (parser == null) {
2538                 Slog.w(TAG, "No " + metadataKey + " meta-data for AppWidget provider '"
2539                         + providerId + '\'');
2540                 return null;
2541             }
2542 
2543             AttributeSet attrs = Xml.asAttributeSet(parser);
2544 
2545             int type;
2546             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2547                     && type != XmlPullParser.START_TAG) {
2548                 // drain whitespace, comments, etc.
2549             }
2550 
2551             String nodeName = parser.getName();
2552             if (!"appwidget-provider".equals(nodeName)) {
2553                 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
2554                         + " AppWidget provider " + providerId.componentName
2555                         + " for user " + providerId.uid);
2556                 return null;
2557             }
2558 
2559             AppWidgetProviderInfo info = new AppWidgetProviderInfo();
2560             info.provider = providerId.componentName;
2561             info.providerInfo = activityInfo;
2562 
2563             final Resources resources;
2564             final long identity = Binder.clearCallingIdentity();
2565             try {
2566                 final PackageManager pm = mContext.getPackageManager();
2567                 final int userId = UserHandle.getUserId(providerId.uid);
2568                 final ApplicationInfo app = pm.getApplicationInfoAsUser(activityInfo.packageName,
2569                         0, userId);
2570                 resources = pm.getResourcesForApplication(app);
2571             } finally {
2572                 Binder.restoreCallingIdentity(identity);
2573             }
2574 
2575             TypedArray sa = resources.obtainAttributes(attrs,
2576                     com.android.internal.R.styleable.AppWidgetProviderInfo);
2577 
2578             // These dimensions has to be resolved in the application's context.
2579             // We simply send back the raw complex data, which will be
2580             // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
2581             TypedValue value = sa
2582                     .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
2583             info.minWidth = value != null ? value.data : 0;
2584             value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
2585             info.minHeight = value != null ? value.data : 0;
2586             value = sa.peekValue(
2587                     com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth);
2588             info.minResizeWidth = value != null ? value.data : info.minWidth;
2589             value = sa.peekValue(
2590                     com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight);
2591             info.minResizeHeight = value != null ? value.data : info.minHeight;
2592             info.updatePeriodMillis = sa.getInt(
2593                     com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
2594             info.initialLayout = sa.getResourceId(
2595                     com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
2596             info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable.
2597                     AppWidgetProviderInfo_initialKeyguardLayout, 0);
2598 
2599             String className = sa
2600                     .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
2601             if (className != null) {
2602                 info.configure = new ComponentName(providerId.componentName.getPackageName(),
2603                         className);
2604             }
2605             info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString();
2606             info.icon = activityInfo.getIconResource();
2607             info.previewImage = sa.getResourceId(
2608                     com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
2609             info.autoAdvanceViewId = sa.getResourceId(
2610                     com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
2611             info.resizeMode = sa.getInt(
2612                     com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
2613                     AppWidgetProviderInfo.RESIZE_NONE);
2614             info.widgetCategory = sa.getInt(
2615                     com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory,
2616                     AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
2617             info.widgetFeatures = sa.getInt(
2618                     com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0);
2619 
2620             sa.recycle();
2621             return info;
2622         } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) {
2623             // Ok to catch Exception here, because anything going wrong because
2624             // of what a client process passes to us should not be fatal for the
2625             // system process.
2626             Slog.w(TAG, "XML parsing failed for AppWidget provider "
2627                     + providerId.componentName + " for user " + providerId.uid, e);
2628             return null;
2629         }
2630     }
2631 
getUidForPackage(String packageName, int userId)2632     private int getUidForPackage(String packageName, int userId) {
2633         PackageInfo pkgInfo = null;
2634 
2635         final long identity = Binder.clearCallingIdentity();
2636         try {
2637             pkgInfo = mPackageManager.getPackageInfo(packageName, 0, userId);
2638         } catch (RemoteException re) {
2639             // Shouldn't happen, local call
2640         } finally {
2641             Binder.restoreCallingIdentity(identity);
2642         }
2643 
2644         if (pkgInfo == null || pkgInfo.applicationInfo == null) {
2645             return -1;
2646         }
2647 
2648         return pkgInfo.applicationInfo.uid;
2649     }
2650 
getProviderInfo(ComponentName componentName, int userId)2651     private ActivityInfo getProviderInfo(ComponentName componentName, int userId) {
2652         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
2653         intent.setComponent(componentName);
2654 
2655         List<ResolveInfo> receivers = queryIntentReceivers(intent, userId);
2656         // We are setting component, so there is only one or none.
2657         if (!receivers.isEmpty()) {
2658             return receivers.get(0).activityInfo;
2659         }
2660 
2661         return null;
2662     }
2663 
queryIntentReceivers(Intent intent, int userId)2664     private List<ResolveInfo> queryIntentReceivers(Intent intent, int userId) {
2665         final long identity = Binder.clearCallingIdentity();
2666         try {
2667             int flags = PackageManager.GET_META_DATA;
2668 
2669             // We really need packages to be around and parsed to know if they
2670             // provide widgets.
2671             flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
2672 
2673             // Widget hosts that are non-crypto aware may be hosting widgets
2674             // from a profile that is still locked, so let them see those
2675             // widgets.
2676             if (isProfileWithUnlockedParent(userId)) {
2677                 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
2678                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
2679             }
2680 
2681             // Widgets referencing shared libraries need to have their
2682             // dependencies loaded.
2683             flags |= PackageManager.GET_SHARED_LIBRARY_FILES;
2684 
2685             return mPackageManager.queryIntentReceivers(intent,
2686                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2687                     flags, userId).getList();
2688         } catch (RemoteException re) {
2689             return Collections.emptyList();
2690         } finally {
2691             Binder.restoreCallingIdentity(identity);
2692         }
2693     }
2694 
2695     /**
2696      * This does not use the usual onUserUnlocked() listener mechanism because it is
2697      * invoked at a choreographed point in the middle of the user unlock sequence,
2698      * before the boot-completed broadcast is issued and the listeners notified.
2699      */
handleUserUnlocked(int userId)2700     void handleUserUnlocked(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, "Processing of handleUserUnlocked u" + userId + " took "
2738                 + (SystemClock.elapsedRealtime() - time) + " ms");
2739     }
2740 
2741     // only call from initialization -- it assumes that the data structures are all empty
loadGroupStateLocked(int[] profileIds)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 
bindLoadedWidgetsLocked(List<LoadedWidgetState> loadedWidgets)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 
findProviderByTag(int tag)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 
findHostByTag(int tag)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      */
addWidgetLocked(Widget widget)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      */
onWidgetProviderAddedOrChangedLocked(Widget widget)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      */
removeWidgetLocked(Widget widget)2871     void removeWidgetLocked(Widget widget) {
2872         mWidgets.remove(widget);
2873 
2874         onWidgetRemovedLocked(widget);
2875     }
2876 
onWidgetRemovedLocked(Widget widget)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      */
clearWidgetsLocked()2903     void clearWidgetsLocked() {
2904         mWidgets.clear();
2905 
2906         onWidgetsClearedLocked();
2907     }
2908 
onWidgetsClearedLocked()2909     private void onWidgetsClearedLocked() {
2910         mWidgetPackages.clear();
2911     }
2912 
2913     @Override
isBoundWidgetPackage(String packageName, int userId)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 
saveStateLocked(int userId)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 
tagProvidersAndHosts()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 
clearProvidersAndHostsTagsLocked()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 
writeProfileStateToFileLocked(FileOutputStream stream, int userId)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 
readProfileStateFromFileLocked(FileInputStream stream, int userId, List<LoadedWidgetState> outLoadedWidgets)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 
performUpgradeLocked(int fromVersion)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 
getStateFile(int userId)3244     private static File getStateFile(int userId) {
3245         return new File(Environment.getUserSystemDirectory(userId), STATE_FILENAME);
3246     }
3247 
getSavedStateFile(int userId)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 
onUserStopped(int userId)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      */
updateProvidersForPackageLocked(String packageName, int userId, Set<ProviderId> removedProviders)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                             cancelBroadcastsLocked(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
removeWidgetsForPackageLocked(String pkgName, int userId, int 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 
removeProvidersForPackageLocked(String pkgName, int userId)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 
removeHostsAndProvidersForPackageLocked(String pkgName, int userId)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 
getCanonicalPackageName(String packageName, String className, int userId)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 
sendBroadcastAsUser(Intent intent, UserHandle userHandle)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 
bindService(Intent intent, ServiceConnection connection, UserHandle userHandle)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 
unbindService(ServiceConnection connection)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
onCrossProfileWidgetProvidersChanged(int userId, List<String> packages)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 
isProfileWithLockedParent(int userId)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 
isProfileWithUnlockedParent(int userId)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 
CallbackHandler(Looper looper)3591         public CallbackHandler(Looper looper) {
3592             super(looper, null, false);
3593         }
3594 
3595         @Override
handleMessage(Message message)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 
isEnabledGroupProfile(int profileId)3649         public boolean isEnabledGroupProfile(int profileId) {
3650             final int parentId = UserHandle.getCallingUserId();
3651             return isParentOrProfile(parentId, profileId) && isProfileEnabled(profileId);
3652         }
3653 
getEnabledGroupProfileIds(int userId)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 
enforceServiceExistsAndRequiresBindRemoteViewsPermission( ComponentName componentName, int userId)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 
enforceModifyAppWidgetBindPermissions(String packageName)3687         public void enforceModifyAppWidgetBindPermissions(String packageName) {
3688             mContext.enforceCallingPermission(
3689                     android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS,
3690                     "hasBindAppWidgetPermission packageName=" + packageName);
3691         }
3692 
isCallerInstantAppLocked()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 
isInstantAppLocked(String packageName, int userId)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 
enforceCallFromPackage(String packageName)3722         public void enforceCallFromPackage(String packageName) {
3723             mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
3724         }
3725 
hasCallerBindPermissionOrBindWhiteListedLocked(String packageName)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 
isCallerBindAppWidgetWhiteListedLocked(String packageName)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 
canAccessAppWidget(Widget widget, int uid, String packageName)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 
isParentOrProfile(int parentId, int profileId)3782         private boolean isParentOrProfile(int parentId, int profileId) {
3783             if (parentId == profileId) {
3784                 return true;
3785             }
3786             return getProfileParent(profileId) == parentId;
3787         }
3788 
isProviderInCallerOrInProfileAndWhitelListed(String packageName, int profileId)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 
isProviderWhiteListed(String packageName, int profileId)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 
getProfileParent(int profileId)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 
getGroupParent(int profileId)3827         public int getGroupParent(int profileId) {
3828             final int parentId = mSecurityPolicy.getProfileParent(profileId);
3829             return (parentId != UNKNOWN_USER_ID) ? parentId : profileId;
3830         }
3831 
isHostInPackageForUid(Host host, int uid, String packageName)3832         public boolean isHostInPackageForUid(Host host, int uid, String packageName) {
3833             return host.id.uid == uid && host.id.packageName.equals(packageName);
3834         }
3835 
isProviderInPackageForUid(Provider provider, int uid, String packageName)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 
isHostAccessingProvider(Host host, Provider provider, int uid, String packageName)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 
isProfileEnabled(int profileId)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 
getUserId()3878         public int getUserId() {
3879             return UserHandle.getUserId(id.uid);
3880         }
3881 
isInPackageForUser(String packageName, int userId)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?
hostedByPackageForUser(String packageName, int userId)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
toString()3901         public String toString() {
3902             return "Provider{" + id + (zombie ? " Z" : "") + '}';
3903         }
3904 
3905         // returns true if it's different from previous state.
setMaskedByQuietProfileLocked(boolean masked)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.
setMaskedByLockedProfileLocked(boolean masked)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.
setMaskedBySuspendedPackageLocked(boolean masked)3920         public boolean setMaskedBySuspendedPackageLocked(boolean masked) {
3921             boolean oldState = maskedBySuspendedPackage;
3922             maskedBySuspendedPackage = masked;
3923             return masked != oldState;
3924         }
3925 
isMaskedLocked()3926         public boolean isMaskedLocked() {
3927             return maskedByQuietProfile || maskedByLockedProfile || maskedBySuspendedPackage;
3928         }
3929 
shouldBePersisted()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 
ProviderId(int uid, ComponentName componentName)3939         private ProviderId(int uid, ComponentName componentName) {
3940             this.uid = uid;
3941             this.componentName = componentName;
3942         }
3943 
3944         @Override
equals(Object obj)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
hashCode()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
toString()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 
getUserId()3997         public int getUserId() {
3998             return UserHandle.getUserId(id.uid);
3999         }
4000 
isInPackageForUser(String packageName, int userId)4001         public boolean isInPackageForUser(String packageName, int userId) {
4002             return getUserId() == userId && id.packageName.equals(packageName);
4003         }
4004 
hostsPackageForUser(String pkg, int userId)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          */
getPendingUpdatesForId(int appWidgetId, LongSparseArray<PendingHostUpdate> outUpdates)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
toString()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 
HostId(int uid, int hostId, String packageName)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
equals(Object obj)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
hashCode()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
toString()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
toString()4133         public String toString() {
4134             return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
4135         }
4136 
replaceWithMaskedViewsLocked(RemoteViews views)4137         private boolean replaceWithMaskedViewsLocked(RemoteViews views) {
4138             maskedViews = views;
4139             return true;
4140         }
4141 
clearMaskedViewsLocked()4142         private boolean clearMaskedViewsLocked() {
4143             if (maskedViews != null) {
4144                 maskedViews = null;
4145                 return true;
4146             } else {
4147                 return false;
4148             }
4149         }
4150 
getEffectiveViewsLocked()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 
LoadedWidgetState(Widget widget, int hostTag, int providerTag)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 
SaveStateRunnable(int userId)4171         public SaveStateRunnable(int userId) {
4172             mUserId = userId;
4173         }
4174 
4175         @Override
run()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 
getWidgetParticipants(int userId)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 
getWidgetState(String backedupPackage, int userId)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 
restoreStarting(int userId)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 
restoreWidgetState(String packageName, byte[] restoredState, int userId)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.
restoreFinished(int userId)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 
findProviderLocked(ComponentName componentName, int userId)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 
findRestoredWidgetLocked(int restoredId, Host host, Provider p)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 
packageNeedsWidgetBackupLocked(String packageName, int userId)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 
stashProviderRestoreUpdateLocked(Provider provider, int oldId, int newId)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 
alreadyStashed(ArrayList<RestoreUpdateRecord> stash, final int oldId, final int newId)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 
stashHostRestoreUpdateLocked(Host host, int oldId, int newId)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 
sendWidgetRestoreBroadcastLocked(String action, Provider provider, Host host, int[] oldIds, int[] newIds, UserHandle userHandle)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.
pruneWidgetStateLocked(String pkg, int userId)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 
isProviderAndHostInUser(Widget widget, int userId)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 
parseWidgetIdOptions(XmlPullParser parser)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 
countPendingUpdates(ArrayList<RestoreUpdateRecord> updates)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 
RestoreUpdateRecord(int theOldId, int theNewId)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
getHostedWidgetPackages(int uid)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         @Override
unlockUser(int userId)4806         public void unlockUser(int userId) {
4807             handleUserUnlocked(userId);
4808         }
4809 
4810     }
4811 }
4812