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