• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.appwidget;
18 
19 import static android.appwidget.flags.Flags.remoteAdapterConversion;
20 import static android.appwidget.flags.Flags.remoteViewsProto;
21 import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath;
22 import static android.appwidget.flags.Flags.securityPolicyInteractAcrossUsers;
23 import static android.appwidget.flags.Flags.supportResumeRestoreAfterReboot;
24 import static android.content.Context.KEYGUARD_SERVICE;
25 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
26 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
27 import static android.content.res.Resources.ID_NULL;
28 import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
29 
30 import static com.android.server.appwidget.AppWidgetXmlUtil.deserializeWidgetSizesStr;
31 import static com.android.server.appwidget.AppWidgetXmlUtil.serializeWidgetSizes;
32 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
33 
34 import android.Manifest;
35 import android.annotation.FlaggedApi;
36 import android.annotation.NonNull;
37 import android.annotation.Nullable;
38 import android.annotation.PermissionName;
39 import android.annotation.RequiresPermission;
40 import android.annotation.UserIdInt;
41 import android.app.ActivityManager;
42 import android.app.ActivityManagerInternal;
43 import android.app.ActivityOptions;
44 import android.app.AlarmManager;
45 import android.app.AppGlobals;
46 import android.app.AppOpsManager;
47 import android.app.AppOpsManagerInternal;
48 import android.app.BroadcastOptions;
49 import android.app.IApplicationThread;
50 import android.app.IServiceConnection;
51 import android.app.KeyguardManager;
52 import android.app.PendingIntent;
53 import android.app.StatsManager;
54 import android.app.admin.DevicePolicyManagerInternal;
55 import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
56 import android.app.usage.Flags;
57 import android.app.usage.UsageEvents;
58 import android.app.usage.UsageStatsManager;
59 import android.app.usage.UsageStatsManagerInternal;
60 import android.appwidget.AppWidgetManager;
61 import android.appwidget.AppWidgetManagerInternal;
62 import android.appwidget.AppWidgetProviderInfo;
63 import android.appwidget.PendingHostUpdate;
64 import android.content.BroadcastReceiver;
65 import android.content.ComponentName;
66 import android.content.ContentResolver;
67 import android.content.Context;
68 import android.content.Intent;
69 import android.content.Intent.FilterComparison;
70 import android.content.IntentFilter;
71 import android.content.IntentSender;
72 import android.content.ServiceConnection;
73 import android.content.pm.ActivityInfo;
74 import android.content.pm.ApplicationInfo;
75 import android.content.pm.IPackageManager;
76 import android.content.pm.LauncherApps;
77 import android.content.pm.PackageInfo;
78 import android.content.pm.PackageManager;
79 import android.content.pm.PackageManagerInternal;
80 import android.content.pm.ParceledListSlice;
81 import android.content.pm.ResolveInfo;
82 import android.content.pm.ServiceInfo;
83 import android.content.pm.ShortcutServiceInternal;
84 import android.content.pm.SuspendDialogInfo;
85 import android.content.pm.UserInfo;
86 import android.content.pm.UserPackage;
87 import android.content.res.Resources;
88 import android.content.res.TypedArray;
89 import android.content.res.XmlResourceParser;
90 import android.graphics.Point;
91 import android.graphics.drawable.Icon;
92 import android.net.Uri;
93 import android.os.Binder;
94 import android.os.Build;
95 import android.os.Bundle;
96 import android.os.Environment;
97 import android.os.Handler;
98 import android.os.HandlerExecutor;
99 import android.os.IBinder;
100 import android.os.Looper;
101 import android.os.Message;
102 import android.os.PersistableBundle;
103 import android.os.Process;
104 import android.os.RemoteException;
105 import android.os.SystemClock;
106 import android.os.Trace;
107 import android.os.UserHandle;
108 import android.os.UserManager;
109 import android.provider.DeviceConfig;
110 import android.service.appwidget.AppWidgetServiceDumpProto;
111 import android.service.appwidget.GeneratedPreviewsProto;
112 import android.service.appwidget.WidgetProto;
113 import android.text.TextUtils;
114 import android.util.ArrayMap;
115 import android.util.ArraySet;
116 import android.util.AtomicFile;
117 import android.util.AttributeSet;
118 import android.util.IntArray;
119 import android.util.Log;
120 import android.util.LongSparseArray;
121 import android.util.Pair;
122 import android.util.SizeF;
123 import android.util.Slog;
124 import android.util.SparseArray;
125 import android.util.SparseBooleanArray;
126 import android.util.SparseIntArray;
127 import android.util.SparseLongArray;
128 import android.util.StatsEvent;
129 import android.util.TypedValue;
130 import android.util.Xml;
131 import android.util.proto.ProtoInputStream;
132 import android.util.proto.ProtoOutputStream;
133 import android.util.proto.ProtoUtils;
134 import android.view.Display;
135 import android.view.View;
136 import android.widget.RemoteViews;
137 
138 import com.android.internal.R;
139 import com.android.internal.annotations.GuardedBy;
140 import com.android.internal.app.SuspendedAppActivity;
141 import com.android.internal.app.UnlaunchableAppActivity;
142 import com.android.internal.appwidget.IAppWidgetHost;
143 import com.android.internal.appwidget.IAppWidgetService;
144 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
145 import com.android.internal.infra.AndroidFuture;
146 import com.android.internal.os.BackgroundThread;
147 import com.android.internal.os.SomeArgs;
148 import com.android.internal.util.ArrayUtils;
149 import com.android.internal.util.DumpUtils;
150 import com.android.internal.util.FrameworkStatsLog;
151 import com.android.internal.widget.IRemoteViewsFactory;
152 import com.android.modules.utils.TypedXmlPullParser;
153 import com.android.modules.utils.TypedXmlSerializer;
154 import com.android.server.LocalServices;
155 import com.android.server.ServiceThread;
156 import com.android.server.WidgetBackupProvider;
157 import com.android.server.uri.GrantUri;
158 import com.android.server.uri.UriGrantsManagerInternal;
159 
160 import org.xmlpull.v1.XmlPullParser;
161 import org.xmlpull.v1.XmlPullParserException;
162 
163 import java.io.ByteArrayInputStream;
164 import java.io.ByteArrayOutputStream;
165 import java.io.File;
166 import java.io.FileDescriptor;
167 import java.io.FileInputStream;
168 import java.io.FileOutputStream;
169 import java.io.IOException;
170 import java.io.OutputStream;
171 import java.io.PrintWriter;
172 import java.nio.charset.StandardCharsets;
173 import java.time.Duration;
174 import java.util.ArrayList;
175 import java.util.Arrays;
176 import java.util.Collections;
177 import java.util.HashMap;
178 import java.util.HashSet;
179 import java.util.Iterator;
180 import java.util.List;
181 import java.util.Map;
182 import java.util.Objects;
183 import java.util.Set;
184 import java.util.concurrent.atomic.AtomicLong;
185 import java.util.function.BiConsumer;
186 import java.util.function.Function;
187 import java.util.function.LongSupplier;
188 
189 class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
190         OnCrossProfileWidgetProvidersChangeListener {
191     // Name of the tag associated with the system logs generated by this service.
192     private static final String TAG = "AppWidgetServiceImpl";
193     // Simple flag to enable/disable debug logging.
194     private static final boolean DEBUG = Build.IS_DEBUGGABLE;
195 
196     // Filename for app widgets state persisted on disk.
197     private static final String STATE_FILENAME = "appwidgets.xml";
198 
199     // XML tag for widget size options of each individual widget when persisted on disk.
200     private static final String KEY_SIZES = "sizes";
201 
202     // Minimum amount of time in millieconds before a widget is updated.
203     private static final int MIN_UPDATE_PERIOD = DEBUG ? 0 : 30 * 60 * 1000; // 30 minutes
204 
205     // Default value of {@link Provider#tag} and {@link Host#tag}.
206     private static final int TAG_UNDEFINED = -1;
207 
208     // Default uid of {@link ProviderId} when corresponding app haven't been installed yet.
209     private static final int UNKNOWN_UID = -1;
210 
211     // Default return value when we can't find the parent of a given profileId.
212     private static final int UNKNOWN_USER_ID = -10;
213 
214     // Version of XML schema for app widgets. Bump if the stored widgets need to be upgraded.
215     // Version 1 introduced in 2014 - Android 5.0
216     private static final int CURRENT_VERSION = 1;
217 
218     // Every widget update request is associated which an increasing sequence number. This is
219     // used to verify which request has successfully been received by the host.
220     private static final AtomicLong UPDATE_COUNTER = new AtomicLong();
221 
222     // Default reset interval for generated preview API rate limiting.
223     private static final long DEFAULT_GENERATED_PREVIEW_RESET_INTERVAL_MS =
224             Duration.ofHours(1).toMillis();
225     // Default max API calls per reset interval for generated preview API rate limiting.
226     private static final int DEFAULT_GENERATED_PREVIEW_MAX_CALLS_PER_INTERVAL = 2;
227     // Default max number of providers for which to keep previews.
228     private static final int DEFAULT_GENERATED_PREVIEW_MAX_PROVIDERS = 50;
229     // XML attribute for widget ids that are pending deletion.
230     // See {@link Provider#pendingDeletedWidgetIds}.
231     private static final String PENDING_DELETED_IDS_ATTR = "pending_deleted_ids";
232     // Name of service directory in /data/system_ce/<user>/
233     private static final String APPWIDGET_CE_DATA_DIRNAME = "appwidget";
234     // Name of previews directory in /data/system_ce/<user>/appwidget/
235     private static final String WIDGET_PREVIEWS_DIRNAME = "previews";
236 
237     // Hard limit of number of hosts an app can create, note that the app that hosts the widgets
238     // can have multiple instances of {@link AppWidgetHost}, typically in respect to different
239     // surfaces in the host app.
240     // @see AppWidgetHost
241     // @see AppWidgetHost#mHostId
242     private static final int MAX_NUMBER_OF_HOSTS_PER_PACKAGE = 20;
243     // Hard limit of number of widgets can be pinned by a host.
244     private static final int MAX_NUMBER_OF_WIDGETS_PER_HOST = 200;
245 
246     // Handles user and package related broadcasts.
247     // See {@link #registerBroadcastReceiver}
248     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
249         @Override
250         public void onReceive(Context context, Intent intent) {
251             final String action = intent.getAction();
252             if (action == null) {
253                 return;
254             }
255 
256             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
257 
258             if (DEBUG) {
259                 Slog.i(TAG, "Received broadcast: " + action + " on user " + userId);
260             }
261 
262             switch (action) {
263                 case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:
264                 case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:
265                     synchronized (mLock) {
266                         reloadWidgetsMaskedState(userId);
267                     }
268                     break;
269                 case Intent.ACTION_PACKAGES_SUSPENDED:
270                     onPackageBroadcastReceived(intent, getSendingUserId());
271                     updateWidgetPackageSuspensionMaskedState(intent, true, getSendingUserId());
272                     break;
273                 case Intent.ACTION_PACKAGES_UNSUSPENDED:
274                     onPackageBroadcastReceived(intent, getSendingUserId());
275                     updateWidgetPackageSuspensionMaskedState(intent, false, getSendingUserId());
276                     break;
277                 case Intent.ACTION_PACKAGE_RESTARTED:
278                 case Intent.ACTION_PACKAGE_UNSTOPPED:
279                     if (!android.content.pm.Flags.stayStopped()) return;
280                     updateWidgetPackageStoppedMaskedState(intent);
281                     break;
282                 default:
283                     onPackageBroadcastReceived(intent, getSendingUserId());
284                     break;
285             }
286         }
287     };
288 
289     // Manages persistent references to RemoteViewsServices from different App Widgets.
290     private final HashMap<Pair<Integer, FilterComparison>, HashSet<Integer>>
291             mRemoteViewsServicesAppWidgets = new HashMap<>();
292 
293     // Synchronization lock for internal states in this service.
294     // TODO: Add GuardedBy annotation on states that need to be guarded.
295     private final Object mLock = new Object();
296 
297     // Instances of actual widgets currently bound to each host.
298     private final ArrayList<Widget> mWidgets = new ArrayList<>();
299     // Information about the host apps that has one or more widgets bound to it.
300     private final ArrayList<Host> mHosts = new ArrayList<>();
301     // Information about the provider apps who indicates that they provide App Widgets
302     // in their manifest.
303     private final ArrayList<Provider> mProviders = new ArrayList<>();
304     // Pairs of (userId, packageName) which has explicit consent from user to
305     // hold the MODIFY_APPWIDGET_BIND_PERMISSIONS permission.
306     // See {@link AppWidgetManager#setBindAppWidgetPermission}
307     private final ArraySet<Pair<Integer, String>> mPackagesWithBindWidgetPermission =
308             new ArraySet<>();
309     // Ids of users whose widgets/provider/hosts have been loaded from disk.
310     private final SparseBooleanArray mLoadedUserIds = new SparseBooleanArray();
311     // Synchronization lock dedicated to {@link #mWidgetPackages}.
312     private final Object mWidgetPackagesLock = new Object();
313     // Set of packages that has at least one widget bounded by a host, keyed on userId.
314     private final SparseArray<ArraySet<String>> mWidgetPackages = new SparseArray<>();
315 
316     private BackupRestoreController mBackupRestoreController;
317 
318     private final Context mContext;
319 
320     private IPackageManager mPackageManager;
321     private AlarmManager mAlarmManager;
322     private UserManager mUserManager;
323     private AppOpsManager mAppOpsManager;
324     private KeyguardManager mKeyguardManager;
325     private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
326     private PackageManagerInternal mPackageManagerInternal;
327     private ActivityManagerInternal mActivityManagerInternal;
328     private AppOpsManagerInternal mAppOpsManagerInternal;
329     private UsageStatsManagerInternal mUsageStatsManagerInternal;
330 
331     private SecurityPolicy mSecurityPolicy;
332 
333     // Handler to the background thread that saves states to disk.
334     private Handler mSaveStateHandler;
335 
336     private Handler mAlarmHandler;
337     // Handler to the background thread that saves generated previews to disk. All operations that
338     // modify saved previews must be run on this Handler.
339     private Handler mSavePreviewsHandler;
340     // Handler to the foreground thread that handles broadcasts related to user
341     // and package events, as well as various internal events within
342     // AppWidgetService.
343     private Handler mCallbackHandler;
344     // Map of user id to the next app widget id (monotonically increasing integer)
345     // that can be allocated for a new app widget.
346     // See {@link AppWidgetHost#allocateAppWidgetId}.
347     private final SparseIntArray mNextAppWidgetIds = new SparseIntArray();
348     // Indicates whether the device is running in safe mode.
349     private boolean mSafeMode;
350     // Load time validation of maximum memory can be used in widget bitmaps.
351     private int mMaxWidgetBitmapMemory;
352     // Feature flag that indicates whether
353     // {@link AppWidgetManager#ACTION_APPWIDGET_ENABLED} and
354     // {@linkAppWidgetManager#ACTION_APPWIDGET_UPDATE} are combined into a
355     // single broadcast.
356     private boolean mIsCombinedBroadcastEnabled;
357 
358     // Mark widget lifecycle broadcasts as 'interactive'
359     private Bundle mInteractiveBroadcast;
360     // Counter that keeps track of how many times generated preview API are
361     // being called to ensure they are subject to rate limiting.
362     private ApiCounter mGeneratedPreviewsApiCounter;
363 
AppWidgetServiceImpl(Context context)364     AppWidgetServiceImpl(Context context) {
365         mContext = context;
366     }
367 
368     @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG)
onStart()369     public void onStart() {
370         mPackageManager = AppGlobals.getPackageManager();
371         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
372         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
373         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
374         mKeyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
375         mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
376         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
377         if (removeAppWidgetServiceIoFromCriticalPath()) {
378             mSaveStateHandler = new Handler(BackgroundThread.get().getLooper(),
379                     this::handleSaveMessage);
380             mAlarmHandler = new Handler(BackgroundThread.get().getLooper());
381         } else {
382             mSaveStateHandler = BackgroundThread.getHandler();
383         }
384         mSavePreviewsHandler = new Handler(BackgroundThread.get().getLooper());
385         final ServiceThread serviceThread = new ServiceThread(TAG,
386                 android.os.Process.THREAD_PRIORITY_FOREGROUND, false /* allowIo */);
387         serviceThread.start();
388         mCallbackHandler = new CallbackHandler(serviceThread.getLooper());
389         mBackupRestoreController = new BackupRestoreController();
390         mSecurityPolicy = new SecurityPolicy();
391         mIsCombinedBroadcastEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
392             SystemUiDeviceConfigFlags.COMBINED_BROADCAST_ENABLED, true);
393 
394         final long generatedPreviewResetInterval = DeviceConfig.getLong(NAMESPACE_SYSTEMUI,
395                 SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_RESET_INTERVAL_MS,
396                 DEFAULT_GENERATED_PREVIEW_RESET_INTERVAL_MS);
397         final int generatedPreviewMaxCallsPerInterval = DeviceConfig.getInt(NAMESPACE_SYSTEMUI,
398                 SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_CALLS_PER_INTERVAL,
399                 DEFAULT_GENERATED_PREVIEW_MAX_CALLS_PER_INTERVAL);
400         final int generatedPreviewsMaxProviders = DeviceConfig.getInt(NAMESPACE_SYSTEMUI,
401                 SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS,
402                 DEFAULT_GENERATED_PREVIEW_MAX_PROVIDERS);
403         mGeneratedPreviewsApiCounter = new ApiCounter(generatedPreviewResetInterval,
404                 generatedPreviewMaxCallsPerInterval,
405                 // Set a limit on the number of providers if storing them in memory.
406                 remoteViewsProto() ? Integer.MAX_VALUE : generatedPreviewsMaxProviders);
407         DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI,
408                 new HandlerExecutor(mCallbackHandler), this::handleSystemUiDeviceConfigChange);
409 
410         BroadcastOptions opts = BroadcastOptions.makeBasic();
411         opts.setBackgroundActivityStartsAllowed(false);
412         opts.setInteractive(true);
413         mInteractiveBroadcast = opts.toBundle();
414 
415         computeMaximumWidgetBitmapMemory();
416         registerBroadcastReceiver();
417         registerOnCrossProfileProvidersChangedListener();
418 
419         LocalServices.addService(AppWidgetManagerInternal.class, new AppWidgetManagerLocal());
420     }
421 
422     /**
423      * Returns the maximum memory can be used in widget bitmaps, in respect to
424      * the display size. Note this should only be called after
425      * {@link #computeMaximumWidgetBitmapMemory} is invoked.
426      */
427     @Override
getMaxBitmapMemory()428     public int getMaxBitmapMemory() {
429         return mMaxWidgetBitmapMemory;
430     }
431 
432     /**
433      * Signals that system services (esp. ActivityManagerService) are ready.
434      */
systemServicesReady()435     void systemServicesReady() {
436         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
437         mAppOpsManagerInternal = LocalServices.getService(AppOpsManagerInternal.class);
438         mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
439         registerPullCallbacks();
440     }
441 
442     /**
443      * Register callbacks for pull atoms.
444      */
registerPullCallbacks()445     private void registerPullCallbacks() {
446         final StatsManager manager = mContext.getSystemService(StatsManager.class);
447         manager.setPullAtomCallback(FrameworkStatsLog.WIDGET_MEMORY_STATS,
448                 new StatsManager.PullAtomMetadata.Builder().build(),
449                 new HandlerExecutor(mCallbackHandler), this::onPullAtom);
450     }
451 
452     /**
453      * Callback from StatsManager to log events indicated by the atomTag. This function will add
454      * the relevant events to the data list.
455      *
456      * @return PULL_SUCCESS if the pull was successful and events should be used, else PULL_SKIP.
457      */
onPullAtom(int atomTag, @NonNull List<StatsEvent> data)458     private int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) {
459         if (atomTag == FrameworkStatsLog.WIDGET_MEMORY_STATS) {
460             synchronized (mLock) {
461                 for (Widget widget : mWidgets) {
462                     if (widget.views != null) {
463                         final int uid = widget.provider.id.uid;
464                         final int appWidgetId = widget.appWidgetId;
465                         final long bitmapMemoryUsage =
466                                 widget.views.estimateTotalBitmapMemoryUsage();
467                         StatsEvent event = FrameworkStatsLog.buildStatsEvent(
468                                 FrameworkStatsLog.WIDGET_MEMORY_STATS, uid, appWidgetId,
469                                 bitmapMemoryUsage);
470                         data.add(event);
471                     }
472                 }
473             }
474             return StatsManager.PULL_SUCCESS;
475         }
476         return StatsManager.PULL_SKIP;
477     }
478 
479     /**
480      * Computes the maximum memory can be used in widget bitmaps, in respect to
481      * the display size.
482      */
computeMaximumWidgetBitmapMemory()483     private void computeMaximumWidgetBitmapMemory() {
484         Display display = mContext.getDisplayNoVerify();
485         Point size = new Point();
486         display.getRealSize(size);
487         // Cap memory usage at 1.5 times the size of the display
488         // 1.5 * 4 bytes/pixel * w * h ==> 6 * w * h
489         mMaxWidgetBitmapMemory = 6 * size.x * size.y;
490     }
491 
492     /**
493      * Callback function that persists the states of the widgets to disk,
494      * should be scheduled on a background thread.
495      */
handleSaveMessage(Message msg)496     private boolean handleSaveMessage(Message msg) {
497         final int userId = msg.what;
498         SparseArray<byte[]> userIdToBytesMapping;
499         synchronized (mLock) {
500             // No need to enforce unlocked state when there is no caller. User can be in the
501             // stopping state or removed by the time the message is processed
502             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "convert_state_to_bytes");
503             ensureGroupStateLoadedLocked(userId, false /* enforceUserUnlockingOrUnlocked */);
504             userIdToBytesMapping = saveStateToByteArrayLocked(userId);
505             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
506         }
507 
508         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "byte_to_disk_io");
509         for (int i = 0; i < userIdToBytesMapping.size(); i++) {
510             int currentProfileId = userIdToBytesMapping.keyAt(i);
511             byte[] currentStateByteArray = userIdToBytesMapping.valueAt(i);
512             AtomicFile currentFile = getSavedStateFile(currentProfileId);
513             FileOutputStream fileStream;
514             try {
515                 fileStream = currentFile.startWrite();
516             } catch (IOException e) {
517                 Log.e(TAG, "Failed to start writing stream", e);
518                 continue;
519             }
520 
521             try {
522                 fileStream.write(currentStateByteArray);
523                 currentFile.finishWrite(fileStream);
524             } catch (IOException e) {
525                 Log.e(TAG, "Failed to write state byte stream to file", e);
526                 currentFile.failWrite(fileStream);
527             }
528         }
529         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
530 
531         return true;
532     }
533 
534     /**
535      * Register receivers for system broadcasts, esp. broadcasts from package manager.
536      */
registerBroadcastReceiver()537     private void registerBroadcastReceiver() {
538         // Register for broadcasts about package install, etc., so we can
539         // update the provider list.
540         IntentFilter packageFilter = new IntentFilter();
541         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
542         packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
543         packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
544         packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
545         packageFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
546         packageFilter.addAction(Intent.ACTION_PACKAGE_UNSTOPPED);
547         packageFilter.addDataScheme("package");
548         packageFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
549         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
550                 packageFilter, null, mCallbackHandler);
551 
552         // Register for events related to sdcard installation.
553         IntentFilter sdFilter = new IntentFilter();
554         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
555         sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
556         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
557                 sdFilter, null, mCallbackHandler);
558 
559         IntentFilter offModeFilter = new IntentFilter();
560         offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
561         offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
562         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
563                 offModeFilter, null, mCallbackHandler);
564 
565         IntentFilter suspendPackageFilter = new IntentFilter();
566         suspendPackageFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
567         suspendPackageFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
568         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
569                 suspendPackageFilter, null, mCallbackHandler);
570     }
571 
572     /**
573      * Listens to cross-profile widget providers changes.
574      *
575      * @see #onCrossProfileWidgetProvidersChanged
576      * @see DevicePolicyManager#addCrossProfileWidgetProvider
577      * @see DevicePolicyManager#removeCrossProfileWidgetProvider
578      */
registerOnCrossProfileProvidersChangedListener()579     private void registerOnCrossProfileProvidersChangedListener() {
580         // The device policy is an optional component.
581         if (mDevicePolicyManagerInternal != null) {
582             mDevicePolicyManagerInternal.addOnCrossProfileWidgetProvidersChangeListener(this);
583         }
584     }
585 
setSafeMode(boolean safeMode)586     public void setSafeMode(boolean safeMode) {
587         mSafeMode = safeMode;
588     }
589 
590     /**
591      * Handles broadcasts from package manager, add/remove/update widget
592      * providers in respect to changes in corresponding packages.
593      * Note: When a package is archived, it is treated as removed.
594      */
onPackageBroadcastReceived(Intent intent, int userId)595     private void onPackageBroadcastReceived(Intent intent, int userId) {
596         final String action = intent.getAction();
597         boolean added = false;
598         boolean changed = false;
599         boolean componentsModified = false;
600         int clearedUid = -1;
601 
602         final String pkgList[];
603         switch (action) {
604             case Intent.ACTION_PACKAGES_SUSPENDED:
605             case Intent.ACTION_PACKAGES_UNSUSPENDED:
606                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
607                 changed = true;
608                 break;
609             case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
610                 added = true;
611                 // fall through
612             case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
613                 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
614                 break;
615             case Intent.ACTION_PACKAGE_DATA_CLEARED:
616                 pkgList = null;
617                 clearedUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
618                 break;
619             default: {
620                 Uri uri = intent.getData();
621                 if (uri == null) {
622                     return;
623                 }
624                 String pkgName = uri.getSchemeSpecificPart();
625                 if (pkgName == null) {
626                     return;
627                 }
628                 pkgList = new String[] { pkgName };
629                 added = Intent.ACTION_PACKAGE_ADDED.equals(action);
630                 changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
631             }
632         }
633         if ((pkgList == null || pkgList.length == 0) && clearedUid == -1) {
634             return;
635         }
636 
637         synchronized (mLock) {
638             if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
639                     isProfileWithLockedParent(userId)) {
640                 return;
641             }
642             ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ false);
643 
644             Bundle extras = intent.getExtras();
645 
646             if (added || changed) {
647                 final boolean newPackageAdded = added && (extras == null
648                         || !extras.getBoolean(Intent.EXTRA_REPLACING, false));
649 
650                 for (String pkgName : pkgList) {
651                     // Fix up the providers - add/remove/update.
652                     componentsModified |= updateProvidersForPackageLocked(pkgName, userId, null);
653 
654                     // ... and see if these are hosts we've been awaiting.
655                     // NOTE: We are backing up and restoring only the owner.
656                     // TODO: http://b/22388012
657                     UserHandle mainUser = mUserManager.getMainUser();
658                     if (newPackageAdded && mainUser != null && userId == mainUser.getIdentifier()) {
659                         final int uid = getUidForPackage(pkgName, userId);
660                         if (uid >= 0 ) {
661                             resolveHostUidLocked(pkgName, uid);
662                         }
663                     }
664                 }
665             } else if (clearedUid != -1) {
666                 componentsModified |= clearPreviewsForUidLocked(clearedUid);
667             } else {
668                 // If the package is being updated, we'll receive a PACKAGE_ADDED
669                 // shortly, otherwise it is removed permanently.
670                 boolean isReplacing = extras != null && extras.getBoolean(Intent.EXTRA_REPLACING,
671                         false);
672                 boolean isArchival = extras != null && extras.getBoolean(Intent.EXTRA_ARCHIVAL,
673                         false);
674                 final boolean packageRemovedPermanently =
675                         (extras == null || !isReplacing || (isReplacing && isArchival));
676                 if (packageRemovedPermanently) {
677                     for (String pkgName : pkgList) {
678                         if (DEBUG) {
679                             Slog.i(TAG, "calling removeHostsAndProvidersForPackageLocked() "
680                                     + "because package removed permanently. extras=" + extras
681                                     + " isReplacing=" + isReplacing + " isArchival=" + isArchival);
682                         }
683                         componentsModified |= removeHostsAndProvidersForPackageLocked(
684                                 pkgName, userId);
685                     }
686                 }
687             }
688 
689             if (componentsModified) {
690                 saveGroupStateAsync(userId);
691 
692                 // If the set of providers has been modified, notify each active AppWidgetHost
693                 scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
694                 // Possibly notify any new components of widget id changes
695                 mBackupRestoreController.widgetComponentsChanged(userId);
696             }
697         }
698     }
699 
700     /**
701      * Clears the generated previews for all widgets belonging to the given UID.
702      * @return true if any previews were cleared.
703      */
704     @GuardedBy("mLock")
clearPreviewsForUidLocked(int clearedUid)705     private boolean clearPreviewsForUidLocked(int clearedUid) {
706         boolean changed = false;
707         final int providerCount = mProviders.size();
708         for (int i = 0; i < providerCount; i++) {
709             Provider provider = mProviders.get(i);
710             if (provider.id.uid == clearedUid) {
711                 if (remoteViewsProto()) {
712                     changed |= clearGeneratedPreviewsAsync(provider);
713                 } else {
714                     changed |= provider.clearGeneratedPreviewsLocked();
715                 }
716                 if (DEBUG) {
717                     Slog.e(TAG, "clearPreviewsForUidLocked " + provider + " changed " + changed);
718                 }
719             }
720         }
721         return changed;
722     }
723 
724     /**
725      * Reload all widgets' masked state for the given user and its associated profiles, including
726      * due to user not being available and package suspension.
727      * userId must be the group parent.
728      */
reloadWidgetsMaskedStateForGroup(int userId)729     void reloadWidgetsMaskedStateForGroup(int userId) {
730         if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
731             return;
732         }
733         synchronized (mLock) {
734             reloadWidgetsMaskedState(userId);
735             int[] profileIds = mUserManager.getEnabledProfileIds(userId);
736             for (int profileId : profileIds) {
737                 reloadWidgetsMaskedState(profileId);
738             }
739         }
740     }
741 
742     /**
743      * Reload all widgets' masked state for the given user or profile.
744      * Keep track of whether the given user or profile is locked, in quiet mode,
745      * suspended or stopped.
746      */
reloadWidgetsMaskedState(int userId)747     private void reloadWidgetsMaskedState(int userId) {
748         final long identity = Binder.clearCallingIdentity();
749         try {
750             UserInfo user  = mUserManager.getUserInfo(userId);
751 
752             boolean lockedProfile = !mUserManager.isUserUnlockingOrUnlocked(userId);
753             boolean quietProfile = user.isQuietModeEnabled();
754             final int N = mProviders.size();
755             for (int i = 0; i < N; i++) {
756                 Provider provider = mProviders.get(i);
757                 int providerUserId = provider.getUserId();
758                 if (providerUserId != userId) {
759                     continue;
760                 }
761 
762                 boolean changed = provider.setMaskedByLockedProfileLocked(lockedProfile);
763                 changed |= provider.setMaskedByQuietProfileLocked(quietProfile);
764                 try {
765                     boolean suspended;
766                     boolean stopped;
767                     try {
768                         suspended = mPackageManager.isPackageSuspendedForUser(
769                                 provider.id.componentName.getPackageName(), provider.getUserId());
770                         stopped = mPackageManager.isPackageStoppedForUser(
771                                 provider.id.componentName.getPackageName(), provider.getUserId());
772                     } catch (IllegalArgumentException ex) {
773                         // Package not found.
774                         suspended = false;
775                         stopped = false;
776                     }
777                     changed |= provider.setMaskedBySuspendedPackageLocked(suspended);
778                     changed |= provider.setMaskedByStoppedPackageLocked(stopped);
779                 } catch (RemoteException e) {
780                     Slog.e(TAG, "Failed to query application info", e);
781                 }
782                 if (changed) {
783                     if (provider.isMaskedLocked()) {
784                         maskWidgetsViewsLocked(provider, null);
785                     } else {
786                         unmaskWidgetsViewsLocked(provider);
787                     }
788                 }
789             }
790         } finally {
791             Binder.restoreCallingIdentity(identity);
792         }
793     }
794 
795     /**
796      * Incrementally update the masked state due to package suspension state.
797      */
updateWidgetPackageSuspensionMaskedState(Intent intent, boolean suspended, int profileId)798     private void updateWidgetPackageSuspensionMaskedState(Intent intent, boolean suspended,
799             int profileId) {
800         String[] packagesArray = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
801         if (packagesArray == null) {
802             return;
803         }
804         Set<String> packages = new ArraySet<>(Arrays.asList(packagesArray));
805         synchronized (mLock) {
806             final int N = mProviders.size();
807             for (int i = 0; i < N; i++) {
808                 Provider provider = mProviders.get(i);
809                 int providerUserId = provider.getUserId();
810                 if (providerUserId != profileId
811                         || !packages.contains(provider.id.componentName.getPackageName())) {
812                     continue;
813                 }
814                 if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
815                     if (provider.isMaskedLocked()) {
816                         maskWidgetsViewsLocked(provider, null);
817                     } else {
818                         unmaskWidgetsViewsLocked(provider);
819                     }
820                 }
821             }
822         }
823     }
824 
825     /**
826      * Update the masked state for a stopped or unstopped package.
827      */
updateWidgetPackageStoppedMaskedState(@onNull Intent intent)828     private void updateWidgetPackageStoppedMaskedState(@NonNull Intent intent) {
829         final int providerUid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
830         final Uri uri = intent.getData();
831         if (providerUid == Process.INVALID_UID || uri == null) {
832             return;
833         }
834 
835         final String packageName = uri.getSchemeSpecificPart();
836         if (packageName == null) {
837             return;
838         }
839 
840         boolean isStopped;
841         try {
842             isStopped = mPackageManager.isPackageStoppedForUser(packageName,
843                     UserHandle.getUserId(providerUid));
844         } catch (Exception e) {
845             Slog.e(TAG, "Failed to query package stopped state", e);
846             return;
847         }
848 
849         if (DEBUG) {
850             Slog.i(TAG, "Updating package stopped masked state for uid " + providerUid + " package "
851                     + packageName + " isStopped " + isStopped);
852         }
853         synchronized (mLock) {
854             final int count = mProviders.size();
855             for (int i = 0; i < count; i++) {
856                 Provider provider = mProviders.get(i);
857                 if (providerUid != provider.id.uid
858                         || !packageName.equals(provider.id.componentName.getPackageName())) {
859                     continue;
860                 }
861                 if (provider.setMaskedByStoppedPackageLocked(isStopped)) {
862                     if (provider.isMaskedLocked()) {
863                         maskWidgetsViewsLocked(provider, null);
864                         cancelBroadcastsLocked(provider);
865                     } else {
866                         unmaskWidgetsViewsLocked(provider);
867                         final int widgetCount = provider.widgets.size();
868                         if (widgetCount > 0) {
869                             final int[] widgetIds = new int[widgetCount];
870                             for (int j = 0; j < widgetCount; j++) {
871                                 widgetIds[j] = provider.widgets.get(j).appWidgetId;
872                             }
873                             registerForBroadcastsLocked(provider, widgetIds);
874                             sendUpdateIntentLocked(provider, widgetIds, /* interactive= */ false);
875                         }
876 
877                         final int pendingIdsCount = provider.pendingDeletedWidgetIds.size();
878                         if (pendingIdsCount > 0) {
879                             if (DEBUG) {
880                                 Slog.i(TAG, "Sending missed deleted broadcasts for "
881                                         + provider.id.componentName + " "
882                                         + provider.pendingDeletedWidgetIds);
883                             }
884                             for (int j = 0; j < pendingIdsCount; j++) {
885                                 sendDeletedIntentLocked(provider.id.componentName,
886                                         provider.id.getProfile(),
887                                         provider.pendingDeletedWidgetIds.get(j));
888                             }
889                             provider.pendingDeletedWidgetIds.clear();
890                             if (widgetCount == 0) {
891                                 sendDisabledIntentLocked(provider);
892                             }
893                             saveGroupStateAsync(provider.id.getProfile().getIdentifier());
894                         }
895                     }
896                 }
897             }
898         }
899     }
900 
901     /**
902      * Mask the target widget belonging to the specified provider, or all active widgets
903      * of the provider if target widget == null.
904      */
maskWidgetsViewsLocked(Provider provider, Widget targetWidget)905     private void maskWidgetsViewsLocked(Provider provider, Widget targetWidget) {
906         final int widgetCount = provider.widgets.size();
907         if (widgetCount == 0) {
908             return;
909         }
910         RemoteViews views = new RemoteViews(mContext.getPackageName(),
911                 R.layout.work_widget_mask_view);
912         final ActivityInfo activityInfo = provider.info.providerInfo;
913         final ApplicationInfo appInfo = activityInfo != null ? activityInfo.applicationInfo : null;
914         final String packageName = appInfo != null
915                 ? appInfo.packageName : provider.id.componentName.getPackageName();
916         final int appUserId = provider.getUserId();
917         boolean showBadge = false;
918 
919         final long identity = Binder.clearCallingIdentity();
920         try {
921             Intent onClickIntent = null;
922 
923             if (provider.maskedByQuietProfile) {
924                 showBadge = true;
925                 onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(appUserId);
926             } else if (provider.maskedBySuspendedPackage) {
927                 showBadge = mUserManager.hasBadge(appUserId);
928                 final UserPackage suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
929                         packageName, appUserId);
930                 // TODO(b/281839596): don't rely on platform always meaning suspended by admin.
931                 if (suspendingPackage != null
932                         && PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
933                     onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
934                             appUserId, true);
935                 } else {
936                     final SuspendDialogInfo dialogInfo =
937                             mPackageManagerInternal.getSuspendedDialogInfo(
938                                     packageName, suspendingPackage, appUserId);
939                     // onUnsuspend is null because we don't want to start any activity on
940                     // unsuspending from a suspended widget.
941                     onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(
942                             packageName, suspendingPackage, dialogInfo, null, null,
943                             appUserId);
944                 }
945             } else if (provider.maskedByLockedProfile) {
946                 showBadge = true;
947                 onClickIntent = mKeyguardManager
948                         .createConfirmDeviceCredentialIntent(null, null, appUserId);
949                 if (onClickIntent != null) {
950                     onClickIntent.setFlags(
951                             FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
952                 }
953             } else if (provider.maskedByStoppedPackage) {
954                 showBadge = mUserManager.hasBadge(appUserId);
955             }
956 
957             Icon icon = (appInfo != null && appInfo.icon != 0)
958                     ? Icon.createWithResource(appInfo.packageName, appInfo.icon)
959                     : Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon);
960             views.setImageViewIcon(R.id.work_widget_app_icon, icon);
961             if (!showBadge) {
962                 views.setViewVisibility(R.id.work_widget_badge_icon, View.INVISIBLE);
963             }
964 
965             for (int j = 0; j < widgetCount; j++) {
966                 Widget widget = provider.widgets.get(j);
967                 if (targetWidget != null && targetWidget != widget) continue;
968                 // Identify the user in the host process since the intent will be invoked by
969                 // the host app.
970                 final Host host = widget.host;
971                 final UserHandle hostUser;
972                 if (host != null && host.id != null) {
973                     hostUser = UserHandle.getUserHandleForUid(host.id.uid);
974                 } else {
975                     // Fallback to the parent profile if the host is null.
976                     Slog.w(TAG, "Host is null when masking widget: " + widget.appWidgetId);
977                     hostUser = mUserManager.getProfileParent(appUserId).getUserHandle();
978                 }
979                 if (provider.maskedByStoppedPackage) {
980                     Intent intent = createUpdateIntentLocked(provider,
981                             new int[] { widget.appWidgetId });
982                     views.setOnClickPendingIntent(android.R.id.background,
983                             PendingIntent.getBroadcastAsUser(mContext, widget.appWidgetId,
984                                     intent, PendingIntent.FLAG_UPDATE_CURRENT
985                                             | PendingIntent.FLAG_IMMUTABLE, hostUser));
986                 } else if (onClickIntent != null) {
987                     views.setOnClickPendingIntent(android.R.id.background,
988                             PendingIntent.getActivityAsUser(mContext, widget.appWidgetId,
989                             onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT
990                                     | PendingIntent.FLAG_IMMUTABLE, null /* options */,
991                             hostUser));
992                 }
993                 if (widget.replaceWithMaskedViewsLocked(views)) {
994                     scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
995                 }
996             }
997         } finally {
998             Binder.restoreCallingIdentity(identity);
999         }
1000     }
1001 
1002     /**
1003      * Unmask widgets of the specified provider. Notify the host to remove the masked views
1004      * if previously masked.
1005      */
unmaskWidgetsViewsLocked(Provider provider)1006     private void unmaskWidgetsViewsLocked(Provider provider) {
1007         final int widgetCount = provider.widgets.size();
1008         for (int j = 0; j < widgetCount; j++) {
1009             Widget widget = provider.widgets.get(j);
1010             if (widget.clearMaskedViewsLocked()) {
1011                 scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
1012             }
1013         }
1014     }
1015 
1016     /**
1017      * Called when a new package is installed, and updates {@link HostId} in corresponding
1018      * {@link Host}.
1019      */
resolveHostUidLocked(String pkg, int uid)1020     private void resolveHostUidLocked(String pkg, int uid) {
1021         final int N = mHosts.size();
1022         for (int i = 0; i < N; i++) {
1023             Host host = mHosts.get(i);
1024             if (host.id.uid == UNKNOWN_UID && pkg.equals(host.id.packageName)) {
1025                 if (DEBUG) {
1026                     Slog.i(TAG, "host " + host.id + " resolved to uid " + uid);
1027                 }
1028                 host.id = new HostId(uid, host.id.hostId, host.id.packageName);
1029                 return;
1030             }
1031         }
1032     }
1033 
1034     /**
1035      * Load widgets/providers/hosts for the specified user and all of its enabled
1036      * child profiles from disk if not already loaded.
1037      *
1038      * @param userId the user id to load
1039      *
1040      * @see #ensureGroupStateLoadedLocked(int, boolean)
1041      */
1042     @GuardedBy("mLock")
ensureGroupStateLoadedLocked(int userId)1043     private void ensureGroupStateLoadedLocked(int userId) {
1044         ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ true );
1045     }
1046 
1047     /**
1048      * Load widgets/providers/hosts for the specified user and all of its enabled
1049      * child profiles from disk if not already loaded.
1050      *
1051      * @param userId the user id to load
1052      * @param enforceUserUnlockingOrUnlocked if true, the user must be unlocked or unlocking
1053      * @throws IllegalStateException if the user or profile is not unlocked or unlocking and
1054      * {@code enforceUserUnlockingOrUnlocked} is true
1055      */
1056     @GuardedBy("mLock")
ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked)1057     private void ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked) {
1058         if (enforceUserUnlockingOrUnlocked && !isUserRunningAndUnlocked(userId)) {
1059             throw new IllegalStateException(
1060                     "User " + userId + " must be unlocked for widgets to be available");
1061         }
1062         if (enforceUserUnlockingOrUnlocked && isProfileWithLockedParent(userId)) {
1063             throw new IllegalStateException(
1064                     "Profile " + userId + " must have unlocked parent");
1065         }
1066         final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
1067 
1068         IntArray newIds = new IntArray(1);
1069         for (int profileId : profileIds) {
1070             if (!mLoadedUserIds.get(profileId)) {
1071                 mLoadedUserIds.put(profileId, true);
1072                 newIds.add(profileId);
1073             }
1074         }
1075         if (newIds.size() <= 0) {
1076             return;
1077         }
1078         final int[] newProfileIds = newIds.toArray();
1079         clearProvidersAndHostsTagsLocked();
1080 
1081         loadGroupWidgetProvidersLocked(newProfileIds);
1082         loadGroupStateLocked(newProfileIds);
1083     }
1084 
isUserRunningAndUnlocked(@serIdInt int userId)1085     private boolean isUserRunningAndUnlocked(@UserIdInt int userId) {
1086         return mUserManager.isUserUnlockingOrUnlocked(userId);
1087     }
1088 
1089     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1090     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1091         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1092 
1093         synchronized (mLock) {
1094             if (args.length > 0 && "--proto".equals(args[0])) {
1095                 dumpProto(fd);
1096             } else {
1097                 dumpInternalLocked(pw);
1098             }
1099         }
1100     }
1101 
dumpProto(FileDescriptor fd)1102     private void dumpProto(FileDescriptor fd) {
1103         Slog.i(TAG, "dump proto for " + mWidgets.size() + " widgets");
1104 
1105         ProtoOutputStream proto = new ProtoOutputStream(fd);
1106         int N = mWidgets.size();
1107         for (int i=0; i < N; i++) {
1108             dumpProtoWidget(proto, mWidgets.get(i));
1109         }
1110         proto.flush();
1111     }
1112 
dumpProtoWidget(ProtoOutputStream proto, Widget widget)1113     private void dumpProtoWidget(ProtoOutputStream proto, Widget widget) {
1114         if (widget.host == null || widget.provider == null) {
1115             Slog.d(TAG, "skip dumping widget because host or provider is null: widget.host="
1116                 + widget.host + " widget.provider="  + widget.provider);
1117             return;
1118         }
1119         long token = proto.start(AppWidgetServiceDumpProto.WIDGETS);
1120         proto.write(WidgetProto.IS_CROSS_PROFILE,
1121             widget.host.getUserId() != widget.provider.getUserId());
1122         proto.write(WidgetProto.IS_HOST_STOPPED, widget.host.callbacks == null);
1123         proto.write(WidgetProto.HOST_PACKAGE, widget.host.id.packageName);
1124         proto.write(WidgetProto.PROVIDER_PACKAGE, widget.provider.id.componentName.getPackageName());
1125         proto.write(WidgetProto.PROVIDER_CLASS, widget.provider.id.componentName.getClassName());
1126         if (widget.options != null) {
1127             proto.write(WidgetProto.RESTORE_COMPLETED,
1128                     widget.options.getBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED));
1129             proto.write(WidgetProto.MIN_WIDTH,
1130                 widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 0));
1131             proto.write(WidgetProto.MIN_HEIGHT,
1132                 widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 0));
1133             proto.write(WidgetProto.MAX_WIDTH,
1134                 widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 0));
1135             proto.write(WidgetProto.MAX_HEIGHT,
1136                 widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 0));
1137         }
1138         if (widget.views != null) {
1139             proto.write(WidgetProto.VIEWS_BITMAP_MEMORY,
1140                     widget.views.estimateTotalBitmapMemoryUsage());
1141         }
1142         proto.end(token);
1143     }
1144 
dumpInternalLocked(PrintWriter pw)1145     private void dumpInternalLocked(PrintWriter pw) {
1146         int N = mProviders.size();
1147         pw.println("Providers:");
1148         for (int i = 0; i < N; i++) {
1149             dumpProviderLocked(mProviders.get(i), i, pw);
1150         }
1151 
1152         N = mWidgets.size();
1153         pw.println(" ");
1154         pw.println("Widgets:");
1155         for (int i = 0; i < N; i++) {
1156             dumpWidget(mWidgets.get(i), i, pw);
1157         }
1158 
1159         N = mHosts.size();
1160         pw.println(" ");
1161         pw.println("Hosts:");
1162         for (int i = 0; i < N; i++) {
1163             dumpHost(mHosts.get(i), i, pw);
1164         }
1165 
1166         N = mPackagesWithBindWidgetPermission.size();
1167         pw.println(" ");
1168         pw.println("Grants:");
1169         for (int i = 0; i < N; i++) {
1170             Pair<Integer, String> grant = mPackagesWithBindWidgetPermission.valueAt(i);
1171             dumpGrant(grant, i, pw);
1172         }
1173     }
1174 
1175     /**
1176      * Called by {@link AppWidgetHost} to start listening for updates from specified widgets.
1177      */
1178     @Override
startListening(IAppWidgetHost callbacks, String callingPackage, int hostId, int[] appWidgetIds)1179     public ParceledListSlice<PendingHostUpdate> startListening(IAppWidgetHost callbacks,
1180             String callingPackage, int hostId, int[] appWidgetIds) {
1181         final int userId = UserHandle.getCallingUserId();
1182         if (DEBUG) {
1183             Slog.i(TAG, "startListening() " + userId);
1184         }
1185 
1186         // Make sure the package runs under the caller uid.
1187         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1188 
1189         synchronized (mLock) {
1190             // Instant apps cannot host app widgets.
1191             if (mSecurityPolicy.isInstantAppLocked(callingPackage, userId)) {
1192                 Slog.w(TAG, "Instant package " + callingPackage + " cannot host app widgets");
1193                 return ParceledListSlice.emptyList();
1194             }
1195 
1196             ensureGroupStateLoadedLocked(userId);
1197 
1198             // NOTE: The lookup is enforcing security across users by making
1199             // sure the caller can only access hosts it owns.
1200             HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
1201             Host host = lookupOrAddHostLocked(id);
1202             host.callbacks = callbacks;
1203 
1204             long updateSequenceNo = UPDATE_COUNTER.incrementAndGet();
1205             int N = appWidgetIds.length;
1206             ArrayList<PendingHostUpdate> outUpdates = new ArrayList<>(N);
1207             LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>();
1208             for (int i = 0; i < N; i++) {
1209                 updatesMap.clear();
1210                 host.getPendingUpdatesForIdLocked(mContext, appWidgetIds[i], updatesMap);
1211                 // We key the updates based on request id, so that the values are sorted in the
1212                 // order they were received.
1213                 int m = updatesMap.size();
1214                 for (int j = 0; j < m; j++) {
1215                     outUpdates.add(updatesMap.valueAt(j));
1216                 }
1217             }
1218             // Reset the update counter once all the updates have been calculated
1219             host.lastWidgetUpdateSequenceNo = updateSequenceNo;
1220             return new ParceledListSlice<>(outUpdates);
1221         }
1222     }
1223 
1224     /**
1225      * Called by {@link AppWidgetHost} to stop listening for updates from all
1226      * widgets bounded to this host.
1227      */
1228     @Override
stopListening(String callingPackage, int hostId)1229     public void stopListening(String callingPackage, int hostId) {
1230         final int userId = UserHandle.getCallingUserId();
1231 
1232         if (DEBUG) {
1233             Slog.i(TAG, "stopListening() " + userId);
1234         }
1235 
1236         // Make sure the package runs under the caller uid.
1237         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1238 
1239         synchronized (mLock) {
1240             ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ false);
1241 
1242             // NOTE: The lookup is enforcing security across users by making
1243             // sure the caller can only access hosts it owns.
1244             HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
1245             Host host = lookupHostLocked(id);
1246 
1247             if (host != null) {
1248                 host.callbacks = null;
1249                 pruneHostLocked(host);
1250                 mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUidsIfBound(),
1251                         false);
1252             }
1253         }
1254     }
1255 
1256     /**
1257      * Creates a new instance of app widget and associate it with the specified host.
1258      * Allocate a new app widget id for the new instance.
1259      */
1260     @Override
allocateAppWidgetId(String callingPackage, int hostId)1261     public int allocateAppWidgetId(String callingPackage, int hostId) {
1262         final int userId = UserHandle.getCallingUserId();
1263 
1264         if (DEBUG) {
1265             Slog.i(TAG, "allocateAppWidgetId() " + userId);
1266         }
1267 
1268         // Make sure the package runs under the caller uid.
1269         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1270 
1271         synchronized (mLock) {
1272             // Instant apps cannot host app widgets.
1273             if (mSecurityPolicy.isInstantAppLocked(callingPackage, userId)) {
1274                 Slog.w(TAG, "Instant package " + callingPackage + " cannot host app widgets");
1275                 return AppWidgetManager.INVALID_APPWIDGET_ID;
1276             }
1277 
1278             ensureGroupStateLoadedLocked(userId);
1279 
1280             if (mNextAppWidgetIds.indexOfKey(userId) < 0) {
1281                 mNextAppWidgetIds.put(userId, AppWidgetManager.INVALID_APPWIDGET_ID + 1);
1282             }
1283 
1284             final int appWidgetId = incrementAndGetAppWidgetIdLocked(userId);
1285 
1286             // NOTE: The lookup is enforcing security across users by making
1287             // sure the caller can only access hosts it owns.
1288             HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
1289             Host host = lookupOrAddHostLocked(id);
1290 
1291             Widget widget = new Widget();
1292             widget.appWidgetId = appWidgetId;
1293             widget.host = host;
1294 
1295             host.widgets.add(widget);
1296             addWidgetLocked(widget);
1297 
1298             saveGroupStateAsync(userId);
1299 
1300             if (DEBUG) {
1301                 Slog.i(TAG, "Allocated widget id " + appWidgetId
1302                         + " for host " + host.id);
1303             }
1304 
1305             return appWidgetId;
1306         }
1307     }
1308 
1309     /**
1310      * Called by {@link AppWidgetHost} to mark all widgets associated with this host
1311      * to be visually hidden (for state tracking).
1312      *
1313      * @see AppOpsManagerInternal#updateAppWidgetVisibility
1314      */
1315     @Override
setAppWidgetHidden(String callingPackage, int hostId)1316     public void setAppWidgetHidden(String callingPackage, int hostId) {
1317         final int userId = UserHandle.getCallingUserId();
1318 
1319         if (DEBUG) {
1320             Slog.i(TAG, "setAppWidgetHidden() " + userId);
1321         }
1322 
1323         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1324 
1325         synchronized (mLock) {
1326             ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */false);
1327 
1328             HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
1329             Host host = lookupHostLocked(id);
1330 
1331             if (host != null) {
1332                 mAppOpsManagerInternal.updateAppWidgetVisibility(host.getWidgetUidsIfBound(),
1333                         false);
1334             }
1335         }
1336     }
1337 
1338     /**
1339      * Deletes specified widget.
1340      * Note: appWidgetId is a monotonic increasing number, so the appWidgetId cannot be
1341      * reclaimed by a new widget.
1342      */
1343     @Override
deleteAppWidgetId(String callingPackage, int appWidgetId)1344     public void deleteAppWidgetId(String callingPackage, int appWidgetId) {
1345         final int userId = UserHandle.getCallingUserId();
1346 
1347         if (DEBUG) {
1348             Slog.i(TAG, "deleteAppWidgetId() " + userId);
1349         }
1350 
1351         // Make sure the package runs under the caller uid.
1352         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1353 
1354         synchronized (mLock) {
1355             ensureGroupStateLoadedLocked(userId);
1356 
1357             // NOTE: The lookup is enforcing security across users by making
1358             // sure the caller can only access widgets it hosts or provides.
1359             Widget widget = lookupWidgetLocked(appWidgetId,
1360                     Binder.getCallingUid(), callingPackage);
1361 
1362             if (widget == null) {
1363                 return;
1364             }
1365 
1366             deleteAppWidgetLocked(widget);
1367 
1368             saveGroupStateAsync(userId);
1369 
1370             if (DEBUG) {
1371                 Slog.i(TAG, "Deleted widget id " + appWidgetId
1372                         + " for host " + widget.host.id);
1373             }
1374         }
1375     }
1376 
1377     /**
1378      * Query if a given package was granted permission by the user to bind app widgets.
1379      *
1380      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
1381      *
1382      * @param packageName The package for which the permission is being queried
1383      * @param userId The user id of the user under which the package runs.
1384      * @return true if the package was granted permission by the user to bind app widgets
1385      *
1386      * @see AppWidgetManager#hasBindAppWidgetPermission(String, int)
1387      */
1388     @Override
hasBindAppWidgetPermission(String packageName, int userId)1389     public boolean hasBindAppWidgetPermission(String packageName, int userId) {
1390         if (DEBUG) {
1391             Slog.i(TAG, "hasBindAppWidgetPermission() " + UserHandle.getCallingUserId());
1392         }
1393 
1394         // A special permission is required for managing allowlisting.
1395         mSecurityPolicy.enforceModifyAppWidgetBindPermissions(packageName);
1396 
1397         synchronized (mLock) {
1398             // The grants are stored in user state wich gets the grant.
1399             ensureGroupStateLoadedLocked(userId);
1400 
1401             final int packageUid = getUidForPackage(packageName, userId);
1402             if (packageUid < 0) {
1403                 return false;
1404             }
1405 
1406             Pair<Integer, String> packageId = Pair.create(userId, packageName);
1407             return mPackagesWithBindWidgetPermission.contains(packageId);
1408         }
1409     }
1410 
1411     /**
1412      * Changes any user-granted permission for the given package to bind app widgets.
1413      *
1414      * <p class="note">You need the MODIFY_APPWIDGET_BIND_PERMISSIONS permission
1415      *
1416      * @param packageName The package whose permission is being changed
1417      * @param userId The user under which the package is running.
1418      * @param permission Whether to give the package permission to bind widgets
1419      *
1420      * @see AppWidgetManager#setBindAppWidgetPermission(String, int, boolean)
1421      */
1422     @Override
setBindAppWidgetPermission(String packageName, int userId, boolean grantPermission)1423     public void setBindAppWidgetPermission(String packageName, int userId,
1424             boolean grantPermission) {
1425         if (DEBUG) {
1426             Slog.i(TAG, "setBindAppWidgetPermission() " + UserHandle.getCallingUserId());
1427         }
1428 
1429         // A special permission is required for managing allowlisting.
1430         mSecurityPolicy.enforceModifyAppWidgetBindPermissions(packageName);
1431 
1432         synchronized (mLock) {
1433             // The grants are stored in user state wich gets the grant.
1434             ensureGroupStateLoadedLocked(userId);
1435 
1436             final int packageUid = getUidForPackage(packageName, userId);
1437             if (packageUid < 0) {
1438                 return;
1439             }
1440 
1441             Pair<Integer, String> packageId = Pair.create(userId, packageName);
1442             if (grantPermission) {
1443                 mPackagesWithBindWidgetPermission.add(packageId);
1444             } else {
1445                 mPackagesWithBindWidgetPermission.remove(packageId);
1446             }
1447 
1448             saveGroupStateAsync(userId);
1449         }
1450     }
1451 
1452     /**
1453      * Called by {@link AppWidgetHost} to start app widget provider configure
1454      * activity for result.
1455      * This method is used if the provider is in a profile different from the host
1456      * as the host is not allowed to start an activity in another profile.
1457      * <p>
1458      * Note that the provided app widget has to be bound for this method to work.
1459      * </p>
1460      *
1461      * @param callingPackage Package that calls this method.
1462      * @param appWidgetId The bound app widget whose provider's config activity to start.
1463      * @param intentFlags Optional intent flags.
1464      * @return IntentSender to start the config activity.
1465      * @throws IllegalArgumentException If the widget is not found.
1466      *
1467      * @see AppWidgetProviderInfo#getProfile()
1468      * @see AppWidgetHost#startAppWidgetConfigureActivityForResult
1469      */
1470     @Override
createAppWidgetConfigIntentSender(String callingPackage, int appWidgetId, final int intentFlags)1471     public IntentSender createAppWidgetConfigIntentSender(String callingPackage, int appWidgetId,
1472             final int intentFlags) {
1473         final int userId = UserHandle.getCallingUserId();
1474 
1475         if (DEBUG) {
1476             Slog.i(TAG, "createAppWidgetConfigIntentSender() " + userId);
1477         }
1478 
1479         // Make sure the package runs under the caller uid.
1480         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1481 
1482         synchronized (mLock) {
1483             ensureGroupStateLoadedLocked(userId);
1484 
1485             // NOTE: The lookup is enforcing security across users by making
1486             // sure the caller can only access widgets it hosts or provides.
1487             Widget widget = lookupWidgetLocked(appWidgetId,
1488                     Binder.getCallingUid(), callingPackage);
1489 
1490             if (widget == null) {
1491                 throw new IllegalArgumentException("Bad widget id " + appWidgetId);
1492             }
1493 
1494             Provider provider = widget.provider;
1495             if (provider == null) {
1496                 throw new IllegalArgumentException("Widget not bound " + appWidgetId);
1497             }
1498 
1499             // Make sure only safe flags can be passed it.
1500             final int secureFlags = intentFlags & ~Intent.IMMUTABLE_FLAGS;
1501 
1502             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
1503             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
1504             intent.setComponent(provider.getInfoLocked(mContext).configure);
1505             intent.setFlags(secureFlags);
1506 
1507             final ActivityOptions options =
1508                     ActivityOptions.makeBasic().setPendingIntentCreatorBackgroundActivityStartMode(
1509                             ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED);
1510 
1511             // All right, create the sender.
1512             final long identity = Binder.clearCallingIdentity();
1513             try {
1514                 return PendingIntent.getActivityAsUser(
1515                         mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
1516                                 | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
1517                                 options.toBundle(), new UserHandle(provider.getUserId()))
1518                         .getIntentSender();
1519             } finally {
1520                 Binder.restoreCallingIdentity(identity);
1521             }
1522         }
1523     }
1524 
1525     /**
1526      * Associates an {@link Widget} (as specified by {@code appWidgetId}) with
1527      * a {@link Provider} (as specified by {@code providerComponent}) from
1528      * a specific user/profile, if applicable.
1529      *
1530      * Note: The {@link Widget} itself is already associated with its {@link Host}
1531      * in {@link #allocateAppWidgetId}.
1532      *
1533      * @param callingPackage The package that calls this method.
1534      * @param appWidgetId The id of the widget to bind.
1535      * @param providerProfileId The user/profile id of the provider.
1536      * @param providerComponent The {@link ComponentName} that provides the widget.
1537      * @param options The options to pass to the provider.
1538      * @see AppWidgetManager#bindAppWidgetIdIfAllowed(int, ComponentName)
1539      * @see AppWidgetManager#bindAppWidgetIdIfAllowed(int, ComponentName, Bundle)
1540      * @see AppWidgetManager#bindAppWidgetIdIfAllowed(int, UserHandle, ComponentName, Bundle)
1541      */
1542     @Override
bindAppWidgetId(String callingPackage, int appWidgetId, int providerProfileId, ComponentName providerComponent, Bundle options)1543     public boolean bindAppWidgetId(String callingPackage, int appWidgetId,
1544             int providerProfileId, ComponentName providerComponent, Bundle options) {
1545         final int userId = UserHandle.getCallingUserId();
1546 
1547         if (DEBUG) {
1548             Slog.i(TAG, "bindAppWidgetId() " + userId);
1549         }
1550 
1551         // Make sure the package runs under the caller uid.
1552         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1553 
1554         // Check that if a cross-profile binding is attempted, it is allowed.
1555         if (!mSecurityPolicy.isEnabledGroupProfile(providerProfileId)) {
1556             return false;
1557         }
1558 
1559         // If the provider is not under the calling user, make sure this provider is allowlisted for
1560         // access from the parent, or that the caller has permission to interact across users.
1561         if (!mSecurityPolicy.canAccessProvider(
1562                 providerComponent.getPackageName(), providerProfileId)) {
1563             return false;
1564         }
1565 
1566         synchronized (mLock) {
1567             ensureGroupStateLoadedLocked(userId);
1568 
1569             // A special permission or allowlisting is required to bind widgets.
1570             if (!mSecurityPolicy.hasCallerBindPermissionOrBindWhiteListedLocked(
1571                     callingPackage)) {
1572                 return false;
1573             }
1574 
1575             // NOTE: The lookup is enforcing security across users by making
1576             // sure the caller can only access widgets it hosts or provides.
1577             Widget widget = lookupWidgetLocked(appWidgetId,
1578                     Binder.getCallingUid(), callingPackage);
1579 
1580             if (widget == null) {
1581                 Slog.e(TAG, "Bad widget id " + appWidgetId);
1582                 return false;
1583             }
1584 
1585             if (widget.provider != null) {
1586                 Slog.e(TAG, "Widget id " + appWidgetId
1587                         + " already bound to: " + widget.provider.id);
1588                 return false;
1589             }
1590 
1591             final int providerUid = getUidForPackage(providerComponent.getPackageName(),
1592                     providerProfileId);
1593             if (providerUid < 0) {
1594                 Slog.e(TAG, "Package " + providerComponent.getPackageName() + " not installed "
1595                         + " for profile " + providerProfileId);
1596                 return false;
1597             }
1598 
1599             // NOTE: The lookup is enforcing security across users by making
1600             // sure the provider is in the already vetted user profile.
1601             ProviderId providerId = new ProviderId(providerUid, providerComponent);
1602             Provider provider = lookupProviderLocked(providerId);
1603 
1604             if (provider == null) {
1605                 Slog.e(TAG, "No widget provider " + providerComponent + " for profile "
1606                         + providerProfileId);
1607                 return false;
1608             }
1609 
1610             if (provider.zombie) {
1611                 Slog.e(TAG, "Can't bind to a 3rd party provider in"
1612                         + " safe mode " + provider);
1613                 return false;
1614             }
1615 
1616             widget.provider = provider;
1617             widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle();
1618 
1619             // We need to provide a default value for the widget category if it is not specified
1620             if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
1621                 widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
1622                         AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
1623             }
1624 
1625             provider.widgets.add(widget);
1626 
1627             onWidgetProviderAddedOrChangedLocked(widget);
1628 
1629             final int widgetCount = provider.widgets.size();
1630             if (widgetCount == 1) {
1631                 // If we are binding the very first widget from a provider, we will send
1632                 // a combined broadcast or 2 separate broadcasts to tell the provider that
1633                 // it's ready, and we need them to provide the update now.
1634                 sendEnableAndUpdateIntentLocked(provider, new int[]{appWidgetId});
1635             } else {
1636                 // For any widget other then the first one, we just send update intent
1637                 // as we normally would.
1638                 sendUpdateIntentLocked(provider, new int[]{appWidgetId}, true);
1639             }
1640 
1641             // Schedule the future updates.
1642             registerForBroadcastsLocked(provider, getWidgetIds(provider.widgets));
1643 
1644             saveGroupStateAsync(userId);
1645             Slog.i(TAG, "Bound widget " + appWidgetId + " to provider " + provider.id);
1646         }
1647 
1648         return true;
1649     }
1650 
1651     /**
1652      * Get the list of appWidgetIds that have been bound to the given AppWidget
1653      * provider.
1654      *
1655      * Note: User can create multiple instances of {@link Widget} that are
1656      * supplied by the same {@link Provider}.
1657      *
1658      * @param provider The {@link android.content.BroadcastReceiver} that is the
1659      *            AppWidget provider to find appWidgetIds for.
1660      * @see AppWidgetManager#getAppWidgetIds(ComponentName)
1661      */
1662     @Override
getAppWidgetIds(ComponentName componentName)1663     public int[] getAppWidgetIds(ComponentName componentName) {
1664         final int userId = UserHandle.getCallingUserId();
1665 
1666         if (DEBUG) {
1667             Slog.i(TAG, "getAppWidgetIds() " + userId);
1668         }
1669 
1670         // Make sure the package runs under the caller uid.
1671         mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
1672 
1673         synchronized (mLock) {
1674             ensureGroupStateLoadedLocked(userId);
1675 
1676             // NOTE: The lookup is enforcing security across users by making
1677             // sure the caller can access only its providers.
1678             ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
1679             Provider provider = lookupProviderLocked(providerId);
1680 
1681             if (provider != null) {
1682                 return getWidgetIds(provider.widgets);
1683             }
1684 
1685             return new int[0];
1686         }
1687     }
1688 
1689     /**
1690      * Gets a list of appWidgetIds that are bound to the specified host.
1691      *
1692      * @param callingPackage The package that calls this method.
1693      * @param hostId id of the {@link Host}.
1694      * @rerurn int[] list of appWidgetIds that are bound to this host.
1695      */
1696     @Override
getAppWidgetIdsForHost(String callingPackage, int hostId)1697     public int[] getAppWidgetIdsForHost(String callingPackage, int hostId) {
1698         final int userId = UserHandle.getCallingUserId();
1699 
1700         if (DEBUG) {
1701             Slog.i(TAG, "getAppWidgetIdsForHost() " + userId);
1702         }
1703 
1704         // Make sure the package runs under the caller uid.
1705         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1706 
1707         synchronized (mLock) {
1708             ensureGroupStateLoadedLocked(userId);
1709 
1710             // NOTE: The lookup is enforcing security across users by making
1711             // sure the caller can only access its hosts.
1712             HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
1713             Host host = lookupHostLocked(id);
1714 
1715             if (host != null) {
1716                 return getWidgetIds(host.widgets);
1717             }
1718 
1719             return new int[0];
1720         }
1721     }
1722 
1723     /**
1724      * Binds the RemoteViewsService for a given appWidgetId and intent.
1725      * This method is used by {@link RemoteViewsAdapter} to establish a connection
1726      * to the {@link RemoteViewsService} that provides data for the adapter.
1727      *
1728      * The appWidgetId specified must already be bound to the calling AppWidgetHost via
1729      * {@link android.appwidget.AppWidgetManager#bindAppWidgetId AppWidgetManager.bindAppWidgetId()}.
1730      *
1731      * Note: Since {@link AppWidgetManager#setRemoteAdapter(int, RemoteViewsAdapter))} is deprecated,
1732      * this method is effectively deprecated as well.
1733      *
1734      * @param callingPackage The package that calls this method.
1735      * @param appWidgetId   The AppWidget instance for which to bind the RemoteViewsService.
1736      * @param intent        The intent of the service which will be providing the data to the
1737      *                      RemoteViewsAdapter.
1738      * @param caller        Caller's {@link IApplicationThread}, see
1739      *                      {@link Context#getIApplicationThread()}
1740      * @param activityToken Caller's {@link IBinder}, see {@link Context#getActivityToken()}
1741      * @param connection    The callback interface to be notified when a connection is made or lost.
1742      * @param flags         Flags used for binding to the service. Only
1743      *                     {@link Context#BIND_AUTO_CREATE} and
1744      *                     {@link Context#BIND_FOREGROUND_SERVICE_WHILE_AWAKE} are supported.
1745      *
1746      * @see AppWidgetManager#setRemoteAdapter(int, RemoteViewsAdapter)
1747      */
1748     @Override
bindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent, IApplicationThread caller, IBinder activtiyToken, IServiceConnection connection, long flags)1749     public boolean bindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent,
1750             IApplicationThread caller, IBinder activtiyToken, IServiceConnection connection,
1751             long flags) {
1752         if (remoteAdapterConversion()) {
1753             throw new UnsupportedOperationException("bindRemoteViewsService is deprecated");
1754         }
1755         final int userId = UserHandle.getCallingUserId();
1756         if (DEBUG) {
1757             Slog.i(TAG, "bindRemoteViewsService() " + userId);
1758         }
1759 
1760         synchronized (mLock) {
1761             ensureGroupStateLoadedLocked(userId);
1762 
1763             // NOTE: The lookup is enforcing security across users by making
1764             // sure the caller can only access widgets it hosts or provides.
1765             Widget widget = lookupWidgetLocked(appWidgetId,
1766                     Binder.getCallingUid(), callingPackage);
1767 
1768             if (widget == null) {
1769                 throw new IllegalArgumentException("Bad widget id");
1770             }
1771 
1772             // Make sure the widget has a provider.
1773             if (widget.provider == null) {
1774                 throw new IllegalArgumentException("No provider for widget "
1775                         + appWidgetId);
1776             }
1777 
1778             ComponentName componentName = intent.getComponent();
1779 
1780             // Ensure that the service belongs to the same package as the provider.
1781             // But this is not enough as they may be under different users - see below...
1782             String providerPackage = widget.provider.id.componentName.getPackageName();
1783             String servicePackage = componentName.getPackageName();
1784             if (!servicePackage.equals(providerPackage)) {
1785                 throw new SecurityException("The taget service not in the same package"
1786                         + " as the widget provider");
1787             }
1788 
1789             // Make sure this service exists under the same user as the provider and
1790             // requires a permission which allows only the system to bind to it.
1791             mSecurityPolicy.enforceServiceExistsAndRequiresBindRemoteViewsPermission(
1792                     componentName, widget.provider.getUserId());
1793 
1794             // Good to go - the service package is correct, it exists for the correct
1795             // user, and requires the bind permission.
1796 
1797             final long callingIdentity = Binder.clearCallingIdentity();
1798             try {
1799                 // Ask ActivityManager to bind it. Notice that we are binding the service with the
1800                 // caller app instead of DevicePolicyManagerService.
1801                 if (ActivityManager.getService().bindService(
1802                         caller, activtiyToken, intent,
1803                         intent.resolveTypeIfNeeded(mContext.getContentResolver()),
1804                         connection, flags & (Context.BIND_AUTO_CREATE
1805                                 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE),
1806                         mContext.getOpPackageName(), widget.provider.getUserId()) != 0) {
1807 
1808                     // Add it to the mapping of RemoteViewsService to appWidgetIds so that we
1809                     // can determine when we can call back to the RemoteViewsService later to
1810                     // destroy associated factories.
1811                     incrementAppWidgetServiceRefCount(appWidgetId,
1812                             Pair.create(widget.provider.id.uid, new FilterComparison(intent)));
1813                     return true;
1814                 }
1815             } catch (RemoteException ex) {
1816                 // Same process, should not happen.
1817             } finally {
1818                 Binder.restoreCallingIdentity(callingIdentity);
1819             }
1820         }
1821 
1822         // Failed to bind.
1823         return false;
1824     }
1825 
1826     /**
1827      * Called by a {@link AppWidgetHost} to remove all records (i.e. {@link Host}
1828      * and all {@link Widget} associated with the host) from a specified host.
1829      *
1830      * @param callingPackage The package that calls this method.
1831      * @param hostId id of the {@link Host}.
1832      * @see AppWidgetHost#deleteHost()
1833      */
1834     @Override
deleteHost(String callingPackage, int hostId)1835     public void deleteHost(String callingPackage, int hostId) {
1836         final int userId = UserHandle.getCallingUserId();
1837 
1838         if (DEBUG) {
1839             Slog.i(TAG, "deleteHost() " + userId);
1840         }
1841 
1842         // Make sure the package runs under the caller uid.
1843         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1844 
1845         synchronized (mLock) {
1846             ensureGroupStateLoadedLocked(userId);
1847 
1848             // NOTE: The lookup is enforcing security across users by making
1849             // sure the caller can only access hosts in its uid and package.
1850             HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
1851             Host host = lookupHostLocked(id);
1852 
1853             if (host == null) {
1854                 return;
1855             }
1856 
1857             deleteHostLocked(host);
1858 
1859             saveGroupStateAsync(userId);
1860 
1861             if (DEBUG) {
1862                 Slog.i(TAG, "Deleted host " + host.id);
1863             }
1864         }
1865     }
1866 
1867     /**
1868      * Called by a host process to remove all records (i.e. {@link Host}
1869      * and all {@link Widget} associated with the host) from all hosts associated
1870      * with the calling process.
1871      *
1872      * Typically used in clean up after test execution.
1873      *
1874      * @see AppWidgetHost#deleteAllHosts()
1875      */
1876     @Override
deleteAllHosts()1877     public void deleteAllHosts() {
1878         final int userId = UserHandle.getCallingUserId();
1879 
1880         if (DEBUG) {
1881             Slog.i(TAG, "deleteAllHosts() " + userId);
1882         }
1883 
1884         synchronized (mLock) {
1885             ensureGroupStateLoadedLocked(userId);
1886 
1887             boolean changed = false;
1888 
1889             final int N = mHosts.size();
1890             for (int i = N - 1; i >= 0; i--) {
1891                 Host host = mHosts.get(i);
1892 
1893                 // Delete only hosts in the calling uid.
1894                 if (host.id.uid == Binder.getCallingUid()) {
1895                     deleteHostLocked(host);
1896                     changed = true;
1897 
1898                     if (DEBUG) {
1899                         Slog.i(TAG, "Deleted host " + host.id);
1900                     }
1901                 }
1902             }
1903 
1904             if (changed) {
1905                 saveGroupStateAsync(userId);
1906             }
1907         }
1908     }
1909 
1910     /**
1911      * Returns the {@link AppWidgetProviderInfo} for the specified AppWidget.
1912      *
1913      * Typically used by launcher during the restore of an AppWidget, the binding
1914      * of new AppWidget, and during grid size migration.
1915      *
1916      * @param callingPackage The package that calls this method.
1917      * @param appWidgetId   Id of the widget.
1918      * @return The {@link AppWidgetProviderInfo} for the specified widget.
1919      *
1920      * @see AppWidgetManager#getAppWidgetInfo(int)
1921      */
1922     @Override
getAppWidgetInfo(String callingPackage, int appWidgetId)1923     public AppWidgetProviderInfo getAppWidgetInfo(String callingPackage, int appWidgetId) {
1924         final int userId = UserHandle.getCallingUserId();
1925 
1926         if (DEBUG) {
1927             Slog.i(TAG, "getAppWidgetInfo() " + userId);
1928         }
1929 
1930         // Make sure the package runs under the caller uid.
1931         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1932 
1933         synchronized (mLock) {
1934             ensureGroupStateLoadedLocked(userId);
1935 
1936             // NOTE: The lookup is enforcing security across users by making
1937             // sure the caller can only access widgets it hosts or provides.
1938             Widget widget = lookupWidgetLocked(appWidgetId,
1939                     Binder.getCallingUid(), callingPackage);
1940 
1941             if (widget != null && widget.provider != null && !widget.provider.zombie) {
1942                 final AppWidgetProviderInfo info = widget.provider.getInfoLocked(mContext);
1943                 if (info == null) {
1944                     Slog.e(TAG, "getAppWidgetInfo() returns null because"
1945                             + " widget.provider.getInfoLocked() returned null."
1946                             + " appWidgetId=" + appWidgetId + " userId=" + userId
1947                             + " widget=" + widget);
1948                     return null;
1949                 }
1950                 final AppWidgetProviderInfo ret = cloneIfLocalBinder(info);
1951                 if (ret == null) {
1952                     Slog.e(TAG, "getAppWidgetInfo() returns null because"
1953                             + " cloneIfLocalBinder() returned null."
1954                             + " appWidgetId=" + appWidgetId + " userId=" + userId
1955                             + " widget=" + widget + " appWidgetProviderInfo=" + info);
1956                 }
1957                 return ret;
1958             } else {
1959                 if (widget == null) {
1960                     Slog.e(TAG, "getAppWidgetInfo() returns null because widget is null."
1961                             + " appWidgetId=" + appWidgetId + " userId=" + userId);
1962                 } else if (widget.provider == null) {
1963                     Slog.e(TAG, "getAppWidgetInfo() returns null because widget.provider is null."
1964                             + " appWidgetId=" + appWidgetId + " userId=" + userId
1965                             + " widget=" + widget);
1966                 } else {
1967                     Slog.e(TAG, "getAppWidgetInfo() returns null because widget.provider is zombie."
1968                             + " appWidgetId=" + appWidgetId + " userId=" + userId
1969                             + " widget=" + widget);
1970                 }
1971             }
1972             return null;
1973         }
1974     }
1975 
1976     /**
1977      * Returns the most recent {@link RemoteViews} of the specified AppWidget.
1978      * Typically serves as a cache of the content of the AppWidget.
1979      *
1980      * @param callingPackage The package that calls this method.
1981      * @param appWidgetId   Id of the widget.
1982      * @return The {@link RemoteViews} of the specified widget.
1983      *
1984      * @see AppWidgetHost#updateAppWidgetDeferred(String, int)
1985      * @see AppWidgetHost#setListener(int, AppWidgetHostListener)
1986      */
1987     @Override
getAppWidgetViews(String callingPackage, int appWidgetId)1988     public RemoteViews getAppWidgetViews(String callingPackage, int appWidgetId) {
1989         final int userId = UserHandle.getCallingUserId();
1990 
1991         if (DEBUG) {
1992             Slog.i(TAG, "getAppWidgetViews() " + userId);
1993         }
1994 
1995         // Make sure the package runs under the caller uid.
1996         mSecurityPolicy.enforceCallFromPackage(callingPackage);
1997 
1998         synchronized (mLock) {
1999             ensureGroupStateLoadedLocked(userId);
2000 
2001             // NOTE: The lookup is enforcing security across users by making
2002             // sure the caller can only access widgets it hosts or provides.
2003             Widget widget = lookupWidgetLocked(appWidgetId,
2004                     Binder.getCallingUid(), callingPackage);
2005 
2006             if (widget != null) {
2007                 return cloneIfLocalBinder(widget.getEffectiveViewsLocked());
2008             }
2009 
2010             return null;
2011         }
2012     }
2013 
2014     /**
2015      * Update the extras for a given widget instance.
2016      * <p>
2017      * The extras can be used to embed additional information about this widget to be accessed
2018      * by the associated widget's AppWidgetProvider.
2019      *
2020      * <p>
2021      * The new options are merged into existing options using {@link Bundle#putAll} semantics.
2022      *
2023      * <p>
2024      * Typically called by a {@link AppWidgetHost} (e.g. Launcher) to notify
2025      * {@link AppWidgetProvider} regarding contextual changes (e.g. sizes) when rendering the
2026      * widget.
2027      * Calling this method would trigger onAppWidgetOptionsChanged() callback on the provider's
2028      * side.
2029      *
2030      * @param callingPackage The package that calls this method.
2031      * @param appWidgetId Id of the widget.
2032      * @param options New options associate with this widget.
2033      *
2034      * @see AppWidgetManager#getAppWidgetOptions(int, Bundle)
2035      * @see AppWidgetProvider#onAppWidgetOptionsChanged(Context, AppWidgetManager, int, Bundle)
2036      */
2037     @Override
updateAppWidgetOptions(String callingPackage, int appWidgetId, Bundle options)2038     public void updateAppWidgetOptions(String callingPackage, int appWidgetId, Bundle options) {
2039         final int userId = UserHandle.getCallingUserId();
2040 
2041         if (DEBUG) {
2042             Slog.i(TAG, "updateAppWidgetOptions() " + userId);
2043         }
2044 
2045         // Make sure the package runs under the caller uid.
2046         mSecurityPolicy.enforceCallFromPackage(callingPackage);
2047 
2048         synchronized (mLock) {
2049             ensureGroupStateLoadedLocked(userId);
2050 
2051             // NOTE: The lookup is enforcing security across users by making
2052             // sure the caller can only access widgets it hosts or provides.
2053             Widget widget = lookupWidgetLocked(appWidgetId,
2054                     Binder.getCallingUid(), callingPackage);
2055 
2056             if (widget == null) {
2057                 return;
2058             }
2059 
2060             // Merge the options.
2061             widget.options.putAll(options);
2062 
2063             // Send the broacast to notify the provider that options changed.
2064             sendOptionsChangedIntentLocked(widget);
2065 
2066             saveGroupStateAsync(userId);
2067         }
2068     }
2069 
2070     /**
2071      * Get the extras associated with a given widget instance.
2072      * <p>
2073      * The extras can be used to embed additional information about this widget to be accessed
2074      * by the associated widget's AppWidgetProvider.
2075      *
2076      * Typically called by a host process (e.g. Launcher) to determine if they need to update the
2077      * options of the widget.
2078      *
2079      * @see #updateAppWidgetOptions(String, int, Bundle)
2080      *
2081      * @param callingPackage The package that calls this method.
2082      * @param appWidgetId Id of the widget.
2083      * @return The options associated with the specified widget instance.
2084      */
2085     @Override
getAppWidgetOptions(String callingPackage, int appWidgetId)2086     public Bundle getAppWidgetOptions(String callingPackage, int appWidgetId) {
2087         final int userId = UserHandle.getCallingUserId();
2088 
2089         if (DEBUG) {
2090             Slog.i(TAG, "getAppWidgetOptions() " + userId);
2091         }
2092 
2093         // Make sure the package runs under the caller uid.
2094         mSecurityPolicy.enforceCallFromPackage(callingPackage);
2095 
2096         synchronized (mLock) {
2097             ensureGroupStateLoadedLocked(userId);
2098 
2099             // NOTE: The lookup is enforcing security across users by making
2100             // sure the caller can only access widgets it hosts or provides.
2101             Widget widget = lookupWidgetLocked(appWidgetId,
2102                     Binder.getCallingUid(), callingPackage);
2103 
2104             if (widget != null && widget.options != null) {
2105                 return cloneIfLocalBinder(widget.options);
2106             }
2107 
2108             return Bundle.EMPTY;
2109         }
2110     }
2111 
2112     /**
2113      * Updates the content of the widgets (as specified by appWidgetIds) using the provided
2114      * {@link RemoteViews}.
2115      *
2116      * Typically called by the provider's process. Either in response to the invocation of
2117      * {@link AppWidgetProvider#onUpdate} or upon receiving the
2118      * {@link AppWidgetManager#ACTION_APPWIDGET_UPDATE} broadcast.
2119      *
2120      * <p>
2121      * Note that the RemoteViews parameter will be cached by the AppWidgetService, and hence should
2122      * contain a complete representation of the widget. For performing partial widget updates, see
2123      * {@link #partiallyUpdateAppWidgetIds(String, int[], RemoteViews)}.
2124      *
2125      * @param callingPackage The package that calls this method.
2126      * @param appWidgetIds Ids of the widgets to be updated.
2127      * @param views The RemoteViews object containing the update.
2128      *
2129      * @see AppWidgetProvider#onUpdate(Context, AppWidgetManager, int[])
2130      * @see AppWidgetManager#ACTION_APPWIDGET_UPDATE
2131      * @see AppWidgetManager#updateAppWidget(int, RemoteViews)
2132      * @see AppWidgetManager#updateAppWidget(int[], RemoteViews)
2133      */
2134     @Override
updateAppWidgetIds(String callingPackage, int[] appWidgetIds, RemoteViews views)2135     public void updateAppWidgetIds(String callingPackage, int[] appWidgetIds,
2136             RemoteViews views) {
2137         if (DEBUG) {
2138             Slog.i(TAG, "updateAppWidgetIds() " + UserHandle.getCallingUserId());
2139         }
2140 
2141         updateAppWidgetIds(callingPackage, appWidgetIds, views, false);
2142     }
2143 
2144     /**
2145      * Perform an incremental update or command on the widget(s) specified by appWidgetIds.
2146      * <p>
2147      * This update  differs from {@link #updateAppWidgetIds(int[], RemoteViews)} in that the
2148      * RemoteViews object which is passed is understood to be an incomplete representation of the
2149      * widget, and hence does not replace the cached representation of the widget. As of API
2150      * level 17, the new properties set within the views objects will be appended to the cached
2151      * representation of the widget, and hence will persist.
2152      *
2153      * <p>
2154      * This method will be ignored if a widget has not received a full update via
2155      * {@link #updateAppWidget(int[], RemoteViews)}.
2156      *
2157      * @param callingPackage   The package that calls this method.
2158      * @param appWidgetIds     Ids of the widgets to be updated.
2159      * @param views            The RemoteViews object containing the incremental update / command.
2160      *
2161      * @see AppWidgetManager#partiallyUpdateAppWidget(int[], RemoteViews)
2162      * @see RemoteViews#setDisplayedChild(int, int)
2163      * @see RemoteViews#setScrollPosition(int, int)
2164      */
2165     @Override
partiallyUpdateAppWidgetIds(String callingPackage, int[] appWidgetIds, RemoteViews views)2166     public void partiallyUpdateAppWidgetIds(String callingPackage, int[] appWidgetIds,
2167             RemoteViews views) {
2168         if (DEBUG) {
2169             Slog.i(TAG, "partiallyUpdateAppWidgetIds() " + UserHandle.getCallingUserId());
2170         }
2171 
2172         updateAppWidgetIds(callingPackage, appWidgetIds, views, true);
2173     }
2174 
2175     /**
2176      * Callback function which marks specified providers as extended from AppWidgetProvider.
2177      *
2178      * This information is used to determine if the system can combine
2179      * {@link AppWidgetManager#ACTION_APPWIDGET_ENABLED} and
2180      * {@link AppWidgetManager#ACTION_APPWIDGET_UPDATE} into a single broadcast.
2181      *
2182      * Note: The system can only combine the two broadcasts if the provider is extended from
2183      * AppWidgetProvider. When they do, they are expected to override the
2184      * {@link AppWidgetProvider#onUpdate} callback function to provide updates, as opposed to
2185      * listening for {@link AppWidgetManager#ACTION_APPWIDGET_UPDATE} broadcasts directly.
2186      *
2187      * @see AppWidgetManager#ACTION_APPWIDGET_ENABLED
2188      * @see AppWidgetManager#ACTION_APPWIDGET_UPDATE
2189      * @see AppWidgetManager#ACTION_APPWIDGET_ENABLE_AND_UPDATE
2190      * @see AppWidgetProvider#onReceive(Context, Intent)
2191      * @see #sendEnableAndUpdateIntentLocked
2192      */
2193     @Override
notifyProviderInheritance(@ullable final ComponentName[] componentNames)2194     public void notifyProviderInheritance(@Nullable final ComponentName[] componentNames) {
2195         final int userId = UserHandle.getCallingUserId();
2196         if (DEBUG) {
2197             Slog.i(TAG, "notifyProviderInheritance() " + userId);
2198         }
2199 
2200         if (componentNames == null) {
2201             return;
2202         }
2203 
2204         for (ComponentName componentName : componentNames) {
2205             if (componentName == null) {
2206                 return;
2207             }
2208             mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
2209         }
2210         synchronized (mLock) {
2211             ensureGroupStateLoadedLocked(userId);
2212 
2213             for (ComponentName componentName : componentNames) {
2214                 final ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
2215                 final Provider provider = lookupProviderLocked(providerId);
2216 
2217                 if (provider == null || provider.info == null) {
2218                     return;
2219                 }
2220 
2221                 provider.info.isExtendedFromAppWidgetProvider = true;
2222             }
2223             saveGroupStateAsync(userId);
2224         }
2225     }
2226 
2227     /**
2228      * Notifies the specified collection view in all the specified AppWidget instances
2229      * to invalidate their data.
2230      *
2231      * This method is effectively deprecated since
2232      * {@link RemoteViews#setRemoteAdapter(int, Intent)} has been deprecated.
2233      *
2234      * @see AppWidgetManager#notifyAppWidgetViewDataChanged(int[], int)
2235      */
2236     @Override
notifyAppWidgetViewDataChanged(String callingPackage, int[] appWidgetIds, int viewId)2237     public void notifyAppWidgetViewDataChanged(String callingPackage, int[] appWidgetIds,
2238             int viewId) {
2239         final int userId = UserHandle.getCallingUserId();
2240 
2241         if (DEBUG) {
2242             Slog.i(TAG, "notifyAppWidgetViewDataChanged() " + userId);
2243         }
2244 
2245         // Make sure the package runs under the caller uid.
2246         mSecurityPolicy.enforceCallFromPackage(callingPackage);
2247 
2248         if (appWidgetIds == null || appWidgetIds.length == 0) {
2249             return;
2250         }
2251 
2252         synchronized (mLock) {
2253             ensureGroupStateLoadedLocked(userId);
2254 
2255             final int N = appWidgetIds.length;
2256             for (int i = 0; i < N; i++) {
2257                 final int appWidgetId = appWidgetIds[i];
2258 
2259                 // NOTE: The lookup is enforcing security across users by making
2260                 // sure the caller can only access widgets it hosts or provides.
2261                 Widget widget = lookupWidgetLocked(appWidgetId,
2262                         Binder.getCallingUid(), callingPackage);
2263 
2264                 if (widget != null) {
2265                     scheduleNotifyAppWidgetViewDataChanged(widget, viewId);
2266                 }
2267             }
2268         }
2269     }
2270 
2271     /**
2272      * Updates the content of all widgets associated with given provider (as specified by
2273      * componentName) using the provided {@link RemoteViews}.
2274      *
2275      * Typically called by the provider's process when there's an update that needs to be supplied
2276      * to all instances of the widgets.
2277      *
2278      * @param componentName The component name of the provider.
2279      * @param views The RemoteViews object containing the update.
2280      *
2281      * @see AppWidgetManager#updateAppWidget(ComponentName, RemoteViews)
2282      */
2283     @Override
updateAppWidgetProvider(ComponentName componentName, RemoteViews views)2284     public void updateAppWidgetProvider(ComponentName componentName, RemoteViews views) {
2285         final int userId = UserHandle.getCallingUserId();
2286 
2287         if (DEBUG) {
2288             Slog.i(TAG, "updateAppWidgetProvider() " + userId);
2289         }
2290 
2291         // Make sure the package runs under the caller uid.
2292         mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
2293 
2294         synchronized (mLock) {
2295             ensureGroupStateLoadedLocked(userId);
2296 
2297             // NOTE: The lookup is enforcing security across users by making
2298             // sure the caller can access only its providers.
2299             ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
2300             Provider provider = lookupProviderLocked(providerId);
2301 
2302             if (provider == null) {
2303                 Slog.w(TAG, "Provider doesn't exist " + providerId);
2304                 return;
2305             }
2306 
2307             ArrayList<Widget> instances = provider.widgets;
2308             final int N = instances.size();
2309             for (int i = 0; i < N; i++) {
2310                 Widget widget = instances.get(i);
2311                 updateAppWidgetInstanceLocked(widget, views, false);
2312             }
2313         }
2314     }
2315 
2316     /**
2317      * Updates the info for the supplied AppWidget provider. Apps can use this to change the default
2318      * behavior of the widget based on the state of the app (e.g., if the user is logged in
2319      * or not). Calling this API completely replaces the previous definition.
2320      *
2321      * <p>
2322      * The manifest entry of the provider should contain an additional meta-data tag similar to
2323      * {@link AppWidgetManager#META_DATA_APPWIDGET_PROVIDER} which should point to any alternative
2324      * definitions for the provider.
2325      *
2326      * <p>
2327      * This is persisted across device reboots and app updates. If this meta-data key is not
2328      * present in the manifest entry, the info reverts to default.
2329      *
2330      * @param provider {@link ComponentName} for the {@link
2331      *    android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget.
2332      * @param metaDataKey key for the meta-data tag pointing to the new provider info. Use null
2333      *    to reset any previously set info.
2334      *
2335      * @see AppWidgetManager#updateAppWidgetProviderInfo(ComponentName, String)
2336      */
2337     @Override
updateAppWidgetProviderInfo(ComponentName componentName, String metadataKey)2338     public void updateAppWidgetProviderInfo(ComponentName componentName, String metadataKey) {
2339         final int userId = UserHandle.getCallingUserId();
2340         if (DEBUG) {
2341             Slog.i(TAG, "updateAppWidgetProvider() " + userId);
2342         }
2343 
2344         // Make sure the package runs under the caller uid.
2345         mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
2346 
2347         synchronized (mLock) {
2348             ensureGroupStateLoadedLocked(userId);
2349 
2350             // NOTE: The lookup is enforcing security across users by making
2351             // sure the caller can access only its providers.
2352             ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
2353             Provider provider = lookupProviderLocked(providerId);
2354             if (provider == null) {
2355                 throw new IllegalArgumentException(
2356                         componentName + " is not a valid AppWidget provider");
2357             }
2358             if (Objects.equals(provider.infoTag, metadataKey)) {
2359                 // No change
2360                 return;
2361             }
2362 
2363             String keyToUse = metadataKey == null
2364                     ? AppWidgetManager.META_DATA_APPWIDGET_PROVIDER : metadataKey;
2365             AppWidgetProviderInfo info = parseAppWidgetProviderInfo(mContext, providerId,
2366                     provider.getPartialInfoLocked().providerInfo, keyToUse);
2367             if (info == null) {
2368                 throw new IllegalArgumentException("Unable to parse " + keyToUse
2369                         + " meta-data to a valid AppWidget provider");
2370             }
2371 
2372             provider.setInfoLocked(info);
2373             provider.infoTag = metadataKey;
2374 
2375             // Update all widgets for this provider
2376             final int N = provider.widgets.size();
2377             for (int i = 0; i < N; i++) {
2378                 Widget widget = provider.widgets.get(i);
2379                 scheduleNotifyProviderChangedLocked(widget);
2380                 updateAppWidgetInstanceLocked(widget, widget.views, false /* isPartialUpdate */);
2381             }
2382 
2383             saveGroupStateAsync(userId);
2384             scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
2385         }
2386     }
2387 
2388     /**
2389      * Returns true if the default launcher app on the device (the one that currently
2390      * holds the android.app.role.HOME role) can support pinning widgets
2391      * (typically means adding widgets into home screen).
2392      */
2393     @Override
isRequestPinAppWidgetSupported()2394     public boolean isRequestPinAppWidgetSupported() {
2395         synchronized (mLock) {
2396             if (mSecurityPolicy.isCallerInstantAppLocked()) {
2397                 Slog.w(TAG, "Instant uid " + Binder.getCallingUid()
2398                         + " query information about app widgets");
2399                 return false;
2400             }
2401         }
2402         return LocalServices.getService(ShortcutServiceInternal.class)
2403                 .isRequestPinItemSupported(UserHandle.getCallingUserId(),
2404                         LauncherApps.PinItemRequest.REQUEST_TYPE_APPWIDGET);
2405     }
2406 
2407     /**
2408      * Request to pin an app widget on the current launcher. It's up to the launcher to accept this
2409      * request (optionally showing a user confirmation). If the request is accepted, the caller will
2410      * get a confirmation with extra {@link #EXTRA_APPWIDGET_ID}.
2411      *
2412      * <p>When a request is denied by the user, the caller app will not get any response.
2413      *
2414      * <p>Only apps with a foreground activity or a foreground service can call it.  Otherwise
2415      * it'll throw {@link IllegalStateException}.
2416      *
2417      * <p>It's up to the launcher how to handle previous pending requests when the same package
2418      * calls this API multiple times in a row.  It may ignore the previous requests,
2419      * for example.
2420      *
2421      * <p>Launcher will not show the configuration activity associated with the provider in this
2422      * case. The app could either show the configuration activity as a response to the callback,
2423      * or show if before calling the API (various configurations can be encapsulated in
2424      * {@code successCallback} to avoid persisting them before the widgetId is known).
2425      *
2426      * @param provider The {@link ComponentName} for the {@link
2427      *    android.content.BroadcastReceiver BroadcastReceiver} provider for your AppWidget.
2428      * @param extras If not null, this is passed to the launcher app. For eg {@link
2429      *    #EXTRA_APPWIDGET_PREVIEW} can be used for a custom preview.
2430      * @param successCallback If not null, this intent will be sent when the widget is created.
2431      *
2432      * @return {@code TRUE} if the launcher supports this feature. Note the API will return without
2433      *    waiting for the user to respond, so getting {@code TRUE} from this API does *not* mean
2434      *    the shortcut is pinned. {@code FALSE} if the launcher doesn't support this feature or if
2435      *    calling app belongs to a user-profile with items restricted on home screen.
2436      *
2437      * @see android.content.pm.ShortcutManager#isRequestPinShortcutSupported()
2438      * @see android.content.pm.ShortcutManager#requestPinShortcut(ShortcutInfo, IntentSender)
2439      * @see AppWidgetManager#isRequestPinAppWidgetSupported()
2440      * @see AppWidgetManager#requestPinAppWidget(ComponentName, Bundle, PendingIntent)
2441      *
2442      * @throws IllegalStateException The caller doesn't have a foreground activity or a foreground
2443      * service or when the user is locked.
2444      */
2445     @Override
requestPinAppWidget(String callingPackage, ComponentName componentName, Bundle extras, IntentSender resultSender)2446     public boolean requestPinAppWidget(String callingPackage, ComponentName componentName,
2447             Bundle extras, IntentSender resultSender) {
2448         final int callingUid = Binder.getCallingUid();
2449         final int userId = UserHandle.getUserId(callingUid);
2450 
2451         if (DEBUG) {
2452             Slog.i(TAG, "requestPinAppWidget() " + userId);
2453         }
2454 
2455         final AppWidgetProviderInfo info;
2456 
2457         synchronized (mLock) {
2458             ensureGroupStateLoadedLocked(userId);
2459 
2460             final String pkg = componentName.getPackageName();
2461             final ProviderId id;
2462             if (!mPackageManagerInternal.isSameApp(pkg, callingUid, userId)) {
2463                 // If the calling process is requesting to pin appwidgets from another process,
2464                 // check if the calling process has the necessary permission.
2465                 if (!injectHasAccessWidgetsPermission(Binder.getCallingPid(), callingUid)) {
2466                     return false;
2467                 }
2468                 id = new ProviderId(mPackageManagerInternal.getPackageUid(
2469                         pkg, 0 /* flags */, userId), componentName);
2470             } else {
2471                 id = new ProviderId(callingUid, componentName);
2472             }
2473             // Look for the widget associated with the caller.
2474             Provider provider = lookupProviderLocked(id);
2475             if (provider == null || provider.zombie) {
2476                 return false;
2477             }
2478             info = provider.getInfoLocked(mContext);
2479             if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) == 0) {
2480                 return false;
2481             }
2482         }
2483 
2484         return LocalServices.getService(ShortcutServiceInternal.class)
2485                 .requestPinAppWidget(callingPackage, info, extras, resultSender, userId);
2486     }
2487 
2488     /**
2489      * Returns true if the caller has the proper permission to access app widgets.
2490      */
injectHasAccessWidgetsPermission(int callingPid, int callingUid)2491     private boolean injectHasAccessWidgetsPermission(int callingPid, int callingUid) {
2492         return mContext.checkPermission(Manifest.permission.CLEAR_APP_USER_DATA,
2493                 callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
2494     }
2495 
2496     /**
2497      * Gets the AppWidget providers for the given user profile. User profile can only
2498      * be the current user or a profile of the current user. For example, the current
2499      * user may have a corporate profile. In this case the parent user profile has a
2500      * child profile, the corporate one.
2501      *
2502      * @param categoryFilter Will only return providers which register as any of the specified
2503      *        specified categories. See {@link AppWidgetProviderInfo#widgetCategory}.
2504      * @param profile A profile of the current user which to be queried. The user
2505      *        is itself also a profile. If null, the providers only for the current user
2506      *        are returned.
2507      * @param packageName If specified, will only return providers from the given package.
2508      * @return The installed providers.
2509      *
2510      * @see android.os.Process#myUserHandle()
2511      * @see android.os.UserManager#getUserProfiles()
2512      * @see AppWidgetManager#getInstalledProvidersForProfile(int, UserHandle, String)
2513      */
2514     @Override
getInstalledProvidersForProfile(int categoryFilter, int profileId, String packageName)2515     public ParceledListSlice<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter,
2516             int profileId, String packageName) {
2517         final int userId = UserHandle.getCallingUserId();
2518         final int callingUid = Binder.getCallingUid();
2519 
2520         if (DEBUG) {
2521             Slog.i(TAG, "getInstalledProvidersForProfiles() " + userId);
2522         }
2523 
2524         // Ensure the profile is in the group and enabled.
2525         if (!mSecurityPolicy.isEnabledGroupProfile(profileId)) {
2526             return null;
2527         }
2528 
2529         synchronized (mLock) {
2530             if (mSecurityPolicy.isCallerInstantAppLocked()) {
2531                 Slog.w(TAG, "Instant uid " + callingUid
2532                         + " cannot access widget providers");
2533                 return ParceledListSlice.emptyList();
2534             }
2535 
2536             ensureGroupStateLoadedLocked(userId);
2537 
2538             ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>();
2539 
2540             final int providerCount = mProviders.size();
2541             for (int i = 0; i < providerCount; i++) {
2542                 Provider provider = mProviders.get(i);
2543                 final String providerPackageName = provider.id.componentName.getPackageName();
2544 
2545                 // Ignore an invalid provider or one that isn't in the given package, if any.
2546                 boolean inPackage = packageName == null || providerPackageName.equals(packageName);
2547                 if (provider.zombie || !inPackage) {
2548                     continue;
2549                 }
2550 
2551                 // Ignore the ones not matching the filter.
2552                 AppWidgetProviderInfo info = provider.getInfoLocked(mContext);
2553                 if ((info.widgetCategory & categoryFilter) == 0) {
2554                     continue;
2555                 }
2556 
2557                 // Add providers only for the requested profile that are allowlisted.
2558                 final int providerProfileId = info.getProfile().getIdentifier();
2559                 if (providerProfileId == profileId
2560                         && mSecurityPolicy.canAccessProvider(
2561                         providerPackageName, providerProfileId)
2562                         && !mPackageManagerInternal.filterAppAccess(providerPackageName, callingUid,
2563                         profileId)) {
2564                     result.add(cloneIfLocalBinder(info));
2565                 }
2566             }
2567 
2568             return new ParceledListSlice<AppWidgetProviderInfo>(result);
2569         }
2570     }
2571 
2572     /**
2573      * Updates the content of the widgets (as specified by appWidgetIds) using the provided
2574      * {@link RemoteViews}.
2575      *
2576      * If performing a partial update, the given RemoteViews object is merged into existing
2577      * RemoteViews object.
2578      *
2579      * Fails silently if appWidgetIds is null or empty, or cannot found a widget with the given
2580      * appWidgetId.
2581      *
2582      * @param callingPackage The package that calls this method.
2583      * @param appWidgetIds Ids of the widgets to be updated.
2584      * @param views The RemoteViews object containing the update.
2585      * @param partially Whether it was a partial update.
2586      *
2587      * @see AppWidgetProvider#onUpdate(Context, AppWidgetManager, int[])
2588      * @see AppWidgetManager#ACTION_APPWIDGET_UPDATE
2589      * @see AppWidgetManager#updateAppWidget(int, RemoteViews)
2590      * @see AppWidgetManager#updateAppWidget(int[], RemoteViews)
2591      */
updateAppWidgetIds(String callingPackage, int[] appWidgetIds, RemoteViews views, boolean partially)2592     private void updateAppWidgetIds(String callingPackage, int[] appWidgetIds,
2593             RemoteViews views, boolean partially) {
2594         final int userId = UserHandle.getCallingUserId();
2595 
2596         if (appWidgetIds == null || appWidgetIds.length == 0) {
2597             return;
2598         }
2599 
2600         // Make sure the package runs under the caller uid.
2601         mSecurityPolicy.enforceCallFromPackage(callingPackage);
2602         // Make sure RemoteViews do not contain URIs that the caller cannot access.
2603         checkRemoteViewsUris(views);
2604         synchronized (mLock) {
2605             ensureGroupStateLoadedLocked(userId);
2606 
2607             final int N = appWidgetIds.length;
2608             for (int i = 0; i < N; i++) {
2609                 final int appWidgetId = appWidgetIds[i];
2610 
2611                 // NOTE: The lookup is enforcing security across users by making
2612                 // sure the caller can only access widgets it hosts or provides.
2613                 Widget widget = lookupWidgetLocked(appWidgetId,
2614                         Binder.getCallingUid(), callingPackage);
2615 
2616                 if (widget != null) {
2617                     updateAppWidgetInstanceLocked(widget, views, partially);
2618                 }
2619             }
2620         }
2621     }
2622 
2623     /**
2624      * Checks that all of the Uris in the given RemoteViews are accessible to the caller.
2625      */
checkRemoteViewsUris(RemoteViews views)2626     private void checkRemoteViewsUris(RemoteViews views) {
2627         UriGrantsManagerInternal uriGrantsManager = LocalServices.getService(
2628                 UriGrantsManagerInternal.class);
2629         int callingUid = Binder.getCallingUid();
2630         int callingUser = UserHandle.getCallingUserId();
2631         views.visitUris(uri -> {
2632             switch (uri.getScheme()) {
2633                 // Check that content:// URIs are accessible to the caller.
2634                 case ContentResolver.SCHEME_CONTENT:
2635                     boolean canAccessUri = uriGrantsManager.checkUriPermission(
2636                             GrantUri.resolve(callingUser, uri,
2637                                     Intent.FLAG_GRANT_READ_URI_PERMISSION), callingUid,
2638                             Intent.FLAG_GRANT_READ_URI_PERMISSION,
2639                             /* isFullAccessForContentUri= */ true);
2640                     if (!canAccessUri) {
2641                         throw new SecurityException(
2642                                 "Provider uid " + callingUid + " cannot access URI " + uri);
2643                     }
2644                     break;
2645                 // android.resource:// URIs are always allowed.
2646                 case ContentResolver.SCHEME_ANDROID_RESOURCE:
2647                     break;
2648                 // file:// and any other schemes are disallowed.
2649                 case ContentResolver.SCHEME_FILE:
2650                 default:
2651                     throw new SecurityException("Disallowed URI " + uri + " in RemoteViews.");
2652             }
2653         });
2654     }
2655 
2656     /**
2657      * Increment the counter of widget ids and return the new id.
2658      *
2659      * Typically called by {@link #allocateAppWidgetId} when a instance of widget is created,
2660      * either as a result of being pinned by launcher or added during a restore.
2661      *
2662      * Note: A widget id is a monotonically increasing integer that uniquely identifies the widget
2663      * instance.
2664      *
2665      * TODO: Revisit this method and determine whether we need to alter the widget id during
2666      *       the restore since widget id mismatch potentially leads to some issues in the past.
2667      */
incrementAndGetAppWidgetIdLocked(int userId)2668     private int incrementAndGetAppWidgetIdLocked(int userId) {
2669         final int appWidgetId = peekNextAppWidgetIdLocked(userId) + 1;
2670         mNextAppWidgetIds.put(userId, appWidgetId);
2671         return appWidgetId;
2672     }
2673 
2674     /**
2675      * Called by {@link #readProfileStateFromFileLocked} when widgets/providers/hosts are loaded
2676      * from disk, which ensures mNextAppWidgetIds is larger than any existing widget id for given
2677      * user.
2678      */
setMinAppWidgetIdLocked(int userId, int minWidgetId)2679     private void setMinAppWidgetIdLocked(int userId, int minWidgetId) {
2680         final int nextAppWidgetId = peekNextAppWidgetIdLocked(userId);
2681         if (nextAppWidgetId < minWidgetId) {
2682             mNextAppWidgetIds.put(userId, minWidgetId);
2683         }
2684     }
2685 
peekNextAppWidgetIdLocked(int userId)2686     private int peekNextAppWidgetIdLocked(int userId) {
2687         if (mNextAppWidgetIds.indexOfKey(userId) < 0) {
2688             return AppWidgetManager.INVALID_APPWIDGET_ID + 1;
2689         } else {
2690             return mNextAppWidgetIds.get(userId);
2691         }
2692     }
2693 
lookupOrAddHostLocked(HostId id)2694     private Host lookupOrAddHostLocked(HostId id) {
2695         Host host = lookupHostLocked(id);
2696         if (host != null) {
2697             return host;
2698         }
2699         ensureHostCountBeforeAddLocked(id);
2700         host = new Host();
2701         host.id = id;
2702         mHosts.add(host);
2703 
2704         return host;
2705     }
2706 
2707     /**
2708      * Ensures that the number of hosts for a package is less than the maximum number of hosts per
2709      * package. If the number of hosts is greater than the maximum number of hosts per package, then
2710      * removes the oldest host.
2711      */
ensureHostCountBeforeAddLocked(@onNull final HostId hostId)2712     private void ensureHostCountBeforeAddLocked(@NonNull final HostId hostId) {
2713         final List<Host> hosts = new ArrayList<>();
2714         for (Host host : mHosts) {
2715             if (host.id.uid == hostId.uid
2716                     && host.id.packageName.equals(hostId.packageName)) {
2717                 hosts.add(host);
2718             }
2719         }
2720         while (hosts.size() >= MAX_NUMBER_OF_HOSTS_PER_PACKAGE) {
2721             deleteHostLocked(hosts.remove(0));
2722         }
2723     }
2724 
deleteHostLocked(Host host)2725     private void deleteHostLocked(Host host) {
2726         if (DEBUG) {
2727             Slog.i(TAG, "deleteHostLocked() " + host);
2728         }
2729         final int N = host.widgets.size();
2730         for (int i = N - 1; i >= 0; i--) {
2731             Widget widget = host.widgets.remove(i);
2732             deleteAppWidgetLocked(widget);
2733         }
2734         mHosts.remove(host);
2735 
2736         // it's gone or going away, abruptly drop the callback connection
2737         host.callbacks = null;
2738     }
2739 
deleteAppWidgetLocked(Widget widget)2740     private void deleteAppWidgetLocked(Widget widget) {
2741         if (DEBUG) {
2742             Slog.i(TAG, "deleteAppWidgetLocked() " + widget);
2743         }
2744         // We first unbind all services that are bound to this id
2745         // Check if we need to destroy any services (if no other app widgets are
2746         // referencing the same service)
2747         decrementAppWidgetServiceRefCount(widget);
2748 
2749         Host host = widget.host;
2750         host.widgets.remove(widget);
2751         pruneHostLocked(host);
2752 
2753         removeWidgetLocked(widget);
2754 
2755         Provider provider = widget.provider;
2756         if (provider != null) {
2757             provider.widgets.remove(widget);
2758             if (!provider.zombie) {
2759                 // If the package is not stopped, send the broadcast saying that this appWidgetId
2760                 // has been deleted. Otherwise, save the ID and send the broadcast when the package
2761                 // is unstopped.
2762                 if (!provider.maskedByStoppedPackage) {
2763                     sendDeletedIntentLocked(widget);
2764                 } else {
2765                     provider.pendingDeletedWidgetIds.add(widget.appWidgetId);
2766                 }
2767 
2768                 if (provider.widgets.isEmpty()) {
2769                     // cancel the future updates
2770                     cancelBroadcastsLocked(provider);
2771 
2772                     // send the broadcast saying that the provider is not in use any more
2773                     if (!provider.maskedByStoppedPackage) {
2774                         sendDisabledIntentLocked(provider);
2775                     }
2776                 }
2777             }
2778         }
2779     }
2780 
cancelBroadcastsLocked(Provider provider)2781     private void cancelBroadcastsLocked(Provider provider) {
2782         if (DEBUG) {
2783             Slog.i(TAG, "cancelBroadcastsLocked() for " + provider);
2784         }
2785         if (provider.broadcast != null) {
2786             final PendingIntent broadcast = provider.broadcast;
2787             Runnable cancelRunnable = () -> {
2788                 mAlarmManager.cancel(broadcast);
2789                 broadcast.cancel();
2790             };
2791             if (removeAppWidgetServiceIoFromCriticalPath()) {
2792                 mAlarmHandler.post(cancelRunnable);
2793             } else {
2794                 mSaveStateHandler.post(cancelRunnable);
2795             }
2796             provider.broadcast = null;
2797         }
2798     }
2799 
2800     // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
destroyRemoteViewsService(final Intent intent, Widget widget)2801     private void destroyRemoteViewsService(final Intent intent, Widget widget) {
2802         final ServiceConnection conn = new ServiceConnection() {
2803             @Override
2804             public void onServiceConnected(ComponentName name, IBinder service) {
2805                 final IRemoteViewsFactory cb = IRemoteViewsFactory.Stub.asInterface(service);
2806                 try {
2807                     cb.onDestroy(intent);
2808                 } catch (RemoteException re) {
2809                     Slog.e(TAG, "Error calling remove view factory", re);
2810                 }
2811                 mContext.unbindService(this);
2812             }
2813 
2814             @Override
2815             public void onNullBinding(ComponentName name) {
2816                 mContext.unbindService(this);
2817             }
2818 
2819             @Override
2820             public void onServiceDisconnected(ComponentName name) {
2821                 // Do nothing
2822             }
2823         };
2824 
2825         // Bind to the service and remove the static intent->factory mapping in the
2826         // RemoteViewsService.
2827         final long token = Binder.clearCallingIdentity();
2828         try {
2829             mContext.bindServiceAsUser(intent, conn,
2830                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
2831                     widget.provider.id.getProfile());
2832         } finally {
2833             Binder.restoreCallingIdentity(token);
2834         }
2835     }
2836 
2837     // Adds to the ref-count for a given RemoteViewsService intent
incrementAppWidgetServiceRefCount(int appWidgetId, Pair<Integer, FilterComparison> serviceId)2838     private void incrementAppWidgetServiceRefCount(int appWidgetId,
2839             Pair<Integer, FilterComparison> serviceId) {
2840         final HashSet<Integer> appWidgetIds;
2841         if (mRemoteViewsServicesAppWidgets.containsKey(serviceId)) {
2842             appWidgetIds = mRemoteViewsServicesAppWidgets.get(serviceId);
2843         } else {
2844             appWidgetIds = new HashSet<>();
2845             mRemoteViewsServicesAppWidgets.put(serviceId, appWidgetIds);
2846         }
2847         appWidgetIds.add(appWidgetId);
2848     }
2849 
2850     // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
2851     // the ref-count reaches zero.
decrementAppWidgetServiceRefCount(Widget widget)2852     private void decrementAppWidgetServiceRefCount(Widget widget) {
2853         Iterator<Pair<Integer, FilterComparison>> it = mRemoteViewsServicesAppWidgets
2854                 .keySet().iterator();
2855         while (it.hasNext()) {
2856             final Pair<Integer, FilterComparison> key = it.next();
2857             final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
2858             if (ids.remove(widget.appWidgetId)) {
2859                 // If we have removed the last app widget referencing this service, then we
2860                 // should destroy it and remove it from this set. This is skipped for widgets whose
2861                 // provider is in a stopped package, to avoid waking up the package.
2862                 if (ids.isEmpty() && !widget.provider.maskedByStoppedPackage) {
2863                     destroyRemoteViewsService(key.second.getIntent(), widget);
2864                     it.remove();
2865                 }
2866             }
2867         }
2868     }
2869 
saveGroupStateAsync(int groupId)2870     private void saveGroupStateAsync(int groupId) {
2871         if (removeAppWidgetServiceIoFromCriticalPath()) {
2872             mSaveStateHandler.removeMessages(groupId);
2873             mSaveStateHandler.sendEmptyMessage(groupId);
2874         } else {
2875             mSaveStateHandler.post(new SaveStateRunnable(groupId));
2876         }
2877     }
2878 
updateAppWidgetInstanceLocked(Widget widget, RemoteViews views, boolean isPartialUpdate)2879     private void updateAppWidgetInstanceLocked(Widget widget, RemoteViews views,
2880             boolean isPartialUpdate) {
2881         if (widget != null && widget.provider != null
2882                 && !widget.provider.zombie && !widget.host.zombie) {
2883 
2884             if (isPartialUpdate && widget.views != null) {
2885                 // For a partial update, we merge the new RemoteViews with the old.
2886                 widget.views.mergeRemoteViews(views);
2887             } else {
2888                 // For a full update we replace the RemoteViews completely.
2889                 widget.views = views;
2890             }
2891             long memoryUsage;
2892             if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) &&
2893                     (widget.views != null) &&
2894                     ((memoryUsage = widget.views.estimateMemoryUsage()) > mMaxWidgetBitmapMemory)) {
2895                 widget.views = null;
2896                 throw new IllegalArgumentException("RemoteViews for widget update exceeds"
2897                         + " maximum bitmap memory usage (used: " + memoryUsage
2898                         + ", max: " + mMaxWidgetBitmapMemory + ")");
2899             }
2900             scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
2901         }
2902     }
scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId)2903     private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) {
2904         if (viewId == ID_VIEWS_UPDATE || viewId == ID_PROVIDER_CHANGED) {
2905             // A view id should never collide with these constants but a developer can call this
2906             // method with a wrong id. In that case, ignore the call.
2907             return;
2908         }
2909         long requestId = UPDATE_COUNTER.incrementAndGet();
2910         if (widget != null) {
2911             widget.updateSequenceNos.put(viewId, requestId);
2912         }
2913         if (widget == null || widget.host == null || widget.host.zombie
2914                 || widget.host.callbacks == null || widget.provider == null
2915                 || widget.provider.zombie) {
2916             return;
2917         }
2918 
2919         SomeArgs args = SomeArgs.obtain();
2920         args.arg1 = widget.host;
2921         args.arg2 = widget.host.callbacks;
2922         args.arg3 = requestId;
2923         args.argi1 = widget.appWidgetId;
2924         args.argi2 = viewId;
2925 
2926         mCallbackHandler.obtainMessage(
2927                 CallbackHandler.MSG_NOTIFY_VIEW_DATA_CHANGED,
2928                 args).sendToTarget();
2929     }
2930 
2931 
handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks, int appWidgetId, int viewId, long requestId)2932     private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
2933             int appWidgetId, int viewId, long requestId) {
2934         try {
2935             Slog.d(TAG, "Trying to notify widget view data changed");
2936             callbacks.viewDataChanged(appWidgetId, viewId);
2937             host.lastWidgetUpdateSequenceNo = requestId;
2938         } catch (RemoteException re) {
2939             // It failed; remove the callback. No need to prune because
2940             // we know that this host is still referenced by this instance.
2941             callbacks = null;
2942         }
2943 
2944         // If the host is unavailable, then we call the associated
2945         // RemoteViewsFactory.onDataSetChanged() directly
2946         synchronized (mLock) {
2947             if (callbacks == null) {
2948                 host.callbacks = null;
2949 
2950                 Set<Pair<Integer, FilterComparison>> keys = mRemoteViewsServicesAppWidgets.keySet();
2951                 for (Pair<Integer, FilterComparison> key : keys) {
2952                     if (mRemoteViewsServicesAppWidgets.get(key).contains(appWidgetId)) {
2953                         final ServiceConnection connection = new ServiceConnection() {
2954                             @Override
2955                             public void onServiceConnected(ComponentName name, IBinder service) {
2956                                 IRemoteViewsFactory cb = IRemoteViewsFactory.Stub
2957                                         .asInterface(service);
2958                                 try {
2959                                     cb.onDataSetChangedAsync();
2960                                 } catch (RemoteException e) {
2961                                     Slog.e(TAG, "Error calling onDataSetChangedAsync()", e);
2962                                 }
2963                                 mContext.unbindService(this);
2964                             }
2965 
2966                             @Override
2967                             public void onNullBinding(ComponentName name) {
2968                                 mContext.unbindService(this);
2969                             }
2970 
2971                             @Override
2972                             public void onServiceDisconnected(android.content.ComponentName name) {
2973                                 // Do nothing
2974                             }
2975                         };
2976 
2977                         final int userId = UserHandle.getUserId(key.first);
2978                         Intent intent = key.second.getIntent();
2979 
2980                         // Bind to the service and call onDataSetChanged()
2981                         bindService(intent, connection, new UserHandle(userId));
2982                     }
2983                 }
2984             }
2985         }
2986     }
2987 
scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews)2988     private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
2989         long requestId = UPDATE_COUNTER.incrementAndGet();
2990         if (widget != null) {
2991             if (widget.trackingUpdate) {
2992                 // This is the first update, end the trace
2993                 widget.trackingUpdate = false;
2994                 Log.i(TAG, "Widget update received " + widget.toString());
2995                 Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
2996                         "appwidget update-intent " + widget.provider.id.toString(),
2997                         widget.appWidgetId);
2998             }
2999             widget.updateSequenceNos.put(ID_VIEWS_UPDATE, requestId);
3000         }
3001         if (widget == null || widget.provider == null || widget.provider.zombie
3002                 || widget.host.callbacks == null || widget.host.zombie) {
3003             return;
3004         }
3005         if (updateViews != null) {
3006             updateViews = new RemoteViews(updateViews);
3007             updateViews.setProviderInstanceId(requestId);
3008         }
3009 
3010         SomeArgs args = SomeArgs.obtain();
3011         args.arg1 = widget.host;
3012         args.arg2 = widget.host.callbacks;
3013         args.arg3 = updateViews;
3014         args.arg4 = requestId;
3015         args.argi1 = widget.appWidgetId;
3016 
3017         if (updateViews != null && updateViews.isLegacyListRemoteViews()) {
3018             mCallbackHandler.obtainMessage(
3019                     CallbackHandler.MSG_NOTIFY_UPDATE_APP_WIDGET_DEFERRED,
3020                     args).sendToTarget();
3021             return;
3022         }
3023 
3024         mCallbackHandler.obtainMessage(
3025                 CallbackHandler.MSG_NOTIFY_UPDATE_APP_WIDGET,
3026                 args).sendToTarget();
3027     }
3028 
handleNotifyUpdateAppWidgetDeferred(Host host, IAppWidgetHost callbacks, int appWidgetId, long requestId)3029     private void handleNotifyUpdateAppWidgetDeferred(Host host, IAppWidgetHost callbacks,
3030             int appWidgetId, long requestId) {
3031         try {
3032             Slog.d(TAG, "Trying to notify widget update deferred for id: " + appWidgetId);
3033             callbacks.updateAppWidgetDeferred(appWidgetId);
3034             host.lastWidgetUpdateSequenceNo = requestId;
3035         } catch (RemoteException re) {
3036             synchronized (mLock) {
3037                 Slog.e(TAG, "Widget host dead: " + host.id, re);
3038                 host.callbacks = null;
3039             }
3040         }
3041     }
3042 
handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks, int appWidgetId, RemoteViews views, long requestId)3043     private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
3044             int appWidgetId, RemoteViews views, long requestId) {
3045         try {
3046             Slog.d(TAG, "Trying to notify widget update for package "
3047                     + (views == null ? "null" : views.getPackage())
3048                     + " with widget id: " + appWidgetId);
3049             callbacks.updateAppWidget(appWidgetId, views);
3050             host.lastWidgetUpdateSequenceNo = requestId;
3051         } catch (RemoteException re) {
3052             synchronized (mLock) {
3053                 Slog.e(TAG, "Widget host dead: " + host.id, re);
3054                 host.callbacks = null;
3055             }
3056         }
3057     }
3058 
3059     @GuardedBy("mLock")
scheduleNotifyProviderChangedLocked(Widget widget)3060     private void scheduleNotifyProviderChangedLocked(Widget widget) {
3061         long requestId = UPDATE_COUNTER.incrementAndGet();
3062         if (widget != null) {
3063             // When the provider changes, reset everything else.
3064             widget.updateSequenceNos.clear();
3065             widget.updateSequenceNos.append(ID_PROVIDER_CHANGED, requestId);
3066         }
3067         if (widget == null || widget.provider == null || widget.provider.zombie
3068                 || widget.host.callbacks == null || widget.host.zombie) {
3069             return;
3070         }
3071 
3072         SomeArgs args = SomeArgs.obtain();
3073         args.arg1 = widget.host;
3074         args.arg2 = widget.host.callbacks;
3075         args.arg3 = widget.provider.getInfoLocked(mContext);
3076         args.arg4 = requestId;
3077         args.argi1 = widget.appWidgetId;
3078 
3079         mCallbackHandler.obtainMessage(
3080                 CallbackHandler.MSG_NOTIFY_PROVIDER_CHANGED,
3081                 args).sendToTarget();
3082     }
3083 
handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks, int appWidgetId, AppWidgetProviderInfo info, long requestId)3084     private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
3085             int appWidgetId, AppWidgetProviderInfo info, long requestId) {
3086         try {
3087             Slog.d(TAG, "Trying to notify provider update");
3088             callbacks.providerChanged(appWidgetId, info);
3089             host.lastWidgetUpdateSequenceNo = requestId;
3090         } catch (RemoteException re) {
3091             synchronized (mLock){
3092                 Slog.e(TAG, "Widget host dead: " + host.id, re);
3093                 host.callbacks = null;
3094             }
3095         }
3096     }
3097 
scheduleNotifyAppWidgetRemovedLocked(Widget widget)3098     private void scheduleNotifyAppWidgetRemovedLocked(Widget widget) {
3099         long requestId = UPDATE_COUNTER.incrementAndGet();
3100         if (widget != null) {
3101             if (widget.trackingUpdate) {
3102                 // Widget is being removed without any update, end the trace
3103                 widget.trackingUpdate = false;
3104                 Log.i(TAG, "Widget removed " + widget.toString());
3105                 Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
3106                         "appwidget update-intent " + widget.provider.id.toString(),
3107                         widget.appWidgetId);
3108             }
3109 
3110             widget.updateSequenceNos.clear();
3111         }
3112         if (widget == null || widget.provider == null || widget.provider.zombie
3113                 || widget.host.callbacks == null || widget.host.zombie) {
3114             return;
3115         }
3116 
3117         SomeArgs args = SomeArgs.obtain();
3118         args.arg1 = widget.host;
3119         args.arg2 = widget.host.callbacks;
3120         args.arg3 = requestId;
3121         args.argi1 = widget.appWidgetId;
3122 
3123         mCallbackHandler.obtainMessage(
3124             CallbackHandler.MSG_NOTIFY_APP_WIDGET_REMOVED,
3125             args).sendToTarget();
3126     }
3127 
handleNotifyAppWidgetRemoved(Host host, IAppWidgetHost callbacks, int appWidgetId, long requestId)3128     private void handleNotifyAppWidgetRemoved(Host host, IAppWidgetHost callbacks, int appWidgetId,
3129             long requestId) {
3130         try {
3131             Slog.d(TAG, "Trying to notify widget removed");
3132             callbacks.appWidgetRemoved(appWidgetId);
3133             host.lastWidgetUpdateSequenceNo = requestId;
3134         } catch (RemoteException re) {
3135             synchronized (mLock) {
3136                 Slog.e(TAG, "Widget host dead: " + host.id, re);
3137                 host.callbacks = null;
3138             }
3139         }
3140     }
3141 
scheduleNotifyGroupHostsForProvidersChangedLocked(int userId)3142     private void scheduleNotifyGroupHostsForProvidersChangedLocked(int userId) {
3143         final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
3144 
3145         final int N = mHosts.size();
3146         for (int i = N - 1; i >= 0; i--) {
3147             Host host = mHosts.get(i);
3148 
3149             boolean hostInGroup = false;
3150             final int M = profileIds.length;
3151             for (int j = 0; j < M; j++) {
3152                 final int profileId = profileIds[j];
3153                 if (host.getUserId() == profileId) {
3154                     hostInGroup = true;
3155                     break;
3156                 }
3157             }
3158 
3159             if (!hostInGroup) {
3160                 continue;
3161             }
3162 
3163             if (host == null || host.zombie || host.callbacks == null) {
3164                 continue;
3165             }
3166 
3167             SomeArgs args = SomeArgs.obtain();
3168             args.arg1 = host;
3169             args.arg2 = host.callbacks;
3170 
3171             mCallbackHandler.obtainMessage(
3172                     CallbackHandler.MSG_NOTIFY_PROVIDERS_CHANGED,
3173                     args).sendToTarget();
3174         }
3175     }
3176 
handleNotifyProvidersChanged(Host host, IAppWidgetHost callbacks)3177     private void handleNotifyProvidersChanged(Host host, IAppWidgetHost callbacks) {
3178         try {
3179             Slog.d(TAG, "Trying to notify widget providers changed");
3180             callbacks.providersChanged();
3181         } catch (RemoteException re) {
3182             synchronized (mLock) {
3183                 Slog.e(TAG, "Widget host dead: " + host.id, re);
3184                 host.callbacks = null;
3185             }
3186         }
3187     }
3188 
isLocalBinder()3189     private static boolean isLocalBinder() {
3190         return Process.myPid() == Binder.getCallingPid();
3191     }
3192 
cloneIfLocalBinder(RemoteViews rv)3193     private static RemoteViews cloneIfLocalBinder(RemoteViews rv) {
3194         if (isLocalBinder() && rv != null) {
3195             return rv.clone();
3196         }
3197         return rv;
3198     }
3199 
cloneIfLocalBinder(AppWidgetProviderInfo info)3200     private static AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) {
3201         if (isLocalBinder() && info != null) {
3202             return info.clone();
3203         }
3204         return info;
3205     }
3206 
cloneIfLocalBinder(Bundle bundle)3207     private static Bundle cloneIfLocalBinder(Bundle bundle) {
3208         // Note: this is only a shallow copy. For now this will be fine, but it could be problematic
3209         // if we start adding objects to the options. Further, it would only be an issue if keyguard
3210         // used such options.
3211         if (isLocalBinder() && bundle != null) {
3212             return (Bundle) bundle.clone();
3213         }
3214         return bundle;
3215     }
3216 
lookupWidgetLocked(int appWidgetId, int uid, String packageName)3217     private Widget lookupWidgetLocked(int appWidgetId, int uid, String packageName) {
3218         final int N = mWidgets.size();
3219         for (int i = 0; i < N; i++) {
3220             Widget widget = mWidgets.get(i);
3221             if (widget.appWidgetId == appWidgetId
3222                     && mSecurityPolicy.canAccessAppWidget(widget, uid, packageName)) {
3223                 return widget;
3224             }
3225         }
3226         if (DEBUG) {
3227             Slog.i(TAG, "cannot find widget for appWidgetId=" + appWidgetId + " uid=" + uid
3228                     + " packageName=" + packageName);
3229         }
3230         return null;
3231     }
3232 
lookupProviderLocked(ProviderId id)3233     private Provider lookupProviderLocked(ProviderId id) {
3234         final int N = mProviders.size();
3235         for (int i = 0; i < N; i++) {
3236             Provider provider = mProviders.get(i);
3237             if (provider.id.equals(id)) {
3238                 return provider;
3239             }
3240         }
3241         return null;
3242     }
3243 
lookupHostLocked(HostId hostId)3244     private Host lookupHostLocked(HostId hostId) {
3245         final int N = mHosts.size();
3246         for (int i = 0; i < N; i++) {
3247             Host host = mHosts.get(i);
3248             if (host.id.equals(hostId)) {
3249                 return host;
3250             }
3251         }
3252         return null;
3253     }
3254 
pruneHostLocked(Host host)3255     private void pruneHostLocked(Host host) {
3256         if (host.widgets.size() == 0 && host.callbacks == null) {
3257             if (DEBUG) {
3258                 Slog.i(TAG, "Pruning host " + host.id);
3259             }
3260             mHosts.remove(host);
3261         }
3262     }
3263 
3264     @GuardedBy("mLock")
loadGroupWidgetProvidersLocked(int[] profileIds)3265     private void loadGroupWidgetProvidersLocked(int[] profileIds) {
3266         List<ResolveInfo> allReceivers = null;
3267         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
3268 
3269         final int profileCount = profileIds.length;
3270         for (int i = 0; i < profileCount; i++) {
3271             final int profileId = profileIds[i];
3272 
3273             List<ResolveInfo> receivers = queryIntentReceivers(intent, profileId);
3274             if (receivers != null && !receivers.isEmpty()) {
3275                 if (allReceivers == null) {
3276                     allReceivers = new ArrayList<>();
3277                 }
3278                 allReceivers.addAll(receivers);
3279             }
3280         }
3281 
3282         final int N = (allReceivers == null) ? 0 : allReceivers.size();
3283         for (int i = 0; i < N; i++) {
3284             ResolveInfo receiver = allReceivers.get(i);
3285             addProviderLocked(receiver);
3286         }
3287     }
3288 
addProviderLocked(ResolveInfo ri)3289     private boolean addProviderLocked(ResolveInfo ri) {
3290         if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
3291             return false;
3292         }
3293 
3294         ComponentName componentName = new ComponentName(ri.activityInfo.packageName,
3295                 ri.activityInfo.name);
3296         ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName);
3297 
3298         // we might have an inactive entry for this provider already due to
3299         // a preceding restore operation.  if so, fix it up in place; otherwise
3300         // just add this new one.
3301         Provider existing = lookupProviderLocked(providerId);
3302 
3303         // If the provider was not found it may be because it was restored and
3304         // we did not know its UID so let us find if there is such one.
3305         if (existing == null) {
3306             ProviderId restoredProviderId = new ProviderId(UNKNOWN_UID, componentName);
3307             existing = lookupProviderLocked(restoredProviderId);
3308         }
3309 
3310         AppWidgetProviderInfo info = createPartialProviderInfo(providerId, ri, existing);
3311 
3312         if (android.os.Flags.allowPrivateProfile()
3313                 && android.multiuser.Flags.disablePrivateSpaceItemsOnHome()
3314                 && android.multiuser.Flags.enablePrivateSpaceFeatures()) {
3315             // Do not add widget providers for profiles with items restricted on home screen.
3316             if (info != null && mUserManager
3317                     .getUserProperties(info.getProfile()).areItemsRestrictedOnHomeScreen()) {
3318                 return false;
3319             }
3320         }
3321 
3322         if (info != null) {
3323             if (existing != null) {
3324                 if (existing.zombie && !mSafeMode) {
3325                     // it's a placeholder that was set up during an app restore
3326                     existing.id = providerId;
3327                     existing.zombie = false;
3328                     existing.setPartialInfoLocked(info);
3329                     if (DEBUG) {
3330                         Slog.i(TAG, "Provider placeholder now reified: " + existing);
3331                     }
3332                 }
3333             } else {
3334                 Provider provider = new Provider();
3335                 provider.id = providerId;
3336                 provider.setPartialInfoLocked(info);
3337                 mProviders.add(provider);
3338             }
3339             return true;
3340         }
3341 
3342         return false;
3343     }
3344 
3345     // Remove widgets for provider that are hosted in userId.
deleteWidgetsLocked(Provider provider, int userId)3346     private void deleteWidgetsLocked(Provider provider, int userId) {
3347         if (DEBUG) {
3348             Slog.i(TAG, "deleteWidgetsLocked() provider=" + provider + " userId=" + userId);
3349         }
3350         final int N = provider.widgets.size();
3351         for (int i = N - 1; i >= 0; i--) {
3352             Widget widget = provider.widgets.get(i);
3353             if (userId == UserHandle.USER_ALL
3354                     || userId == widget.host.getUserId()) {
3355                 provider.widgets.remove(i);
3356                 // Call back with empty RemoteViews
3357                 updateAppWidgetInstanceLocked(widget, null, false);
3358                 // clear out references to this appWidgetId
3359                 widget.host.widgets.remove(widget);
3360                 removeWidgetLocked(widget);
3361                 widget.provider = null;
3362                 pruneHostLocked(widget.host);
3363                 widget.host = null;
3364             }
3365         }
3366     }
3367 
deleteProviderLocked(Provider provider)3368     private void deleteProviderLocked(Provider provider) {
3369         deleteWidgetsLocked(provider, UserHandle.USER_ALL);
3370         mProviders.remove(provider);
3371         mGeneratedPreviewsApiCounter.remove(provider.id);
3372         if (remoteViewsProto()) {
3373             clearGeneratedPreviewsAsync(provider);
3374         }
3375 
3376         // no need to send the DISABLE broadcast, since the receiver is gone anyway
3377         cancelBroadcastsLocked(provider);
3378     }
3379 
sendEnableAndUpdateIntentLocked(@onNull Provider p, int[] appWidgetIds)3380     private void sendEnableAndUpdateIntentLocked(@NonNull Provider p, int[] appWidgetIds) {
3381         final boolean canSendCombinedBroadcast = mIsCombinedBroadcastEnabled && p.info != null
3382                 && p.info.isExtendedFromAppWidgetProvider;
3383         if (!canSendCombinedBroadcast) {
3384             // If this function is called by mistake, send two separate broadcasts instead
3385             sendEnableIntentLocked(p);
3386             sendUpdateIntentLocked(p, appWidgetIds, true);
3387             return;
3388         }
3389 
3390         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE);
3391         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
3392         intent.setComponent(p.id.componentName);
3393         // Placing a widget is something users expect to be UX-responsive, so mark this
3394         // broadcast as interactive
3395         sendBroadcastAsUser(intent, p.id.getProfile(), true);
3396     }
3397 
sendEnableIntentLocked(Provider p)3398     private void sendEnableIntentLocked(Provider p) {
3399         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
3400         intent.setComponent(p.id.componentName);
3401         // Enabling the widget is something users expect to be UX-responsive, so mark this
3402         // broadcast as interactive
3403         sendBroadcastAsUser(intent, p.id.getProfile(), true);
3404     }
3405 
sendUpdateIntentLocked(Provider provider, int[] appWidgetIds, boolean interactive)3406     private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds,
3407             boolean interactive) {
3408         Intent intent = createUpdateIntentLocked(provider, appWidgetIds);
3409         sendBroadcastAsUser(intent, provider.id.getProfile(), interactive);
3410     }
3411 
createUpdateIntentLocked(Provider provider, int[] appWidgetIds)3412     private Intent createUpdateIntentLocked(Provider provider, int[] appWidgetIds) {
3413         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
3414         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
3415         intent.setComponent(provider.id.componentName);
3416         return intent;
3417     }
3418 
sendDeletedIntentLocked(Widget widget)3419     private void sendDeletedIntentLocked(Widget widget) {
3420         sendDeletedIntentLocked(widget.provider.id.componentName, widget.provider.id.getProfile(),
3421                 widget.appWidgetId);
3422     }
3423 
sendDeletedIntentLocked(ComponentName provider, UserHandle profile, int appWidgetId)3424     private void sendDeletedIntentLocked(ComponentName provider, UserHandle profile,
3425             int appWidgetId) {
3426         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
3427         intent.setComponent(provider);
3428         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
3429         // Cleanup after deletion isn't an interactive UX case
3430         sendBroadcastAsUser(intent, profile, false);
3431     }
3432 
sendDisabledIntentLocked(Provider provider)3433     private void sendDisabledIntentLocked(Provider provider) {
3434         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
3435         intent.setComponent(provider.id.componentName);
3436         // Cleanup after disable isn't an interactive UX case
3437         sendBroadcastAsUser(intent, provider.id.getProfile(), false);
3438     }
3439 
sendOptionsChangedIntentLocked(Widget widget)3440     public void sendOptionsChangedIntentLocked(Widget widget) {
3441         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED);
3442         intent.setComponent(widget.provider.id.componentName);
3443         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
3444         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, widget.options);
3445         // The user's changed the options, so seeing them take effect promptly is
3446         // an interactive UX expectation
3447         sendBroadcastAsUser(intent, widget.provider.id.getProfile(), true);
3448     }
3449 
3450     @GuardedBy("mLock")
registerForBroadcastsLocked(Provider provider, int[] appWidgetIds)3451     private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) {
3452         AppWidgetProviderInfo info = provider.getInfoLocked(mContext);
3453         if (info.updatePeriodMillis > 0) {
3454             // if this is the first instance, set the alarm. otherwise,
3455             // rely on the fact that we've already set it and that
3456             // PendingIntent.getBroadcast will update the extras.
3457             boolean alreadyRegistered = provider.broadcast != null;
3458             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
3459             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
3460             intent.setComponent(info.provider);
3461             final long token = Binder.clearCallingIdentity();
3462             try {
3463                 // Broadcast alarms sent by system are immutable
3464                 provider.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
3465                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
3466                         info.getProfile());
3467             } finally {
3468                 Binder.restoreCallingIdentity(token);
3469             }
3470             if (!alreadyRegistered) {
3471                 // Set the alarm outside of our locks; we've latched the first-time
3472                 // invariant and established the PendingIntent safely.
3473                 final long period = Math.max(info.updatePeriodMillis, MIN_UPDATE_PERIOD);
3474                 final PendingIntent broadcast = provider.broadcast;
3475 
3476                 Runnable repeatRunnable = () -> {
3477                     mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
3478                             SystemClock.elapsedRealtime() + period, period, broadcast);
3479                 };
3480                 if (removeAppWidgetServiceIoFromCriticalPath()) {
3481                     mAlarmHandler.post(repeatRunnable);
3482                 } else {
3483                     mSaveStateHandler.post(repeatRunnable);
3484                 }
3485             }
3486         }
3487     }
3488 
getWidgetIds(ArrayList<Widget> widgets)3489     private static int[] getWidgetIds(ArrayList<Widget> widgets) {
3490         int instancesSize = widgets.size();
3491         int appWidgetIds[] = new int[instancesSize];
3492         for (int i = 0; i < instancesSize; i++) {
3493             appWidgetIds[i] = widgets.get(i).appWidgetId;
3494         }
3495         return appWidgetIds;
3496     }
3497 
dumpProviderLocked(Provider provider, int index, PrintWriter pw)3498     private static void dumpProviderLocked(Provider provider, int index, PrintWriter pw) {
3499         AppWidgetProviderInfo info = provider.getPartialInfoLocked();
3500         pw.print("  ["); pw.print(index); pw.print("] provider ");
3501         pw.println(provider.id);
3502         pw.print("    min=("); pw.print(info.minWidth);
3503         pw.print("x"); pw.print(info.minHeight);
3504         pw.print(")   minResize=("); pw.print(info.minResizeWidth);
3505         pw.print("x"); pw.print(info.minResizeHeight);
3506         pw.print(") updatePeriodMillis=");
3507         pw.print(info.updatePeriodMillis);
3508         pw.print(" resizeMode=");
3509         pw.print(info.resizeMode);
3510         pw.print(" widgetCategory=");
3511         pw.print(info.widgetCategory);
3512         pw.print(" autoAdvanceViewId=");
3513         pw.print(info.autoAdvanceViewId);
3514         pw.print(" initialLayout=#");
3515         pw.print(Integer.toHexString(info.initialLayout));
3516         pw.print(" initialKeyguardLayout=#");
3517         pw.print(Integer.toHexString(info.initialKeyguardLayout));
3518         pw.print("   zombie="); pw.println(provider.zombie);
3519     }
3520 
dumpHost(Host host, int index, PrintWriter pw)3521     private static void dumpHost(Host host, int index, PrintWriter pw) {
3522         pw.print("  ["); pw.print(index); pw.print("] hostId=");
3523         pw.println(host.id);
3524         pw.print("    callbacks="); pw.println(host.callbacks);
3525         pw.print("    widgets.size="); pw.print(host.widgets.size());
3526         pw.print(" zombie="); pw.println(host.zombie);
3527     }
3528 
dumpGrant(Pair<Integer, String> grant, int index, PrintWriter pw)3529     private static void dumpGrant(Pair<Integer, String> grant, int index, PrintWriter pw) {
3530         pw.print("  ["); pw.print(index); pw.print(']');
3531         pw.print(" user="); pw.print(grant.first);
3532         pw.print(" package="); pw.println(grant.second);
3533     }
3534 
dumpWidget(Widget widget, int index, PrintWriter pw)3535     private static void dumpWidget(Widget widget, int index, PrintWriter pw) {
3536         pw.print("  ["); pw.print(index); pw.print("] id=");
3537         pw.println(widget.appWidgetId);
3538         pw.print("    host=");
3539         pw.println(widget.host.id);
3540         if (widget.provider != null) {
3541             pw.print("    provider="); pw.println(widget.provider.id);
3542         }
3543         if (widget.host != null) {
3544             pw.print("    host.callbacks="); pw.println(widget.host.callbacks);
3545         }
3546         if (widget.views != null) {
3547             pw.print("    views="); pw.println(widget.views);
3548             pw.print("    views_bitmap_memory=");
3549             pw.println(widget.views.estimateTotalBitmapMemoryUsage());
3550         }
3551     }
3552 
serializeProvider(@onNull final TypedXmlSerializer out, @NonNull final Provider p, final boolean persistsProviderInfo)3553     private static void serializeProvider(@NonNull final TypedXmlSerializer out,
3554             @NonNull final Provider p, final boolean persistsProviderInfo) throws IOException {
3555         Objects.requireNonNull(out);
3556         Objects.requireNonNull(p);
3557         out.startTag(null, "p");
3558         out.attribute(null, "pkg", p.id.componentName.getPackageName());
3559         out.attribute(null, "cl", p.id.componentName.getClassName());
3560         out.attributeIntHex(null, "tag", p.tag);
3561         if (!TextUtils.isEmpty(p.infoTag)) {
3562             out.attribute(null, "info_tag", p.infoTag);
3563         }
3564         if (persistsProviderInfo && p.mInfoParsed) {
3565             AppWidgetXmlUtil.writeAppWidgetProviderInfoLocked(out, p.info);
3566         }
3567         final int pendingIdsCount = p.pendingDeletedWidgetIds.size();
3568         if (pendingIdsCount > 0) {
3569             final List<String> idStrings = new ArrayList<>();
3570             for (int i = 0; i < pendingIdsCount; i++) {
3571                 idStrings.add(String.valueOf(p.pendingDeletedWidgetIds.get(i)));
3572             }
3573             out.attribute(null, PENDING_DELETED_IDS_ATTR, String.join(",", idStrings));
3574         }
3575         out.endTag(null, "p");
3576     }
3577 
serializeHost(TypedXmlSerializer out, Host host)3578     private static void serializeHost(TypedXmlSerializer out, Host host) throws IOException {
3579         out.startTag(null, "h");
3580         out.attribute(null, "pkg", host.id.packageName);
3581         out.attributeIntHex(null, "id", host.id.hostId);
3582         out.attributeIntHex(null, "tag", host.tag);
3583         out.endTag(null, "h");
3584     }
3585 
serializeAppWidget(TypedXmlSerializer out, Widget widget, boolean saveRestoreCompleted)3586     private static void serializeAppWidget(TypedXmlSerializer out, Widget widget,
3587             boolean saveRestoreCompleted) throws IOException {
3588         out.startTag(null, "g");
3589         out.attributeIntHex(null, "id", widget.appWidgetId);
3590         out.attributeIntHex(null, "rid", widget.restoredId);
3591         out.attributeIntHex(null, "h", widget.host.tag);
3592         if (widget.provider != null) {
3593             out.attributeIntHex(null, "p", widget.provider.tag);
3594         }
3595         if (widget.options != null) {
3596             int minWidth = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
3597             int minHeight = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
3598             int maxWidth = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
3599             int maxHeight = widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
3600             out.attributeIntHex(null, "min_width", (minWidth > 0) ? minWidth : 0);
3601             out.attributeIntHex(null, "min_height", (minHeight > 0) ? minHeight : 0);
3602             out.attributeIntHex(null, "max_width", (maxWidth > 0) ? maxWidth : 0);
3603             out.attributeIntHex(null, "max_height", (maxHeight > 0) ? maxHeight : 0);
3604             out.attributeIntHex(null, "host_category", widget.options.getInt(
3605                     AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY));
3606             List<SizeF> sizes = widget.options.getParcelableArrayList(
3607                     AppWidgetManager.OPTION_APPWIDGET_SIZES, SizeF.class);
3608             if (sizes != null) {
3609                 out.attribute(null, KEY_SIZES, serializeWidgetSizes(sizes));
3610             }
3611             if (saveRestoreCompleted) {
3612                 boolean restoreCompleted = widget.options.getBoolean(
3613                         AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED);
3614                 out.attributeBoolean(null, "restore_completed", restoreCompleted);
3615             }
3616         }
3617         out.endTag(null, "g");
3618     }
3619 
parseWidgetIdOptions(TypedXmlPullParser parser)3620     private static Bundle parseWidgetIdOptions(TypedXmlPullParser parser) {
3621         Bundle options = new Bundle();
3622         boolean restoreCompleted = parser.getAttributeBoolean(null, "restore_completed", false);
3623         if (restoreCompleted) {
3624             options.putBoolean(AppWidgetManager.OPTION_APPWIDGET_RESTORE_COMPLETED, true);
3625         }
3626         int minWidth = parser.getAttributeIntHex(null, "min_width", -1);
3627         if (minWidth != -1) {
3628             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, minWidth);
3629         }
3630         int minHeight = parser.getAttributeIntHex(null, "min_height", -1);
3631         if (minHeight != -1) {
3632             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, minHeight);
3633         }
3634         int maxWidth = parser.getAttributeIntHex(null, "max_width", -1);
3635         if (maxWidth != -1) {
3636             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, maxWidth);
3637         }
3638         int maxHeight = parser.getAttributeIntHex(null, "max_height", -1);
3639         if (maxHeight != -1) {
3640             options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, maxHeight);
3641         }
3642         String sizesStr = parser.getAttributeValue(null, KEY_SIZES);
3643         ArrayList<SizeF> sizes = deserializeWidgetSizesStr(sizesStr);
3644         if (sizes != null) {
3645             options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, sizes);
3646         }
3647         int category = parser.getAttributeIntHex(null, "host_category",
3648                 AppWidgetProviderInfo.WIDGET_CATEGORY_UNKNOWN);
3649         if (category != AppWidgetProviderInfo.WIDGET_CATEGORY_UNKNOWN) {
3650             options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, category);
3651         }
3652         return options;
3653     }
3654 
3655     @Override
getWidgetParticipants(int userId)3656     public List<String> getWidgetParticipants(int userId) {
3657         return mBackupRestoreController.getWidgetParticipants(userId);
3658     }
3659 
3660     @Override
getWidgetState(String packageName, int userId)3661     public byte[] getWidgetState(String packageName, int userId) {
3662         return mBackupRestoreController.getWidgetState(packageName, userId);
3663     }
3664 
3665     @Override
systemRestoreStarting(int userId)3666     public void systemRestoreStarting(int userId) {
3667         mBackupRestoreController.systemRestoreStarting(userId);
3668     }
3669 
3670     @Override
restoreWidgetState(String packageName, byte[] restoredState, int userId)3671     public void restoreWidgetState(String packageName, byte[] restoredState, int userId) {
3672         mBackupRestoreController.restoreWidgetState(packageName, restoredState, userId);
3673     }
3674 
3675     @Override
systemRestoreFinished(int userId)3676     public void systemRestoreFinished(int userId) {
3677         mBackupRestoreController.systemRestoreFinished(userId);
3678     }
3679 
3680     @SuppressWarnings("deprecation")
createPartialProviderInfo(ProviderId providerId, ResolveInfo ri, Provider provider)3681     private AppWidgetProviderInfo createPartialProviderInfo(ProviderId providerId, ResolveInfo ri,
3682             Provider provider) {
3683         boolean hasXmlDefinition = false;
3684         Bundle metaData = ri.activityInfo.metaData;
3685         if (metaData == null) {
3686             return null;
3687         }
3688 
3689         if (provider != null && !TextUtils.isEmpty(provider.infoTag)) {
3690             hasXmlDefinition = metaData.getInt(provider.infoTag) != 0;
3691         }
3692         hasXmlDefinition |= metaData.getInt(AppWidgetManager.META_DATA_APPWIDGET_PROVIDER) != 0;
3693 
3694         if (hasXmlDefinition) {
3695             AppWidgetProviderInfo info = new AppWidgetProviderInfo();
3696             info.provider = providerId.componentName;
3697             info.providerInfo = ri.activityInfo;
3698             if (DEBUG) {
3699                 Objects.requireNonNull(ri.activityInfo);
3700             }
3701             return info;
3702         }
3703         return null;
3704     }
3705 
parseAppWidgetProviderInfo(Context context, ProviderId providerId, ActivityInfo activityInfo, String metadataKey)3706     private static AppWidgetProviderInfo parseAppWidgetProviderInfo(Context context,
3707             ProviderId providerId, ActivityInfo activityInfo, String metadataKey) {
3708         final PackageManager pm = context.getPackageManager();
3709         try (XmlResourceParser parser = activityInfo.loadXmlMetaData(pm, metadataKey)) {
3710             if (parser == null) {
3711                 Slog.w(TAG, "No " + metadataKey + " meta-data for AppWidget provider '"
3712                         + providerId + '\'');
3713                 return null;
3714             }
3715 
3716             AttributeSet attrs = Xml.asAttributeSet(parser);
3717 
3718             int type;
3719             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3720                     && type != XmlPullParser.START_TAG) {
3721                 // drain whitespace, comments, etc.
3722             }
3723 
3724             String nodeName = parser.getName();
3725             if (!"appwidget-provider".equals(nodeName)) {
3726                 Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
3727                         + " AppWidget provider " + providerId.componentName
3728                         + " for user " + providerId.uid);
3729                 return null;
3730             }
3731 
3732             AppWidgetProviderInfo info = new AppWidgetProviderInfo();
3733             info.provider = providerId.componentName;
3734             info.providerInfo = activityInfo;
3735             if (DEBUG) {
3736                 Objects.requireNonNull(activityInfo);
3737             }
3738 
3739             final Resources resources;
3740             final long identity = Binder.clearCallingIdentity();
3741             try {
3742                 final int userId = UserHandle.getUserId(providerId.uid);
3743                 final ApplicationInfo app = pm.getApplicationInfoAsUser(activityInfo.packageName,
3744                         0, userId);
3745                 resources = pm.getResourcesForApplication(app);
3746             } finally {
3747                 Binder.restoreCallingIdentity(identity);
3748             }
3749 
3750             TypedArray sa = resources.obtainAttributes(attrs,
3751                     com.android.internal.R.styleable.AppWidgetProviderInfo);
3752 
3753             // These dimensions has to be resolved in the application's context.
3754             // We simply send back the raw complex data, which will be
3755             // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
3756             TypedValue value = sa
3757                     .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
3758             info.minWidth = value != null ? value.data : 0;
3759             value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
3760             info.minHeight = value != null ? value.data : 0;
3761 
3762             value = sa.peekValue(
3763                     com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth);
3764             info.minResizeWidth = value != null ? value.data : info.minWidth;
3765             value = sa.peekValue(
3766                     com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight);
3767             info.minResizeHeight = value != null ? value.data : info.minHeight;
3768 
3769             value = sa.peekValue(
3770                     com.android.internal.R.styleable.AppWidgetProviderInfo_maxResizeWidth);
3771             info.maxResizeWidth = value != null ? value.data : 0;
3772             value = sa.peekValue(
3773                     com.android.internal.R.styleable.AppWidgetProviderInfo_maxResizeHeight);
3774             info.maxResizeHeight = value != null ? value.data : 0;
3775 
3776             info.targetCellWidth = sa.getInt(
3777                     com.android.internal.R.styleable.AppWidgetProviderInfo_targetCellWidth, 0);
3778             info.targetCellHeight = sa.getInt(
3779                     com.android.internal.R.styleable.AppWidgetProviderInfo_targetCellHeight, 0);
3780 
3781             info.updatePeriodMillis = sa.getInt(
3782                     com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
3783             info.initialLayout = sa.getResourceId(
3784                     com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, ID_NULL);
3785             info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable.
3786                     AppWidgetProviderInfo_initialKeyguardLayout, ID_NULL);
3787 
3788             String className = sa
3789                     .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
3790             if (className != null) {
3791                 info.configure = new ComponentName(providerId.componentName.getPackageName(),
3792                         className);
3793             }
3794             info.label = activityInfo.loadLabel(pm).toString();
3795             info.icon = activityInfo.getIconResource();
3796             info.previewImage = sa.getResourceId(
3797                     com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, ID_NULL);
3798             info.previewLayout = sa.getResourceId(
3799                     com.android.internal.R.styleable.AppWidgetProviderInfo_previewLayout, ID_NULL);
3800             info.autoAdvanceViewId = sa.getResourceId(
3801                     com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId,
3802                     View.NO_ID);
3803             info.resizeMode = sa.getInt(
3804                     com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
3805                     AppWidgetProviderInfo.RESIZE_NONE);
3806             info.widgetCategory = sa.getInt(
3807                     com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory,
3808                     AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
3809             info.widgetFeatures = sa.getInt(
3810                     com.android.internal.R.styleable.AppWidgetProviderInfo_widgetFeatures, 0);
3811             info.descriptionRes = sa.getResourceId(
3812                     com.android.internal.R.styleable.AppWidgetProviderInfo_description, ID_NULL);
3813             sa.recycle();
3814             return info;
3815         } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) {
3816             // Ok to catch Exception here, because anything going wrong because
3817             // of what a client process passes to us should not be fatal for the
3818             // system process.
3819             Slog.w(TAG, "XML parsing failed for AppWidget provider "
3820                     + providerId.componentName + " for user " + providerId.uid, e);
3821             return null;
3822         }
3823     }
3824 
getUidForPackage(String packageName, int userId)3825     private int getUidForPackage(String packageName, int userId) {
3826         PackageInfo pkgInfo = null;
3827 
3828         final long identity = Binder.clearCallingIdentity();
3829         try {
3830             pkgInfo = mPackageManager.getPackageInfo(packageName, 0, userId);
3831         } catch (RemoteException re) {
3832             // Shouldn't happen, local call
3833         } finally {
3834             Binder.restoreCallingIdentity(identity);
3835         }
3836 
3837         if (pkgInfo == null || pkgInfo.applicationInfo == null) {
3838             return -1;
3839         }
3840 
3841         return pkgInfo.applicationInfo.uid;
3842     }
3843 
getProviderInfo(ComponentName componentName, int userId)3844     private ActivityInfo getProviderInfo(ComponentName componentName, int userId) {
3845         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
3846         intent.setComponent(componentName);
3847 
3848         List<ResolveInfo> receivers = queryIntentReceivers(intent, userId);
3849         // We are setting component, so there is only one or none.
3850         if (!receivers.isEmpty()) {
3851             return receivers.get(0).activityInfo;
3852         }
3853 
3854         return null;
3855     }
3856 
queryIntentReceivers(Intent intent, int userId)3857     private List<ResolveInfo> queryIntentReceivers(Intent intent, int userId) {
3858         final long identity = Binder.clearCallingIdentity();
3859         try {
3860             int flags = PackageManager.GET_META_DATA;
3861 
3862             // We really need packages to be around and parsed to know if they
3863             // provide widgets.
3864             flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
3865 
3866             // Widget hosts that are non-crypto aware may be hosting widgets
3867             // from a profile that is still locked, so let them see those
3868             // widgets.
3869             if (isProfileWithUnlockedParent(userId)) {
3870                 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
3871                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
3872             }
3873 
3874             // Widgets referencing shared libraries need to have their
3875             // dependencies loaded.
3876             flags |= PackageManager.GET_SHARED_LIBRARY_FILES;
3877 
3878             return mPackageManager.queryIntentReceivers(intent,
3879                     intent.resolveTypeIfNeeded(mContext.getContentResolver()),
3880                     flags, userId).getList();
3881         } catch (RemoteException re) {
3882             return Collections.emptyList();
3883         } finally {
3884             Binder.restoreCallingIdentity(identity);
3885         }
3886     }
3887 
3888     /**
3889      * This does not use the usual onUserUnlocked() listener mechanism because it is
3890      * invoked at a choreographed point in the middle of the user unlock sequence,
3891      * before the boot-completed broadcast is issued and the listeners notified.
3892      */
handleUserUnlocked(int userId)3893     void handleUserUnlocked(int userId) {
3894         if (isProfileWithLockedParent(userId)) {
3895             return;
3896         }
3897         if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
3898             Slog.w(TAG, "User " + userId + " is no longer unlocked - exiting");
3899             return;
3900         }
3901         long time = SystemClock.elapsedRealtime();
3902         synchronized (mLock) {
3903             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "appwidget ensure");
3904             ensureGroupStateLoadedLocked(userId);
3905             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
3906             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "appwidget reload");
3907             reloadWidgetsMaskedStateForGroup(mSecurityPolicy.getGroupParent(userId));
3908             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
3909 
3910             final int N = mProviders.size();
3911             for (int i = 0; i < N; i++) {
3912                 Provider provider = mProviders.get(i);
3913 
3914                 // Send broadcast only to the providers of the user.
3915                 if (provider.getUserId() != userId) {
3916                     continue;
3917                 }
3918 
3919                 if (provider.widgets.size() > 0 && !provider.maskedByStoppedPackage) {
3920                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
3921                             "appwidget init " + provider.id.componentName.getPackageName());
3922                     provider.widgets.forEach(widget -> {
3923                         widget.trackingUpdate = true;
3924                         Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
3925                                 "appwidget update-intent " + provider.id.toString(),
3926                                 widget.appWidgetId);
3927                         Log.i(TAG, "Widget update scheduled on unlock " + widget.toString());
3928                     });
3929                     int[] appWidgetIds = getWidgetIds(provider.widgets);
3930                     sendEnableAndUpdateIntentLocked(provider, appWidgetIds);
3931                     registerForBroadcastsLocked(provider, appWidgetIds);
3932                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
3933                 }
3934             }
3935         }
3936         Slog.i(TAG, "Processing of handleUserUnlocked u" + userId + " took "
3937                 + (SystemClock.elapsedRealtime() - time) + " ms");
3938     }
3939 
3940     // only call from initialization -- it assumes that the data structures are all empty
3941     @GuardedBy("mLock")
loadGroupStateLocked(int[] profileIds)3942     private void loadGroupStateLocked(int[] profileIds) {
3943         // We can bind the widgets to host and providers only after
3944         // reading the host and providers for all users since a widget
3945         // can have a host and a provider in different users.
3946         List<LoadedWidgetState> loadedWidgets = new ArrayList<>();
3947 
3948         int version = 0;
3949 
3950         final int profileIdCount = profileIds.length;
3951         for (int i = 0; i < profileIdCount; i++) {
3952             final int profileId = profileIds[i];
3953 
3954             // No file written for this user - nothing to do.
3955             AtomicFile file = getSavedStateFile(profileId);
3956             try (FileInputStream stream = file.openRead()) {
3957                 version = readProfileStateFromFileLocked(stream, profileId, loadedWidgets);
3958             } catch (IOException e) {
3959                 Slog.w(TAG, "Failed to read state: " + e);
3960             }
3961 
3962             if (remoteViewsProto()) {
3963                 try {
3964                     loadGeneratedPreviewCategoriesLocked(profileId);
3965                 } catch (IOException e) {
3966                     Slog.w(TAG, "Failed to read preview categories: " + e);
3967                 }
3968             }
3969         }
3970 
3971         if (version >= 0) {
3972             // Hooke'm up...
3973             bindLoadedWidgetsLocked(loadedWidgets);
3974 
3975             // upgrade the database if needed
3976             performUpgradeLocked(version);
3977         } else {
3978             // failed reading, clean up
3979             Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
3980             clearWidgetsLocked();
3981             mHosts.clear();
3982             final int N = mProviders.size();
3983             for (int i = 0; i < N; i++) {
3984                 mProviders.get(i).widgets.clear();
3985             }
3986         }
3987     }
3988 
bindLoadedWidgetsLocked(List<LoadedWidgetState> loadedWidgets)3989     private void bindLoadedWidgetsLocked(List<LoadedWidgetState> loadedWidgets) {
3990         final int loadedWidgetCount = loadedWidgets.size();
3991         for (int i = loadedWidgetCount - 1; i >= 0; i--) {
3992             LoadedWidgetState loadedWidget = loadedWidgets.remove(i);
3993             Widget widget = loadedWidget.widget;
3994 
3995             widget.provider = findProviderByTag(loadedWidget.providerTag);
3996             if (widget.provider == null) {
3997                 // This provider is gone. We just let the host figure out
3998                 // that this happened when it fails to load it.
3999                 continue;
4000             }
4001 
4002             widget.host = findHostByTag(loadedWidget.hostTag);
4003             if (widget.host == null) {
4004                 // This host is gone.
4005                 continue;
4006             }
4007 
4008             widget.provider.widgets.add(widget);
4009             widget.host.widgets.add(widget);
4010             addWidgetLocked(widget);
4011         }
4012     }
4013 
findProviderByTag(int tag)4014     private Provider findProviderByTag(int tag) {
4015         if (tag < 0) {
4016             return null;
4017         }
4018         final int providerCount = mProviders.size();
4019         for (int i = 0; i < providerCount; i++) {
4020             Provider provider = mProviders.get(i);
4021             if (provider.tag == tag) {
4022                 return provider;
4023             }
4024         }
4025         return null;
4026     }
4027 
findHostByTag(int tag)4028     private Host findHostByTag(int tag) {
4029         if (tag < 0) {
4030             return null;
4031         }
4032         final int hostCount = mHosts.size();
4033         for (int i = 0; i < hostCount; i++) {
4034             Host host = mHosts.get(i);
4035             if (host.tag == tag) {
4036                 return host;
4037             }
4038         }
4039         return null;
4040     }
4041 
4042     /**
4043      * Adds the widget to mWidgets and tracks the package name in mWidgetPackages.
4044      */
addWidgetLocked(Widget widget)4045     void addWidgetLocked(Widget widget) {
4046         if (DEBUG) {
4047             Slog.i(TAG, "addWidgetLocked() " + widget);
4048         }
4049         ensureWidgetCountBeforeAddLocked(widget);
4050         mWidgets.add(widget);
4051 
4052         onWidgetProviderAddedOrChangedLocked(widget);
4053     }
4054 
4055     /**
4056      * Ensures that the widget count for the widget's host is not greater than the maximum
4057      * number of widgets per host. If the count is greater than the maximum, removes oldest widgets
4058      * from the host until the count is less than or equal to the maximum.
4059      */
ensureWidgetCountBeforeAddLocked(@onNull final Widget widget)4060     private void ensureWidgetCountBeforeAddLocked(@NonNull final Widget widget) {
4061         if (widget.host == null || widget.host.id == null) {
4062             return;
4063         }
4064         final List<Widget> widgetsInSameHost = new ArrayList<>();
4065         for (Widget w : mWidgets) {
4066             if (w.host != null && widget.host.id.equals(w.host.id)) {
4067                 widgetsInSameHost.add(w);
4068             }
4069         }
4070         while (widgetsInSameHost.size() >= MAX_NUMBER_OF_WIDGETS_PER_HOST) {
4071             removeWidgetLocked(widgetsInSameHost.remove(0));
4072         }
4073     }
4074 
4075     /**
4076      * Checks if the provider is assigned and updates the mWidgetPackages to track packages
4077      * that have bound widgets.
4078      */
onWidgetProviderAddedOrChangedLocked(Widget widget)4079     void onWidgetProviderAddedOrChangedLocked(Widget widget) {
4080         if (widget.provider == null) return;
4081 
4082         int userId = widget.provider.getUserId();
4083         synchronized (mWidgetPackagesLock) {
4084             ArraySet<String> packages = mWidgetPackages.get(userId);
4085             if (packages == null) {
4086                 mWidgetPackages.put(userId, packages = new ArraySet<String>());
4087             }
4088             packages.add(widget.provider.id.componentName.getPackageName());
4089         }
4090 
4091         // If we are adding a widget it might be for a provider that
4092         // is currently masked, if so mask the widget.
4093         if (widget.provider.isMaskedLocked()) {
4094             maskWidgetsViewsLocked(widget.provider, widget);
4095         } else {
4096             widget.clearMaskedViewsLocked();
4097         }
4098     }
4099 
4100     /**
4101      * Removes a widget from mWidgets and updates the cache of bound widget provider packages.
4102      * If there are other widgets with the same package, leaves it in the cache, otherwise it
4103      * removes the associated package from the cache.
4104      */
removeWidgetLocked(Widget widget)4105     void removeWidgetLocked(Widget widget) {
4106         if (DEBUG) {
4107             Slog.i(TAG, "removeWidgetLocked() " + widget);
4108         }
4109         mWidgets.remove(widget);
4110         onWidgetRemovedLocked(widget);
4111         scheduleNotifyAppWidgetRemovedLocked(widget);
4112     }
4113 
onWidgetRemovedLocked(Widget widget)4114     private void onWidgetRemovedLocked(Widget widget) {
4115         if (widget.provider == null) return;
4116 
4117         final int userId = widget.provider.getUserId();
4118         final String packageName = widget.provider.id.componentName.getPackageName();
4119         synchronized (mWidgetPackagesLock) {
4120             ArraySet<String> packages = mWidgetPackages.get(userId);
4121             if (packages == null) {
4122                 return;
4123             }
4124             // Check if there is any other widget with the same package name.
4125             // Remove packageName if none.
4126             final int N = mWidgets.size();
4127             for (int i = 0; i < N; i++) {
4128                 Widget w = mWidgets.get(i);
4129                 if (w.provider == null) continue;
4130                 if (w.provider.getUserId() == userId
4131                         && packageName.equals(w.provider.id.componentName.getPackageName())) {
4132                     return;
4133                 }
4134             }
4135             packages.remove(packageName);
4136         }
4137     }
4138 
4139     /**
4140      * Clears all widgets and associated cache of packages with bound widgets.
4141      */
clearWidgetsLocked()4142     void clearWidgetsLocked() {
4143         if (DEBUG) {
4144             Slog.i(TAG, "clearWidgetsLocked()");
4145         }
4146         mWidgets.clear();
4147 
4148         onWidgetsClearedLocked();
4149     }
4150 
onWidgetsClearedLocked()4151     private void onWidgetsClearedLocked() {
4152         synchronized (mWidgetPackagesLock) {
4153             mWidgetPackages.clear();
4154         }
4155     }
4156 
4157     @Override
isBoundWidgetPackage(String packageName, int userId)4158     public boolean isBoundWidgetPackage(String packageName, int userId) {
4159         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
4160             throw new SecurityException("Only the system process can call this");
4161         }
4162         synchronized (mWidgetPackagesLock) {
4163             final ArraySet<String> packages = mWidgetPackages.get(userId);
4164             if (packages != null) {
4165                 return packages.contains(packageName);
4166             }
4167         }
4168         return false;
4169     }
4170 
4171     @GuardedBy("mLock")
saveStateToByteArrayLocked(int userId)4172     private @NonNull SparseArray<byte[]> saveStateToByteArrayLocked(int userId) {
4173         tagProvidersAndHosts();
4174 
4175         final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
4176         SparseArray<byte[]> userIdToBytesMapping = new SparseArray<>();
4177 
4178         for (int profileId : profileIds) {
4179             ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
4180             if (writeProfileStateToStreamLocked(outputStream, profileId)) {
4181                 userIdToBytesMapping.put(profileId, outputStream.toByteArray());
4182             }
4183         }
4184 
4185         return userIdToBytesMapping;
4186     }
4187 
4188     @GuardedBy("mLock")
saveStateLocked(int userId)4189     private void saveStateLocked(int userId) {
4190         tagProvidersAndHosts();
4191 
4192         final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
4193 
4194         final int profileCount = profileIds.length;
4195         for (int i = 0; i < profileCount; i++) {
4196             final int profileId = profileIds[i];
4197 
4198             AtomicFile file = getSavedStateFile(profileId);
4199             FileOutputStream stream;
4200             try {
4201                 stream = file.startWrite();
4202                 if (writeProfileStateToStreamLocked(stream, profileId)) {
4203                     file.finishWrite(stream);
4204                 } else {
4205                     file.failWrite(stream);
4206                     Slog.w(TAG, "Failed to save state, restoring backup.");
4207                 }
4208             } catch (IOException e) {
4209                 Slog.w(TAG, "Failed open state file for write: " + e);
4210             }
4211         }
4212     }
4213 
tagProvidersAndHosts()4214     private void tagProvidersAndHosts() {
4215         final int providerCount = mProviders.size();
4216         for (int i = 0; i < providerCount; i++) {
4217             Provider provider = mProviders.get(i);
4218             provider.tag = i;
4219         }
4220 
4221         final int hostCount = mHosts.size();
4222         for (int i = 0; i < hostCount; i++) {
4223             Host host = mHosts.get(i);
4224             host.tag = i;
4225         }
4226     }
4227 
clearProvidersAndHostsTagsLocked()4228     private void clearProvidersAndHostsTagsLocked() {
4229         final int providerCount = mProviders.size();
4230         for (int i = 0; i < providerCount; i++) {
4231             Provider provider = mProviders.get(i);
4232             provider.tag = TAG_UNDEFINED;
4233         }
4234 
4235         final int hostCount = mHosts.size();
4236         for (int i = 0; i < hostCount; i++) {
4237             Host host = mHosts.get(i);
4238             host.tag = TAG_UNDEFINED;
4239         }
4240     }
4241 
4242     @GuardedBy("mLock")
writeProfileStateToStreamLocked(OutputStream stream, int userId)4243     private boolean writeProfileStateToStreamLocked(OutputStream stream, int userId) {
4244         int N;
4245 
4246         try {
4247             TypedXmlSerializer out = Xml.resolveSerializer(stream);
4248             out.startDocument(null, true);
4249             out.startTag(null, "gs");
4250             out.attributeInt(null, "version", CURRENT_VERSION);
4251 
4252             N = mProviders.size();
4253             for (int i = 0; i < N; i++) {
4254                 Provider provider = mProviders.get(i);
4255                 // Save only providers for the user.
4256                 if (provider.getUserId() != userId) {
4257                     continue;
4258                 }
4259                 serializeProvider(out, provider, true /* persistsProviderInfo */);
4260             }
4261 
4262             N = mHosts.size();
4263             for (int i = 0; i < N; i++) {
4264                 Host host = mHosts.get(i);
4265                 // Save only hosts for the user.
4266                 if (host.getUserId() != userId) {
4267                     continue;
4268                 }
4269                 serializeHost(out, host);
4270             }
4271 
4272             N = mWidgets.size();
4273             for (int i = 0; i < N; i++) {
4274                 Widget widget = mWidgets.get(i);
4275                 // Save only widgets hosted by the user.
4276                 if (widget.host.getUserId() != userId) {
4277                     continue;
4278                 }
4279                 serializeAppWidget(out, widget, true);
4280             }
4281 
4282             Iterator<Pair<Integer, String>> it = mPackagesWithBindWidgetPermission.iterator();
4283             while (it.hasNext()) {
4284                 Pair<Integer, String> binding = it.next();
4285                 // Save only white listings for the user.
4286                 if (binding.first != userId) {
4287                     continue;
4288                 }
4289                 out.startTag(null, "b");
4290                 out.attribute(null, "packageName", binding.second);
4291                 out.endTag(null, "b");
4292             }
4293 
4294             out.endTag(null, "gs");
4295 
4296             if (supportResumeRestoreAfterReboot()
4297                     && mBackupRestoreController.requiresPersistenceLocked()) {
4298                 AppWidgetXmlUtil.writeBackupRestoreControllerState(
4299                         out, mBackupRestoreController.getStateLocked(userId));
4300             }
4301 
4302             out.endDocument();
4303             return true;
4304         } catch (IOException e) {
4305             Slog.w(TAG, "Failed to write state: " + e);
4306             return false;
4307         }
4308     }
4309 
4310     @GuardedBy("mLock")
readProfileStateFromFileLocked(FileInputStream stream, int userId, List<LoadedWidgetState> outLoadedWidgets)4311     private int readProfileStateFromFileLocked(FileInputStream stream, int userId,
4312             List<LoadedWidgetState> outLoadedWidgets) {
4313         int version = -1;
4314         try {
4315             TypedXmlPullParser parser = Xml.resolvePullParser(stream);
4316 
4317             int legacyProviderIndex = -1;
4318             int legacyHostIndex = -1;
4319             int type;
4320             do {
4321                 type = parser.next();
4322                 if (type == XmlPullParser.START_TAG) {
4323                     String tag = parser.getName();
4324                     if ("gs".equals(tag)) {
4325                         version = parser.getAttributeInt(null, "version", 0);
4326                     } else if ("p".equals(tag)) {
4327                         legacyProviderIndex++;
4328                         // TODO: do we need to check that this package has the same signature
4329                         // as before?
4330                         String pkg = parser.getAttributeValue(null, "pkg");
4331                         String cl = parser.getAttributeValue(null, "cl");
4332 
4333                         pkg = getCanonicalPackageName(pkg, cl, userId);
4334                         if (pkg == null) {
4335                             continue;
4336                         }
4337 
4338                         final int uid = getUidForPackage(pkg, userId);
4339                         if (uid < 0) {
4340                             continue;
4341                         }
4342 
4343                         ComponentName componentName = new ComponentName(pkg, cl);
4344 
4345                         ActivityInfo providerInfo = getProviderInfo(componentName, userId);
4346                         if (providerInfo == null) {
4347                             continue;
4348                         }
4349 
4350                         ProviderId providerId = new ProviderId(uid, componentName);
4351                         Provider provider = lookupProviderLocked(providerId);
4352 
4353                         if (provider == null && mSafeMode) {
4354                             // if we're in safe mode, make a temporary one
4355                             AppWidgetProviderInfo info = new AppWidgetProviderInfo();
4356                             info.provider = providerId.componentName;
4357                             info.providerInfo = providerInfo;
4358                             if (DEBUG) {
4359                                 Objects.requireNonNull(providerInfo);
4360                             }
4361 
4362                             provider = new Provider();
4363                             provider.setPartialInfoLocked(info);
4364                             provider.zombie = true;
4365                             provider.id = providerId;
4366                             mProviders.add(provider);
4367                         } else {
4368                             final AppWidgetProviderInfo info =
4369                                     AppWidgetXmlUtil.readAppWidgetProviderInfoLocked(parser);
4370                             if (DEBUG && info == null) {
4371                                 Slog.d(TAG, "Unable to load widget provider info from xml for "
4372                                         + providerId.componentName);
4373                             }
4374                             if (info != null) {
4375                                 info.provider = providerId.componentName;
4376                                 info.providerInfo = providerInfo;
4377                                 if (DEBUG) {
4378                                     Objects.requireNonNull(providerInfo);
4379                                 }
4380                                 provider.setInfoLocked(info);
4381                             }
4382                         }
4383 
4384                         final int providerTag = parser.getAttributeIntHex(null, "tag",
4385                                 legacyProviderIndex);
4386                         provider.tag = providerTag;
4387                         provider.infoTag = parser.getAttributeValue(null, "info_tag");
4388 
4389                         final String pendingDeletedIds = parser.getAttributeValue(null,
4390                                 PENDING_DELETED_IDS_ATTR);
4391                         if (pendingDeletedIds != null && !pendingDeletedIds.isEmpty()) {
4392                             final String[] idStrings = pendingDeletedIds.split(",");
4393                             for (int i = 0; i < idStrings.length; i++) {
4394                                 provider.pendingDeletedWidgetIds.add(
4395                                         Integer.parseInt(idStrings[i]));
4396                             }
4397                         }
4398                     } else if ("h".equals(tag)) {
4399                         legacyHostIndex++;
4400                         Host host = new Host();
4401                         // TODO: do we need to check that this package has the same signature
4402                         // as before?
4403                         String pkg = parser.getAttributeValue(null, "pkg");
4404 
4405                         final int uid = getUidForPackage(pkg, userId);
4406                         if (uid < 0) {
4407                             host.zombie = true;
4408                         }
4409 
4410                         if (!host.zombie || mSafeMode) {
4411                             // In safe mode, we don't discard the hosts we don't recognize
4412                             // so that they're not pruned from our list. Otherwise, we do.
4413                             final int hostId = parser.getAttributeIntHex(null, "id");
4414                             final int hostTag = parser.getAttributeIntHex(null, "tag",
4415                                     legacyHostIndex);
4416 
4417                             host.tag = hostTag;
4418                             host.id = new HostId(uid, hostId, pkg);
4419                             mHosts.add(host);
4420                         }
4421                     } else if ("b".equals(tag)) {
4422                         String packageName = parser.getAttributeValue(null, "packageName");
4423                         final int uid = getUidForPackage(packageName, userId);
4424                         if (uid >= 0) {
4425                             Pair<Integer, String> packageId = Pair.create(userId, packageName);
4426                             mPackagesWithBindWidgetPermission.add(packageId);
4427                         }
4428                     } else if ("g".equals(tag)) {
4429                         Widget widget = new Widget();
4430                         widget.appWidgetId = parser.getAttributeIntHex(null, "id");
4431                         setMinAppWidgetIdLocked(userId, widget.appWidgetId + 1);
4432 
4433                         // restored ID is allowed to be absent
4434                         widget.restoredId = parser.getAttributeIntHex(null, "rid", 0);
4435                         widget.options = parseWidgetIdOptions(parser);
4436 
4437                         final int hostTag = parser.getAttributeIntHex(null, "h");
4438                         String providerString = parser.getAttributeValue(null, "p");
4439                         final int providerTag = (providerString != null)
4440                                 ? parser.getAttributeIntHex(null, "p") : TAG_UNDEFINED;
4441 
4442                         // We can match widgets with hosts and providers only after hosts
4443                         // and providers for all users have been loaded since the widget
4444                         // host and provider can be in different user profiles.
4445                         LoadedWidgetState loadedWidgets = new LoadedWidgetState(widget,
4446                                 hostTag, providerTag);
4447                         outLoadedWidgets.add(loadedWidgets);
4448                     } else if (supportResumeRestoreAfterReboot()
4449                             && AppWidgetXmlUtil.TAG_BACKUP_RESTORE_CONTROLLER_STATE.equals(tag)) {
4450                         final BackupRestoreController.State s =
4451                                 AppWidgetXmlUtil.readBackupRestoreControllerState(parser);
4452                         if (s == null) {
4453                             continue;
4454                         }
4455                         final Set<String> prunedAppsInFile = s.getPrunedApps();
4456                         if (prunedAppsInFile != null) {
4457                             final Set<String> prunedAppsInMemory = mBackupRestoreController
4458                                     .mPrunedAppsPerUser.get(userId);
4459                             if (prunedAppsInMemory == null) {
4460                                 mBackupRestoreController.mPrunedAppsPerUser.put(
4461                                         userId, prunedAppsInFile);
4462                             } else {
4463                                 prunedAppsInMemory.addAll(prunedAppsInFile);
4464                             }
4465                         }
4466                         loadUpdateRecords(s.getUpdatesByProvider(),
4467                                 this::findProviderByTag,
4468                                 mBackupRestoreController.mUpdatesByProvider::get,
4469                                 mBackupRestoreController.mUpdatesByProvider::put);
4470                         loadUpdateRecords(s.getUpdatesByHost(),
4471                                 this::findHostByTag,
4472                                 mBackupRestoreController.mUpdatesByHost::get,
4473                                 mBackupRestoreController.mUpdatesByHost::put);
4474                     }
4475                 }
4476             } while (type != XmlPullParser.END_DOCUMENT);
4477         } catch (NullPointerException
4478                 | NumberFormatException
4479                 | XmlPullParserException
4480                 | IOException
4481                 | IndexOutOfBoundsException e) {
4482             Slog.w(TAG, "failed parsing " + e);
4483             return -1;
4484         }
4485 
4486         return version;
4487     }
4488 
loadUpdateRecords( @ullable final SparseArray< List<BackupRestoreController.RestoreUpdateRecord>> updatesOnFile, @NonNull final Function<Integer, T> findKeyByTagCb, @NonNull final Function<T, List< BackupRestoreController.RestoreUpdateRecord>> findRecordsCb, @NonNull final BiConsumer<T, List< BackupRestoreController.RestoreUpdateRecord>> newRecordsCb)4489     private <T> void loadUpdateRecords(
4490             @Nullable final SparseArray<
4491                     List<BackupRestoreController.RestoreUpdateRecord>> updatesOnFile,
4492             @NonNull final Function<Integer, T> findKeyByTagCb,
4493             @NonNull final Function<T, List<
4494                     BackupRestoreController.RestoreUpdateRecord>> findRecordsCb,
4495             @NonNull final BiConsumer<T, List<
4496                     BackupRestoreController.RestoreUpdateRecord>> newRecordsCb) {
4497         if (updatesOnFile == null) {
4498             return;
4499         }
4500         for (int i = 0; i < updatesOnFile.size(); i++) {
4501             final int tag = updatesOnFile.keyAt(i);
4502             final List<
4503                     BackupRestoreController.RestoreUpdateRecord
4504                     > recordsOnFile = updatesOnFile.get(tag);
4505             if (recordsOnFile == null || recordsOnFile.isEmpty()) {
4506                 continue;
4507             }
4508             final T key = findKeyByTagCb.apply(tag);
4509             final List<BackupRestoreController.RestoreUpdateRecord> recordsInMemory =
4510                     findRecordsCb.apply(key);
4511             if (recordsInMemory != null) {
4512                 recordsInMemory.addAll(recordsOnFile);
4513             } else  {
4514                 newRecordsCb.accept(key, recordsOnFile);
4515             }
4516         }
4517     }
4518 
performUpgradeLocked(int fromVersion)4519     private void performUpgradeLocked(int fromVersion) {
4520         if (fromVersion < CURRENT_VERSION) {
4521             Slog.v(TAG, "Upgrading widget database from " + fromVersion + " to "
4522                     + CURRENT_VERSION);
4523         }
4524 
4525         int version = fromVersion;
4526 
4527         // Update 1: From version 0 to 1, was used from Android 4 to Android 5. It updated the
4528         // location of the keyguard widget database. No modern device will have db version 0.
4529         if (version == 0) {
4530             Slog.e(TAG, "Found widget database with version 0, this should not be possible,"
4531                     + " forcing upgrade to version 1");
4532 
4533             version = 1;
4534         }
4535 
4536         if (version != CURRENT_VERSION) {
4537             throw new IllegalStateException("Failed to upgrade widget database");
4538         }
4539     }
4540 
getSavedStateFile(int userId)4541     private static AtomicFile getSavedStateFile(int userId) {
4542         return new AtomicFile(new File(Environment.getUserSystemDirectory(userId), STATE_FILENAME));
4543     }
4544 
onUserStopped(int userId)4545     void onUserStopped(int userId) {
4546         if (DEBUG) {
4547             Slog.i(TAG, "onUserStopped() " + userId);
4548         }
4549         synchronized (mLock) {
4550             boolean crossProfileWidgetsChanged = false;
4551 
4552             // Remove widgets that have both host and provider in the user.
4553             final int widgetCount = mWidgets.size();
4554             for (int i = widgetCount - 1; i >= 0; i--) {
4555                 Widget widget = mWidgets.get(i);
4556 
4557                 final boolean hostInUser = widget.host.getUserId() == userId;
4558                 final boolean hasProvider = widget.provider != null;
4559                 final boolean providerInUser = hasProvider && widget.provider.getUserId() == userId;
4560 
4561                 // If both host and provider are in the user, just drop the widgets
4562                 // as we do not want to make host callbacks and provider broadcasts
4563                 // as the host and the provider will be killed.
4564                 if (hostInUser && (!hasProvider || providerInUser)) {
4565                     removeWidgetLocked(widget);
4566                     widget.host.widgets.remove(widget);
4567                     widget.host = null;
4568                     if (hasProvider) {
4569                         widget.provider.widgets.remove(widget);
4570                         widget.provider = null;
4571                     }
4572                 }
4573             }
4574 
4575             // Remove hosts and notify providers in other profiles.
4576             final int hostCount = mHosts.size();
4577             for (int i = hostCount - 1; i >= 0; i--) {
4578                 Host host = mHosts.get(i);
4579                 if (host.getUserId() == userId) {
4580                     crossProfileWidgetsChanged |= !host.widgets.isEmpty();
4581                     deleteHostLocked(host);
4582                 }
4583             }
4584 
4585             // Leave the providers present as hosts will show the widgets
4586             // masked while the user is stopped.
4587 
4588             // Remove grants for this user.
4589             final int grantCount = mPackagesWithBindWidgetPermission.size();
4590             for (int i = grantCount - 1; i >= 0; i--) {
4591                 Pair<Integer, String> packageId = mPackagesWithBindWidgetPermission.valueAt(i);
4592                 if (packageId.first == userId) {
4593                     mPackagesWithBindWidgetPermission.removeAt(i);
4594                 }
4595             }
4596 
4597             // Take a note we no longer have state for this user.
4598             final int userIndex = mLoadedUserIds.indexOfKey(userId);
4599             if (userIndex >= 0) {
4600                 mLoadedUserIds.removeAt(userIndex);
4601             }
4602 
4603             // Remove the widget id counter.
4604             final int nextIdIndex = mNextAppWidgetIds.indexOfKey(userId);
4605             if (nextIdIndex >= 0) {
4606                 mNextAppWidgetIds.removeAt(nextIdIndex);
4607             }
4608 
4609             // Save state if removing a profile changed the group state.
4610             // Nothing will be saved if the group parent was removed.
4611             if (crossProfileWidgetsChanged) {
4612                 saveGroupStateAsync(userId);
4613             }
4614         }
4615     }
4616 
applyResourceOverlaysToWidgetsLocked(Set<String> packageNames, int userId, boolean updateFrameworkRes)4617     private void applyResourceOverlaysToWidgetsLocked(Set<String> packageNames, int userId,
4618             boolean updateFrameworkRes) {
4619         for (int i = 0, N = mProviders.size(); i < N; i++) {
4620             Provider provider = mProviders.get(i);
4621             if (provider.getUserId() != userId) {
4622                 continue;
4623             }
4624 
4625             final String packageName = provider.id.componentName.getPackageName();
4626             if (!updateFrameworkRes && !packageNames.contains(packageName)) {
4627                 continue;
4628             }
4629 
4630             ApplicationInfo newAppInfo = null;
4631             try {
4632                 newAppInfo = mPackageManager.getApplicationInfo(packageName,
4633                         PackageManager.GET_SHARED_LIBRARY_FILES, userId);
4634             } catch (RemoteException e) {
4635                 Slog.w(TAG, "Failed to retrieve app info for " + packageName
4636                         + " userId=" + userId, e);
4637             }
4638             if (newAppInfo == null || provider.info == null
4639                     || provider.info.providerInfo == null) {
4640                 continue;
4641             }
4642             ApplicationInfo oldAppInfo = provider.info.providerInfo.applicationInfo;
4643             if (oldAppInfo == null || !newAppInfo.sourceDir.equals(oldAppInfo.sourceDir)) {
4644                 // Overlay paths are generated against a particular version of an application.
4645                 // The overlays paths of a newly upgraded application are incompatible with the
4646                 // old version of the application.
4647                 continue;
4648             }
4649 
4650             // Isolate the changes relating to RROs. The app info must be copied to prevent
4651             // affecting other parts of system server that may have cached this app info.
4652             oldAppInfo = new ApplicationInfo(oldAppInfo);
4653             oldAppInfo.overlayPaths = newAppInfo.overlayPaths == null
4654                     ? null : newAppInfo.overlayPaths.clone();
4655             oldAppInfo.resourceDirs = newAppInfo.resourceDirs == null
4656                     ? null : newAppInfo.resourceDirs.clone();
4657             provider.info.providerInfo.applicationInfo = oldAppInfo;
4658 
4659             for (int j = 0, M = provider.widgets.size(); j < M; j++) {
4660                 Widget widget = provider.widgets.get(j);
4661                 if (widget.views != null) {
4662                     widget.views.updateAppInfo(oldAppInfo);
4663                 }
4664                 if (widget.maskedViews != null) {
4665                     widget.maskedViews.updateAppInfo(oldAppInfo);
4666                 }
4667             }
4668         }
4669     }
4670 
4671     /**
4672      * Updates all providers with the specified package names, and records any providers that were
4673      * pruned.
4674      *
4675      * @return whether any providers were updated
4676      */
4677     @GuardedBy("mLock")
updateProvidersForPackageLocked(String packageName, int userId, Set<ProviderId> removedProviders)4678     private boolean updateProvidersForPackageLocked(String packageName, int userId,
4679             Set<ProviderId> removedProviders) {
4680         boolean providersUpdated = false;
4681 
4682         HashSet<ProviderId> keep = new HashSet<>();
4683         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
4684         intent.setPackage(packageName);
4685         List<ResolveInfo> broadcastReceivers = queryIntentReceivers(intent, userId);
4686 
4687         // add the missing ones and collect which ones to keep
4688         int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
4689         for (int i = 0; i < N; i++) {
4690             ResolveInfo ri = broadcastReceivers.get(i);
4691             ActivityInfo ai = ri.activityInfo;
4692 
4693             if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
4694                 continue;
4695             }
4696 
4697             if (packageName.equals(ai.packageName)) {
4698                 ProviderId providerId = new ProviderId(ai.applicationInfo.uid,
4699                         new ComponentName(ai.packageName, ai.name));
4700 
4701                 Provider provider = lookupProviderLocked(providerId);
4702                 if (provider == null) {
4703                     if (addProviderLocked(ri)) {
4704                         keep.add(providerId);
4705                         providersUpdated = true;
4706                     }
4707                 } else {
4708                     AppWidgetProviderInfo info =
4709                             createPartialProviderInfo(providerId, ri, provider);
4710                     if (info != null) {
4711                         keep.add(providerId);
4712                         // Use the new AppWidgetProviderInfo.
4713                         provider.setPartialInfoLocked(info);
4714                         // If it's enabled
4715                         final int M = provider.widgets.size();
4716                         if (M > 0) {
4717                             int[] appWidgetIds = getWidgetIds(provider.widgets);
4718                             // Reschedule for the new updatePeriodMillis (don't worry about handling
4719                             // it specially if updatePeriodMillis didn't change because we just sent
4720                             // an update, and the next one will be updatePeriodMillis from now).
4721                             cancelBroadcastsLocked(provider);
4722                             registerForBroadcastsLocked(provider, appWidgetIds);
4723                             // If it's currently showing, call back with the new
4724                             // AppWidgetProviderInfo.
4725                             for (int j = 0; j < M; j++) {
4726                                 Widget widget = provider.widgets.get(j);
4727                                 widget.views = null;
4728                                 scheduleNotifyProviderChangedLocked(widget);
4729                             }
4730                             // Now that we've told the host, push out an update.
4731                             sendUpdateIntentLocked(provider, appWidgetIds, false);
4732                         }
4733                     }
4734                     providersUpdated = true;
4735                 }
4736             }
4737         }
4738 
4739         // prune the ones we don't want to keep
4740         N = mProviders.size();
4741         for (int i = N - 1; i >= 0; i--) {
4742             Provider provider = mProviders.get(i);
4743             if (packageName.equals(provider.id.componentName.getPackageName())
4744                     && provider.getUserId() == userId
4745                     && !keep.contains(provider.id)) {
4746                 if (removedProviders != null) {
4747                     removedProviders.add(provider.id);
4748                 }
4749                 deleteProviderLocked(provider);
4750                 providersUpdated = true;
4751             }
4752         }
4753 
4754         return providersUpdated;
4755     }
4756 
4757     // Remove widgets for provider in userId that are hosted in parentUserId
removeWidgetsForPackageLocked(String pkgName, int userId, int parentUserId)4758     private void removeWidgetsForPackageLocked(String pkgName, int userId, int parentUserId) {
4759         final int N = mProviders.size();
4760         for (int i = 0; i < N; ++i) {
4761             Provider provider = mProviders.get(i);
4762             if (pkgName.equals(provider.id.componentName.getPackageName())
4763                     && provider.getUserId() == userId
4764                     && provider.widgets.size() > 0) {
4765                 deleteWidgetsLocked(provider, parentUserId);
4766             }
4767         }
4768     }
4769 
removeProvidersForPackageLocked(String pkgName, int userId)4770     private boolean removeProvidersForPackageLocked(String pkgName, int userId) {
4771         boolean removed = false;
4772 
4773         final int N = mProviders.size();
4774         for (int i = N - 1; i >= 0; i--) {
4775             Provider provider = mProviders.get(i);
4776             if (pkgName.equals(provider.id.componentName.getPackageName())
4777                     && provider.getUserId() == userId) {
4778                 deleteProviderLocked(provider);
4779                 removed = true;
4780             }
4781         }
4782         return removed;
4783     }
4784 
removeHostsAndProvidersForPackageLocked(String pkgName, int userId)4785     private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) {
4786         if (DEBUG) {
4787             Slog.i(TAG, "removeHostsAndProvidersForPackageLocked() pkg=" + pkgName
4788                     + " userId=" + userId);
4789         }
4790         boolean removed = removeProvidersForPackageLocked(pkgName, userId);
4791 
4792         // Delete the hosts for this package too
4793         // By now, we have removed any AppWidgets that were in any hosts here,
4794         // so we don't need to worry about sending DISABLE broadcasts to them.
4795         final int N = mHosts.size();
4796         for (int i = N - 1; i >= 0; i--) {
4797             Host host = mHosts.get(i);
4798             if (pkgName.equals(host.id.packageName)
4799                     && host.getUserId() == userId) {
4800                 deleteHostLocked(host);
4801                 removed = true;
4802             }
4803         }
4804 
4805         return removed;
4806     }
4807 
getCanonicalPackageName(String packageName, String className, int userId)4808     private String getCanonicalPackageName(String packageName, String className, int userId) {
4809         final long identity = Binder.clearCallingIdentity();
4810         try {
4811             try {
4812                 AppGlobals.getPackageManager().getReceiverInfo(new ComponentName(packageName,
4813                         className), 0, userId);
4814                 return packageName;
4815             } catch (RemoteException re) {
4816                 String[] packageNames = mContext.getPackageManager()
4817                         .currentToCanonicalPackageNames(new String[]{packageName});
4818                 if (packageNames != null && packageNames.length > 0) {
4819                     return packageNames[0];
4820                 }
4821             }
4822         } finally {
4823             Binder.restoreCallingIdentity(identity);
4824         }
4825         return null;
4826     }
4827 
4828     /**
4829      * Sends a widget lifecycle broadcast within the specified user.  If {@code isInteractive}
4830      * is specified as {@code true}, the broadcast dispatch mechanism will be told that it
4831      * is related to a UX flow with user-visible expectations about timely dispatch.  This
4832      * should only be used for broadcast flows that do have such expectations.
4833      */
sendBroadcastAsUser(Intent intent, UserHandle userHandle, boolean isInteractive)4834     private void sendBroadcastAsUser(Intent intent, UserHandle userHandle, boolean isInteractive) {
4835         final long identity = Binder.clearCallingIdentity();
4836         try {
4837             mContext.sendBroadcastAsUser(intent, userHandle, null,
4838                     isInteractive ? mInteractiveBroadcast : null);
4839         } finally {
4840             Binder.restoreCallingIdentity(identity);
4841         }
4842     }
4843 
bindService(Intent intent, ServiceConnection connection, UserHandle userHandle)4844     private void bindService(Intent intent, ServiceConnection connection,
4845             UserHandle userHandle) {
4846         final long token = Binder.clearCallingIdentity();
4847         try {
4848             mContext.bindServiceAsUser(intent, connection,
4849                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
4850                     userHandle);
4851         } finally {
4852             Binder.restoreCallingIdentity(token);
4853         }
4854     }
4855 
unbindService(ServiceConnection connection)4856     private void unbindService(ServiceConnection connection) {
4857         final long token = Binder.clearCallingIdentity();
4858         try {
4859             mContext.unbindService(connection);
4860         } finally {
4861             Binder.restoreCallingIdentity(token);
4862         }
4863     }
4864 
4865     /**
4866      * Callback functions that add/update/remove widget providers in respect to
4867      * changes in a specific child profile (e.g. deleting a work profile)
4868      * depicted by DevicePolicyManager.
4869      */
4870     @Override
onCrossProfileWidgetProvidersChanged(int userId, List<String> packages)4871     public void onCrossProfileWidgetProvidersChanged(int userId, List<String> packages) {
4872         final int parentId = mSecurityPolicy.getProfileParent(userId);
4873         // We care only if the allowlisted package is in a profile of
4874         // the group parent as only the parent can add widgets from the
4875         // profile and not the other way around.
4876         if (parentId != userId) {
4877             synchronized (mLock) {
4878                 boolean providersChanged = false;
4879 
4880                 ArraySet<String> previousPackages = new ArraySet<String>();
4881                 final int providerCount = mProviders.size();
4882                 for (int i = 0; i < providerCount; ++i) {
4883                     Provider provider = mProviders.get(i);
4884                     if (provider.getUserId() == userId) {
4885                         previousPackages.add(provider.id.componentName.getPackageName());
4886                     }
4887                 }
4888 
4889                 final int packageCount = packages.size();
4890                 for (int i = 0; i < packageCount; i++) {
4891                     String packageName = packages.get(i);
4892                     previousPackages.remove(packageName);
4893                     providersChanged |= updateProvidersForPackageLocked(packageName,
4894                             userId, null);
4895                 }
4896 
4897                 // Remove widgets from hosts in parent user for packages not in the allowlist
4898                 final int removedCount = previousPackages.size();
4899                 for (int i = 0; i < removedCount; ++i) {
4900                     removeWidgetsForPackageLocked(previousPackages.valueAt(i),
4901                             userId, parentId);
4902                 }
4903 
4904                 if (providersChanged || removedCount > 0) {
4905                     saveGroupStateAsync(userId);
4906                     scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
4907                 }
4908             }
4909         }
4910     }
4911 
isProfileWithLockedParent(int userId)4912     private boolean isProfileWithLockedParent(int userId) {
4913         final long token = Binder.clearCallingIdentity();
4914         try {
4915             UserInfo userInfo = mUserManager.getUserInfo(userId);
4916             if (userInfo != null && userInfo.isProfile()) {
4917                 UserInfo parentInfo = mUserManager.getProfileParent(userId);
4918                 if (parentInfo != null
4919                         && !isUserRunningAndUnlocked(parentInfo.getUserHandle().getIdentifier())) {
4920                     return true;
4921                 }
4922             }
4923         } finally {
4924             Binder.restoreCallingIdentity(token);
4925         }
4926         return false;
4927     }
4928 
isProfileWithUnlockedParent(int userId)4929     private boolean isProfileWithUnlockedParent(int userId) {
4930         UserInfo userInfo = mUserManager.getUserInfo(userId);
4931         if (userInfo != null && userInfo.isProfile()) {
4932             UserInfo parentInfo = mUserManager.getProfileParent(userId);
4933             if (parentInfo != null
4934                     && mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) {
4935                 return true;
4936             }
4937         }
4938         return false;
4939     }
4940 
4941     /**
4942      * Note an app widget is tapped on. If a app widget is tapped, the underlying app is treated as
4943      * foreground so the app can get while-in-use permission.
4944      *
4945      * @param callingPackage calling app's packageName.
4946      * @param appWidgetId App widget id.
4947      */
4948     @Override
noteAppWidgetTapped(String callingPackage, int appWidgetId)4949     public void noteAppWidgetTapped(String callingPackage, int appWidgetId) {
4950         mSecurityPolicy.enforceCallFromPackage(callingPackage);
4951         final int callingUid = Binder.getCallingUid();
4952         final long ident = Binder.clearCallingIdentity();
4953         try {
4954             // The launcher must be at TOP.
4955             final int procState = mActivityManagerInternal.getUidProcessState(callingUid);
4956             if (procState > ActivityManager.PROCESS_STATE_TOP) {
4957                 return;
4958             }
4959             synchronized (mLock) {
4960                 final Widget widget = lookupWidgetLocked(appWidgetId, callingUid, callingPackage);
4961                 if (widget == null) {
4962                     return;
4963                 }
4964                 final ProviderId providerId = widget.provider.id;
4965                 final String packageName = providerId.componentName.getPackageName();
4966                 if (packageName == null) {
4967                     return;
4968                 }
4969                 final SparseArray<String> uid2PackageName = new SparseArray<String>();
4970                 uid2PackageName.put(providerId.uid, packageName);
4971                 mAppOpsManagerInternal.updateAppWidgetVisibility(uid2PackageName, true);
4972                 reportWidgetInteractionEvent(packageName, UserHandle.getUserId(providerId.uid),
4973                         "tap");
4974             }
4975         } finally {
4976             Binder.restoreCallingIdentity(ident);
4977         }
4978     }
4979 
reportWidgetInteractionEvent(@onNull String packageName, @UserIdInt int userId, @NonNull String action)4980     private void reportWidgetInteractionEvent(@NonNull String packageName, @UserIdInt int userId,
4981             @NonNull String action) {
4982         if (Flags.userInteractionTypeApi()) {
4983             PersistableBundle extras = new PersistableBundle();
4984             extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "android.appwidget");
4985             extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, action);
4986             mUsageStatsManagerInternal.reportUserInteractionEvent(packageName, userId, extras);
4987         } else {
4988             mUsageStatsManagerInternal.reportEvent(packageName, userId,
4989                     UsageEvents.Event.USER_INTERACTION);
4990         }
4991     }
4992 
4993     @Override
4994     @Nullable
getWidgetPreview(@onNull String callingPackage, @NonNull ComponentName providerComponent, int profileId, @AppWidgetProviderInfo.CategoryFlags int widgetCategory)4995     public RemoteViews getWidgetPreview(@NonNull String callingPackage,
4996             @NonNull ComponentName providerComponent, int profileId,
4997             @AppWidgetProviderInfo.CategoryFlags int widgetCategory) {
4998         final int callingUserId = UserHandle.getCallingUserId();
4999         if (DEBUG) {
5000             Slog.i(TAG, "getWidgetPreview() " + callingUserId);
5001         }
5002         mSecurityPolicy.enforceCallFromPackage(callingPackage);
5003         ensureWidgetCategoryCombinationIsValid(widgetCategory);
5004 
5005         AndroidFuture<RemoteViews> result = null;
5006         synchronized (mLock) {
5007             ensureGroupStateLoadedLocked(profileId);
5008             final int providerCount = mProviders.size();
5009             for (int i = 0; i < providerCount; i++) {
5010                 Provider provider = mProviders.get(i);
5011                 final ComponentName componentName = provider.id.componentName;
5012                 if (provider.zombie || !providerComponent.equals(componentName)) {
5013                     continue;
5014                 }
5015 
5016                 final AppWidgetProviderInfo info = provider.getInfoLocked(mContext);
5017                 final int providerProfileId = info.getProfile().getIdentifier();
5018                 if (providerProfileId != profileId) {
5019                     continue;
5020                 }
5021 
5022                 // Allow access to this provider if it is from the calling package or the caller has
5023                 // BIND_APPWIDGET permission.
5024                 final int callingUid = Binder.getCallingUid();
5025                 final String providerPackageName = componentName.getPackageName();
5026                 final boolean providerIsInCallerProfile =
5027                         mSecurityPolicy.canAccessProvider(
5028                                 providerPackageName, providerProfileId);
5029                 final boolean shouldFilterAppAccess = mPackageManagerInternal.filterAppAccess(
5030                         providerPackageName, callingUid, providerProfileId);
5031                 final boolean providerIsInCallerPackage =
5032                         mSecurityPolicy.isProviderInPackageForUid(provider, callingUid,
5033                                 callingPackage);
5034                 final boolean hasBindAppWidgetPermission =
5035                         mSecurityPolicy.hasCallerBindPermissionOrBindWhiteListedLocked(
5036                                 callingPackage);
5037                 if (providerIsInCallerProfile && !shouldFilterAppAccess
5038                         && (providerIsInCallerPackage || hasBindAppWidgetPermission)) {
5039                     if (remoteViewsProto()) {
5040                         result = getGeneratedPreviewsAsync(provider, widgetCategory);
5041                     } else {
5042                         return provider.getGeneratedPreviewLocked(widgetCategory);
5043                     }
5044                 }
5045             }
5046         }
5047 
5048         if (result != null) {
5049             try {
5050                 return result.get();
5051             } catch (Exception e) {
5052                 Slog.e(TAG, "Failed to get generated previews Future result", e);
5053                 return null;
5054             }
5055         }
5056         // Either the provider does not exist or the caller does not have permission to access its
5057         // previews.
5058         return null;
5059     }
5060 
5061     @Override
setWidgetPreview(@onNull ComponentName providerComponent, @AppWidgetProviderInfo.CategoryFlags int widgetCategories, @NonNull RemoteViews preview)5062     public boolean setWidgetPreview(@NonNull ComponentName providerComponent,
5063             @AppWidgetProviderInfo.CategoryFlags int widgetCategories,
5064             @NonNull RemoteViews preview) {
5065         final int userId = UserHandle.getCallingUserId();
5066         if (DEBUG) {
5067             Slog.i(TAG, "setWidgetPreview() " + userId);
5068         }
5069 
5070         // Make sure callers only set previews for their own package.
5071         mSecurityPolicy.enforceCallFromPackage(providerComponent.getPackageName());
5072 
5073         ensureWidgetCategoryCombinationIsValid(widgetCategories);
5074 
5075         synchronized (mLock) {
5076             ensureGroupStateLoadedLocked(userId);
5077 
5078             final ProviderId providerId = new ProviderId(Binder.getCallingUid(), providerComponent);
5079             final Provider provider = lookupProviderLocked(providerId);
5080             if (provider == null) {
5081                 throw new IllegalArgumentException(
5082                         providerComponent + " is not a valid AppWidget provider");
5083             }
5084             if (mGeneratedPreviewsApiCounter.tryApiCall(providerId)) {
5085                 if (remoteViewsProto()) {
5086                     setGeneratedPreviewsAsync(provider, widgetCategories, preview);
5087                 } else {
5088                     provider.setGeneratedPreviewLocked(widgetCategories, preview);
5089                     scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
5090                 }
5091                 return true;
5092             }
5093             return false;
5094         }
5095     }
5096 
5097     @Override
removeWidgetPreview(@onNull ComponentName providerComponent, @AppWidgetProviderInfo.CategoryFlags int widgetCategories)5098     public void removeWidgetPreview(@NonNull ComponentName providerComponent,
5099             @AppWidgetProviderInfo.CategoryFlags int widgetCategories) {
5100         final int userId = UserHandle.getCallingUserId();
5101         if (DEBUG) {
5102             Slog.i(TAG, "removeWidgetPreview() " + userId);
5103         }
5104 
5105         // Make sure callers only remove previews for their own package.
5106         mSecurityPolicy.enforceCallFromPackage(providerComponent.getPackageName());
5107 
5108         ensureWidgetCategoryCombinationIsValid(widgetCategories);
5109         synchronized (mLock) {
5110             ensureGroupStateLoadedLocked(userId);
5111 
5112             final ProviderId providerId = new ProviderId(Binder.getCallingUid(), providerComponent);
5113             final Provider provider = lookupProviderLocked(providerId);
5114             if (provider == null) {
5115                 throw new IllegalArgumentException(
5116                         providerComponent + " is not a valid AppWidget provider");
5117             }
5118 
5119             if (remoteViewsProto()) {
5120                 removeGeneratedPreviewsAsync(provider, widgetCategories);
5121             } else {
5122                 final boolean changed = provider.removeGeneratedPreviewLocked(widgetCategories);
5123                 if (changed) scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
5124             }
5125         }
5126     }
5127 
5128     /**
5129      * Return previews for the specified provider from a background thread. The result of the future
5130      * is nullable.
5131      */
5132     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
5133     @NonNull
getGeneratedPreviewsAsync( @onNull Provider provider, @AppWidgetProviderInfo.CategoryFlags int widgetCategory)5134     private AndroidFuture<RemoteViews> getGeneratedPreviewsAsync(
5135             @NonNull Provider provider, @AppWidgetProviderInfo.CategoryFlags int widgetCategory) {
5136         AndroidFuture<RemoteViews> result = new AndroidFuture<>();
5137         mSavePreviewsHandler.post(() -> {
5138             SparseArray<RemoteViews> previews = loadGeneratedPreviews(provider);
5139             if (previews.size() == 0 && provider.info.generatedPreviewCategories != 0) {
5140                 // Failed to read previews from file, clear the file and update providers.
5141                 saveGeneratedPreviews(provider, previews, /* notify= */ true);
5142             }
5143             for (int i = 0; i < previews.size(); i++) {
5144                 if ((widgetCategory & previews.keyAt(i)) != 0) {
5145                     result.complete(previews.valueAt(i));
5146                     return;
5147                 }
5148             }
5149             result.complete(null);
5150         });
5151         return result;
5152     }
5153 
5154     /**
5155      * Set previews for the specified provider on a background thread.
5156      */
5157     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
setGeneratedPreviewsAsync(@onNull Provider provider, int widgetCategories, @NonNull RemoteViews preview)5158     private void setGeneratedPreviewsAsync(@NonNull Provider provider, int widgetCategories,
5159             @NonNull RemoteViews preview) {
5160         mSavePreviewsHandler.post(() -> {
5161             SparseArray<RemoteViews> previews = loadGeneratedPreviews(provider);
5162             for (int flag : Provider.WIDGET_CATEGORY_FLAGS) {
5163                 if ((widgetCategories & flag) != 0) {
5164                     previews.put(flag, preview);
5165                 }
5166             }
5167             saveGeneratedPreviews(provider, previews, /* notify= */ true);
5168         });
5169     }
5170 
5171     /**
5172      * Remove previews for the specified provider on a background thread.
5173      */
5174     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
removeGeneratedPreviewsAsync(@onNull Provider provider, int widgetCategories)5175     private void removeGeneratedPreviewsAsync(@NonNull Provider provider, int widgetCategories) {
5176         mSavePreviewsHandler.post(() -> {
5177             SparseArray<RemoteViews> previews = loadGeneratedPreviews(provider);
5178             boolean changed = false;
5179             for (int flag : Provider.WIDGET_CATEGORY_FLAGS) {
5180                 if ((widgetCategories & flag) != 0) {
5181                     changed |= previews.removeReturnOld(flag) != null;
5182                 }
5183             }
5184             if (changed) {
5185                 saveGeneratedPreviews(provider, previews, /* notify= */ true);
5186             }
5187         });
5188     }
5189 
5190     /**
5191      * Clear previews for the specified provider on a background thread. Returns true if changed
5192      * (i.e. there are previews to clear). If returns true, the caller should schedule a providers
5193      * changed notification.
5194      */
5195     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
clearGeneratedPreviewsAsync(@onNull Provider provider)5196     private boolean clearGeneratedPreviewsAsync(@NonNull Provider provider) {
5197         mSavePreviewsHandler.post(() -> {
5198             saveGeneratedPreviews(provider, /* previews= */ null, /* notify= */ false);
5199         });
5200         return provider.info.generatedPreviewCategories != 0;
5201     }
5202 
checkSavePreviewsThread()5203     private void checkSavePreviewsThread() {
5204         if (DEBUG && !mSavePreviewsHandler.getLooper().isCurrentThread()) {
5205             throw new IllegalStateException("Only modify previews on the background thread");
5206         }
5207     }
5208 
5209     /**
5210      * Load previews from file for the given provider. If there are no previews, returns an empty
5211      * SparseArray. Else, returns a SparseArray of the previews mapped by widget category.
5212      */
5213     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
5214     @NonNull
loadGeneratedPreviews(@onNull Provider provider)5215     private SparseArray<RemoteViews> loadGeneratedPreviews(@NonNull Provider provider) {
5216         checkSavePreviewsThread();
5217         try {
5218             AtomicFile previewsFile = getWidgetPreviewsFile(provider);
5219             if (!previewsFile.exists()) {
5220                 return new SparseArray<>();
5221             }
5222             ProtoInputStream input = new ProtoInputStream(previewsFile.readFully());
5223             SparseArray<RemoteViews> entries = readGeneratedPreviewsFromProto(input);
5224             SparseArray<RemoteViews> singleCategoryKeyedEntries = new SparseArray<>();
5225             for (int i = 0; i < entries.size(); i++) {
5226                 int widgetCategories = entries.keyAt(i);
5227                 RemoteViews preview = entries.valueAt(i);
5228                 for (int flag : Provider.WIDGET_CATEGORY_FLAGS) {
5229                     if ((widgetCategories & flag) != 0) {
5230                         singleCategoryKeyedEntries.put(flag, preview);
5231                     }
5232                 }
5233             }
5234             return singleCategoryKeyedEntries;
5235         } catch (Exception e) {
5236             Slog.e(TAG, "Failed to load generated previews for " + provider, e);
5237             return new SparseArray<>();
5238         }
5239     }
5240 
5241     /**
5242      * This is called when loading profile/group state to populate
5243      * AppWidgetProviderInfo.generatedPreviewCategories based on what previews are saved.
5244      *
5245      * This is the only time previews are read while not on mSavePreviewsHandler. It happens once
5246      * per profile during initialization, before any calls to get/set/removeWidgetPreviewAsync
5247      * happen for that profile.
5248      */
5249     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
5250     @GuardedBy("mLock")
loadGeneratedPreviewCategoriesLocked(int profileId)5251     private void loadGeneratedPreviewCategoriesLocked(int profileId) throws IOException {
5252         for (Provider provider : mProviders) {
5253             if (provider.id.getProfile().getIdentifier() != profileId) {
5254                 continue;
5255             }
5256             AtomicFile previewsFile = getWidgetPreviewsFile(provider);
5257             if (!previewsFile.exists()) {
5258                 continue;
5259             }
5260             ProtoInputStream input = new ProtoInputStream(previewsFile.readFully());
5261             try {
5262                 provider.info.generatedPreviewCategories = readGeneratedPreviewCategoriesFromProto(
5263                         input);
5264             } catch (Exception e) {
5265                 Slog.e(TAG, "Failed to read generated previews from file for " + provider, e);
5266                 previewsFile.delete();
5267                 provider.info.generatedPreviewCategories = 0;
5268             }
5269             if (DEBUG) {
5270                 Slog.i(TAG, TextUtils.formatSimple(
5271                         "loadGeneratedPreviewCategoriesLocked %d %s categories %d", profileId,
5272                         provider, provider.info.generatedPreviewCategories));
5273             }
5274         }
5275     }
5276 
5277     /**
5278      * Save the given previews into storage.
5279      *
5280      * @param provider Provider for which to save previews
5281      * @param previews Previews to save. If null or empty, clears any saved previews for this
5282      *                 provider.
5283      * @param notify If true, then this function will notify hosts of updated provider info.
5284      */
5285     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
saveGeneratedPreviews(@onNull Provider provider, @Nullable SparseArray<RemoteViews> previews, boolean notify)5286     private void saveGeneratedPreviews(@NonNull Provider provider,
5287             @Nullable SparseArray<RemoteViews> previews, boolean notify) {
5288         checkSavePreviewsThread();
5289         AtomicFile file = null;
5290         FileOutputStream stream = null;
5291         try {
5292             file = getWidgetPreviewsFile(provider);
5293             if (previews == null || previews.size() == 0) {
5294                 if (file.exists()) {
5295                     if (DEBUG) {
5296                         Slog.i(TAG, "Deleting widget preview file " + file);
5297                     }
5298                     file.delete();
5299                 }
5300             } else {
5301                 if (DEBUG) {
5302                     Slog.i(TAG, "Writing widget preview file " + file);
5303                 }
5304                 ProtoOutputStream out = new ProtoOutputStream();
5305                 writePreviewsToProto(out, previews);
5306                 stream = file.startWrite();
5307                 stream.write(out.getBytes());
5308                 file.finishWrite(stream);
5309             }
5310 
5311             synchronized (mLock) {
5312                 provider.updateGeneratedPreviewCategoriesLocked(previews);
5313                 if (notify) {
5314                     scheduleNotifyGroupHostsForProvidersChangedLocked(provider.getUserId());
5315                 }
5316             }
5317         } catch (Exception e) {
5318             if (file != null && stream != null) {
5319                 file.failWrite(stream);
5320             }
5321             Slog.w(TAG, "Failed to save widget previews for provider " + provider.id.componentName);
5322         }
5323     }
5324 
5325 
5326     /**
5327      * Write the given previews as a GeneratedPreviewsProto to the output stream.
5328      */
5329     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
writePreviewsToProto(@onNull ProtoOutputStream out, @NonNull SparseArray<RemoteViews> generatedPreviews)5330     private void writePreviewsToProto(@NonNull ProtoOutputStream out,
5331             @NonNull SparseArray<RemoteViews> generatedPreviews) {
5332         // Collect RemoteViews mapped by hashCode in order to avoid writing duplicates.
5333         SparseArray<Pair<Integer, RemoteViews>> previewsToWrite = new SparseArray<>();
5334         for (int i = 0; i < generatedPreviews.size(); i++) {
5335             int widgetCategory = generatedPreviews.keyAt(i);
5336             RemoteViews views = generatedPreviews.valueAt(i);
5337             if (!previewsToWrite.contains(views.hashCode())) {
5338                 previewsToWrite.put(views.hashCode(), new Pair<>(widgetCategory, views));
5339             } else {
5340                 Pair<Integer, RemoteViews> entry = previewsToWrite.get(views.hashCode());
5341                 previewsToWrite.put(views.hashCode(),
5342                         Pair.create(entry.first | widgetCategory, views));
5343             }
5344         }
5345 
5346         for (int i = 0; i < previewsToWrite.size(); i++) {
5347             final long token = out.start(GeneratedPreviewsProto.PREVIEWS);
5348             Pair<Integer, RemoteViews> entry = previewsToWrite.valueAt(i);
5349             out.write(GeneratedPreviewsProto.Preview.WIDGET_CATEGORIES, entry.first);
5350             final long viewsToken = out.start(GeneratedPreviewsProto.Preview.VIEWS);
5351             entry.second.writePreviewToProto(mContext, out);
5352             out.end(viewsToken);
5353             out.end(token);
5354         }
5355     }
5356 
5357     /**
5358      * Read a GeneratedPreviewsProto message from the input stream.
5359      */
5360     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
5361     @NonNull
readGeneratedPreviewsFromProto(@onNull ProtoInputStream input)5362     private SparseArray<RemoteViews> readGeneratedPreviewsFromProto(@NonNull ProtoInputStream input)
5363             throws IOException {
5364         SparseArray<RemoteViews> entries = new SparseArray<>();
5365         while (input.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
5366             switch (input.getFieldNumber()) {
5367                 case (int) GeneratedPreviewsProto.PREVIEWS:
5368                     final long token = input.start(GeneratedPreviewsProto.PREVIEWS);
5369                     Pair<Integer, RemoteViews> entry = readSinglePreviewFromProto(input,
5370                             /* skipViews= */ false);
5371                     entries.put(entry.first, entry.second);
5372                     input.end(token);
5373                     break;
5374                 default:
5375                     Slog.w(TAG, "Unknown field while reading GeneratedPreviewsProto! "
5376                             + ProtoUtils.currentFieldToString(input));
5377             }
5378         }
5379         return entries;
5380     }
5381 
5382     /**
5383      * Read the widget categories from GeneratedPreviewsProto and return an int representing the
5384      * combined widget categories of all the previews.
5385      */
5386     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
5387     @AppWidgetProviderInfo.CategoryFlags
readGeneratedPreviewCategoriesFromProto(@onNull ProtoInputStream input)5388     private int readGeneratedPreviewCategoriesFromProto(@NonNull ProtoInputStream input)
5389             throws IOException {
5390         int widgetCategories = 0;
5391         while (input.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
5392             switch (input.getFieldNumber()) {
5393                 case (int) GeneratedPreviewsProto.PREVIEWS:
5394                     final long token = input.start(GeneratedPreviewsProto.PREVIEWS);
5395                     Pair<Integer, RemoteViews> entry = readSinglePreviewFromProto(input,
5396                             /* skipViews= */ true);
5397                     widgetCategories |= entry.first;
5398                     input.end(token);
5399                     break;
5400                 default:
5401                     Slog.w(TAG, "Unknown field while reading GeneratedPreviewsProto! "
5402                             + ProtoUtils.currentFieldToString(input));
5403             }
5404         }
5405         return widgetCategories;
5406     }
5407 
5408     /**
5409      * Read a single GeneratedPreviewsProto.Preview message from the input stream, and returns a
5410      * pair of widget category and corresponding RemoteViews. If skipViews is true, this function
5411      * will only read widget categories and the returned RemoteViews will be null.
5412      */
5413     @FlaggedApi(android.appwidget.flags.Flags.FLAG_REMOTE_VIEWS_PROTO)
5414     @NonNull
readSinglePreviewFromProto(@onNull ProtoInputStream input, boolean skipViews)5415     private Pair<Integer, RemoteViews> readSinglePreviewFromProto(@NonNull ProtoInputStream input,
5416             boolean skipViews) throws IOException {
5417         int widgetCategories = 0;
5418         RemoteViews views = null;
5419         while (input.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
5420             switch (input.getFieldNumber()) {
5421                 case (int) GeneratedPreviewsProto.Preview.VIEWS:
5422                     if (skipViews)  {
5423                         // ProtoInputStream will skip over the nested message when nextField() is
5424                         // called.
5425                         continue;
5426                     }
5427                     final long token = input.start(GeneratedPreviewsProto.Preview.VIEWS);
5428                     try {
5429                         views = RemoteViews.createPreviewFromProto(mContext, input);
5430                     } catch (Exception e) {
5431                         Slog.e(TAG, "Unable to deserialize RemoteViews", e);
5432                     }
5433                     input.end(token);
5434                     break;
5435                 case (int) GeneratedPreviewsProto.Preview.WIDGET_CATEGORIES:
5436                     widgetCategories = input.readInt(
5437                             GeneratedPreviewsProto.Preview.WIDGET_CATEGORIES);
5438                     break;
5439                 default:
5440                     Slog.w(TAG, "Unknown field while reading GeneratedPreviewsProto! "
5441                             + ProtoUtils.currentFieldToString(input));
5442             }
5443         }
5444         return Pair.create(widgetCategories, views);
5445     }
5446 
5447     /**
5448      * Returns the file in which all generated previews for this provider are stored. This will be
5449      * a path of the form:
5450      *  {@literal /data/system_ce/<userId>/appwidget/previews/<package>-<class>-<uid>.binpb}
5451      *
5452      * This function will not create the file if it does not already exist.
5453      */
5454     @NonNull
getWidgetPreviewsFile(@onNull Provider provider)5455     private static AtomicFile getWidgetPreviewsFile(@NonNull Provider provider) throws IOException {
5456         int userId = provider.getUserId();
5457         File previewsDirectory = getWidgetPreviewsDirectory(userId);
5458         File providerPreviews = Environment.buildPath(previewsDirectory,
5459                 TextUtils.formatSimple("%s-%s-%d.binpb", provider.id.componentName.getPackageName(),
5460                         provider.id.componentName.getClassName(), provider.id.uid));
5461         return new AtomicFile(providerPreviews);
5462     }
5463 
5464     /**
5465      * Returns the widget previews directory for the given user, creating it if it does not exist.
5466      * This will be a path of the form:
5467      *  {@literal /data/system_ce/<userId>/appwidget/previews}
5468      */
5469     @NonNull
getWidgetPreviewsDirectory(int userId)5470     private static File getWidgetPreviewsDirectory(int userId) throws IOException {
5471         File dataSystemCeDirectory = Environment.getDataSystemCeDirectory(userId);
5472         File previewsDirectory = Environment.buildPath(dataSystemCeDirectory,
5473                 APPWIDGET_CE_DATA_DIRNAME, WIDGET_PREVIEWS_DIRNAME);
5474         if (!previewsDirectory.exists()) {
5475             if (!previewsDirectory.mkdirs()) {
5476                 throw new IOException("Unable to create widget preview directory "
5477                         + previewsDirectory.getPath());
5478             }
5479         }
5480         return previewsDirectory;
5481     }
5482 
ensureWidgetCategoryCombinationIsValid(int widgetCategories)5483     private static void ensureWidgetCategoryCombinationIsValid(int widgetCategories) {
5484         int validCategories = AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
5485                 | AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD
5486                 | AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX;
5487         int invalid = ~validCategories;
5488         if ((widgetCategories & invalid) != 0) {
5489             throw new IllegalArgumentException(widgetCategories
5490                     + " is not a valid widget category combination");
5491         }
5492     }
5493 
handleSystemUiDeviceConfigChange(DeviceConfig.Properties properties)5494     private void handleSystemUiDeviceConfigChange(DeviceConfig.Properties properties) {
5495         Set<String> changed = properties.getKeyset();
5496         synchronized (mLock) {
5497             if (changed.contains(
5498                     SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_RESET_INTERVAL_MS)) {
5499                 long resetIntervalMs = properties.getLong(
5500                         SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_RESET_INTERVAL_MS,
5501                         /* defaultValue= */ mGeneratedPreviewsApiCounter.getResetIntervalMs());
5502                 mGeneratedPreviewsApiCounter.setResetIntervalMs(resetIntervalMs);
5503             }
5504             if (changed.contains(
5505                     SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_CALLS_PER_INTERVAL)) {
5506                 int maxCallsPerInterval = properties.getInt(
5507                         SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_CALLS_PER_INTERVAL,
5508                         /* defaultValue= */ mGeneratedPreviewsApiCounter.getMaxCallsPerInterval());
5509                 mGeneratedPreviewsApiCounter.setMaxCallsPerInterval(maxCallsPerInterval);
5510             }
5511             if (changed.contains(
5512                     SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS)) {
5513                 int maxProviders = properties.getInt(
5514                         SystemUiDeviceConfigFlags.GENERATED_PREVIEW_API_MAX_PROVIDERS,
5515                         /* defaultValue= */ mGeneratedPreviewsApiCounter.getMaxProviders());
5516                 mGeneratedPreviewsApiCounter.setMaxProviders(maxProviders);
5517             }
5518         }
5519     }
5520 
5521     private final class CallbackHandler extends Handler {
5522         public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1;
5523         public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2;
5524         public static final int MSG_NOTIFY_PROVIDERS_CHANGED = 3;
5525         public static final int MSG_NOTIFY_VIEW_DATA_CHANGED = 4;
5526         public static final int MSG_NOTIFY_APP_WIDGET_REMOVED = 5;
5527         public static final int MSG_NOTIFY_UPDATE_APP_WIDGET_DEFERRED = 6;
5528 
CallbackHandler(Looper looper)5529         public CallbackHandler(Looper looper) {
5530             super(looper, null, false);
5531         }
5532 
5533         @Override
handleMessage(Message message)5534         public void handleMessage(Message message) {
5535             switch (message.what) {
5536                 case MSG_NOTIFY_UPDATE_APP_WIDGET: {
5537                     SomeArgs args = (SomeArgs) message.obj;
5538                     Host host = (Host) args.arg1;
5539                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
5540                     RemoteViews views = (RemoteViews) args.arg3;
5541                     long requestId = (Long) args.arg4;
5542                     final int appWidgetId = args.argi1;
5543                     args.recycle();
5544 
5545                     handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views, requestId);
5546                 } break;
5547 
5548                 case MSG_NOTIFY_PROVIDER_CHANGED: {
5549                     SomeArgs args = (SomeArgs) message.obj;
5550                     Host host = (Host) args.arg1;
5551                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
5552                     AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3;
5553                     long requestId = (Long) args.arg4;
5554                     final int appWidgetId = args.argi1;
5555                     args.recycle();
5556 
5557                     handleNotifyProviderChanged(host, callbacks, appWidgetId, info, requestId);
5558                 } break;
5559 
5560                 case MSG_NOTIFY_APP_WIDGET_REMOVED: {
5561                     SomeArgs args = (SomeArgs) message.obj;
5562                     Host host = (Host) args.arg1;
5563                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
5564                     long requestId = (Long) args.arg3;
5565                     final int appWidgetId = args.argi1;
5566                     args.recycle();
5567                     handleNotifyAppWidgetRemoved(host, callbacks, appWidgetId, requestId);
5568                 } break;
5569 
5570                 case MSG_NOTIFY_PROVIDERS_CHANGED: {
5571                     SomeArgs args = (SomeArgs) message.obj;
5572                     Host host = (Host) args.arg1;
5573                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
5574                     args.recycle();
5575 
5576                     handleNotifyProvidersChanged(host, callbacks);
5577                 } break;
5578 
5579                 case MSG_NOTIFY_VIEW_DATA_CHANGED: {
5580                     SomeArgs args = (SomeArgs) message.obj;
5581                     Host host = (Host) args.arg1;
5582                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
5583                     long requestId = (Long) args.arg3;
5584                     final int appWidgetId = args.argi1;
5585                     final int viewId = args.argi2;
5586                     args.recycle();
5587 
5588                     handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId,
5589                             requestId);
5590                 } break;
5591 
5592                 case MSG_NOTIFY_UPDATE_APP_WIDGET_DEFERRED: {
5593                     SomeArgs args = (SomeArgs) message.obj;
5594                     Host host = (Host) args.arg1;
5595                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
5596                     long requestId = (Long) args.arg4;
5597                     final int appWidgetId = args.argi1;
5598                     args.recycle();
5599 
5600                     handleNotifyUpdateAppWidgetDeferred(host, callbacks, appWidgetId, requestId);
5601                 } break;
5602             }
5603         }
5604     }
5605 
5606     private final class SecurityPolicy {
5607 
isEnabledGroupProfile(int profileId)5608         public boolean isEnabledGroupProfile(int profileId) {
5609             final int parentId = UserHandle.getCallingUserId();
5610             return isParentOrProfile(parentId, profileId) && isProfileEnabled(profileId);
5611         }
5612 
getEnabledGroupProfileIds(int userId)5613         public int[] getEnabledGroupProfileIds(int userId) {
5614             final int parentId = getGroupParent(userId);
5615 
5616             final long identity = Binder.clearCallingIdentity();
5617             try {
5618                 return mUserManager.getEnabledProfileIds(parentId);
5619             } finally {
5620                 Binder.restoreCallingIdentity(identity);
5621             }
5622         }
5623 
enforceServiceExistsAndRequiresBindRemoteViewsPermission( ComponentName componentName, int userId)5624         public void enforceServiceExistsAndRequiresBindRemoteViewsPermission(
5625                 ComponentName componentName, int userId) {
5626             final long identity = Binder.clearCallingIdentity();
5627             try {
5628                 ServiceInfo serviceInfo = mPackageManager.getServiceInfo(componentName,
5629                         PackageManager.GET_PERMISSIONS, userId);
5630                 if (serviceInfo == null) {
5631                     throw new SecurityException("Service " + componentName
5632                             + " not installed for user " + userId);
5633                 }
5634                 if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(serviceInfo.permission)) {
5635                     throw new SecurityException("Service " + componentName
5636                             + " in user " + userId + "does not require "
5637                             + android.Manifest.permission.BIND_REMOTEVIEWS);
5638                 }
5639             } catch (RemoteException re) {
5640                 // Local call - shouldn't happen.
5641             } finally {
5642                 Binder.restoreCallingIdentity(identity);
5643             }
5644         }
5645 
enforceModifyAppWidgetBindPermissions(String packageName)5646         public void enforceModifyAppWidgetBindPermissions(String packageName) {
5647             mContext.enforceCallingPermission(
5648                     android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS,
5649                     "hasBindAppWidgetPermission packageName=" + packageName);
5650         }
5651 
isCallerInstantAppLocked()5652         public boolean isCallerInstantAppLocked() {
5653             final int callingUid =  Binder.getCallingUid();
5654             final long identity = Binder.clearCallingIdentity();
5655             try {
5656                 final String[] uidPackages = mPackageManager.getPackagesForUid(callingUid);
5657                 if (!ArrayUtils.isEmpty(uidPackages)) {
5658                     return mPackageManager.isInstantApp(uidPackages[0],
5659                             UserHandle.getUserId(callingUid));
5660                 }
5661             } catch (RemoteException e) {
5662                 /* ignore - same process */
5663             } finally {
5664                 Binder.restoreCallingIdentity(identity);
5665             }
5666             return false;
5667         }
5668 
isInstantAppLocked(String packageName, int userId)5669         public boolean isInstantAppLocked(String packageName, int userId) {
5670             final long identity = Binder.clearCallingIdentity();
5671             try {
5672                 return mPackageManager.isInstantApp(packageName, userId);
5673             } catch (RemoteException e) {
5674                 /* ignore - same process */
5675             } finally {
5676                 Binder.restoreCallingIdentity(identity);
5677             }
5678             return false;
5679         }
5680 
enforceCallFromPackage(String packageName)5681         public void enforceCallFromPackage(String packageName) {
5682             mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
5683         }
5684 
hasCallerBindPermissionOrBindWhiteListedLocked(String packageName)5685         public boolean hasCallerBindPermissionOrBindWhiteListedLocked(String packageName) {
5686             try {
5687                 mContext.enforceCallingOrSelfPermission(
5688                         android.Manifest.permission.BIND_APPWIDGET, null);
5689             } catch (SecurityException se) {
5690                 if (!isCallerBindAppWidgetAllowListedLocked(packageName)) {
5691                     return false;
5692                 }
5693             }
5694             return true;
5695         }
5696 
isCallerBindAppWidgetAllowListedLocked(String packageName)5697         private boolean isCallerBindAppWidgetAllowListedLocked(String packageName) {
5698             final int userId = UserHandle.getCallingUserId();
5699             final int packageUid = getUidForPackage(packageName, userId);
5700             if (packageUid < 0) {
5701                 throw new IllegalArgumentException("No package " + packageName
5702                         + " for user " + userId);
5703             }
5704             synchronized (mLock) {
5705                 ensureGroupStateLoadedLocked(userId);
5706 
5707                 Pair<Integer, String> packageId = Pair.create(userId, packageName);
5708                 if (mPackagesWithBindWidgetPermission.contains(packageId)) {
5709                     return true;
5710                 }
5711             }
5712 
5713             return false;
5714         }
5715 
canAccessAppWidget(Widget widget, int uid, String packageName)5716         public boolean canAccessAppWidget(Widget widget, int uid, String packageName) {
5717             if (packageName != null
5718                     && widget.provider != null
5719                     && isDifferentPackageFromProvider(widget.provider, packageName)
5720                     && widget.host != null
5721                     && isDifferentPackageFromHost(widget.host, packageName)) {
5722                 // An AppWidget can only be accessed by either
5723                 // 1. The package that provides the AppWidget.
5724                 // 2. The package that hosts the AppWidget.
5725                 return false;
5726             }
5727             if (isHostInPackageForUid(widget.host, uid, packageName)) {
5728                 // Apps hosting the AppWidget have access to it.
5729                 return true;
5730             }
5731             if (isProviderInPackageForUid(widget.provider, uid, packageName)) {
5732                 // Apps providing the AppWidget have access to it.
5733                 return true;
5734             }
5735             if (isHostAccessingProvider(widget.host, widget.provider, uid, packageName)) {
5736                 // Apps hosting the AppWidget get to bind to a remote view service in the provider.
5737                 return true;
5738             }
5739             final int userId = UserHandle.getUserId(uid);
5740             if ((widget.host.getUserId() == userId
5741                     || (widget.provider != null && widget.provider.getUserId() == userId)
5742                     || hasCallerInteractAcrossUsersPermission())
5743                     && callerHasPermission(android.Manifest.permission.BIND_APPWIDGET)) {
5744                 // Access to the widget requires the app to:
5745                 // - Run in the same user as the host or provider, or have permission to interact
5746                 //   across users
5747                 // - Have bind widget permission
5748                 return true;
5749             }
5750             if (DEBUG) {
5751                 Slog.i(TAG, "canAccessAppWidget() failed. packageName=" + packageName
5752                         + " uid=" + uid + " userId=" + userId + " widget=" + widget);
5753             }
5754             return false;
5755         }
5756 
isParentOrProfile(int parentId, int profileId)5757         private boolean isParentOrProfile(int parentId, int profileId) {
5758             if (parentId == profileId) {
5759                 return true;
5760             }
5761             return getProfileParent(profileId) == parentId;
5762         }
5763 
5764         /**
5765          * The provider is accessible by the caller if any of the following is true:
5766          * - The provider belongs to the caller
5767          * - The provider belongs to a profile of the caller and is allowlisted
5768          */
canAccessProvider(String packageName, int profileId)5769         public boolean canAccessProvider(String packageName, int profileId) {
5770             final int callerId = UserHandle.getCallingUserId();
5771             if (profileId == callerId) {
5772                 return true;
5773             }
5774             final int parentId = getProfileParent(profileId);
5775             if (parentId != callerId) {
5776                 return false;
5777             }
5778             return isProviderWhiteListed(packageName, profileId);
5779         }
5780 
isProviderWhiteListed(String packageName, int profileId)5781         public boolean isProviderWhiteListed(String packageName, int profileId) {
5782             // If the policy manager is not available on the device we deny it all.
5783             if (mDevicePolicyManagerInternal == null) {
5784                 return false;
5785             }
5786 
5787             List<String> crossProfilePackages = mDevicePolicyManagerInternal
5788                     .getCrossProfileWidgetProviders(profileId);
5789 
5790             return crossProfilePackages.contains(packageName);
5791         }
5792 
getProfileParent(int profileId)5793         public int getProfileParent(int profileId) {
5794             final long identity = Binder.clearCallingIdentity();
5795             try {
5796                 UserInfo parent = mUserManager.getProfileParent(profileId);
5797                 if (parent != null) {
5798                     return parent.getUserHandle().getIdentifier();
5799                 }
5800             } finally {
5801                 Binder.restoreCallingIdentity(identity);
5802             }
5803             return UNKNOWN_USER_ID;
5804         }
5805 
getGroupParent(int profileId)5806         public int getGroupParent(int profileId) {
5807             final int parentId = mSecurityPolicy.getProfileParent(profileId);
5808             return (parentId != UNKNOWN_USER_ID) ? parentId : profileId;
5809         }
5810 
isHostInPackageForUid(Host host, int uid, String packageName)5811         public boolean isHostInPackageForUid(Host host, int uid, String packageName) {
5812             return host.id.uid == uid && host.id.packageName.equals(packageName);
5813         }
5814 
isProviderInPackageForUid(Provider provider, int uid, String packageName)5815         public boolean isProviderInPackageForUid(Provider provider, int uid,
5816                 String packageName) {
5817             // Packages providing the AppWidget have access to it.
5818             return provider != null && provider.id.uid == uid
5819                     && provider.id.componentName.getPackageName().equals(packageName);
5820         }
5821 
isHostAccessingProvider(Host host, Provider provider, int uid, String packageName)5822         public boolean isHostAccessingProvider(Host host, Provider provider, int uid,
5823                 String packageName) {
5824             // The host creates a package context to bind to remote views service in the provider.
5825             return host.id.uid == uid && provider != null
5826                     && provider.id.componentName.getPackageName().equals(packageName);
5827         }
5828 
isDifferentPackageFromHost( @onNull final Host host, @NonNull final String packageName)5829         private boolean isDifferentPackageFromHost(
5830                 @NonNull final Host host, @NonNull final String packageName) {
5831             if (host.id == null || host.id.packageName == null) {
5832                 return true;
5833             }
5834             return !packageName.equals(host.id.packageName);
5835         }
5836 
isDifferentPackageFromProvider( @onNull final Provider provider, @NonNull final String packageName)5837         private boolean isDifferentPackageFromProvider(
5838                 @NonNull final Provider provider, @NonNull final String packageName) {
5839             if (provider.id == null || provider.id.componentName == null) {
5840                 return true;
5841             }
5842             return !packageName.equals(provider.id.componentName.getPackageName());
5843         }
5844 
isProfileEnabled(int profileId)5845         private boolean isProfileEnabled(int profileId) {
5846             final long identity = Binder.clearCallingIdentity();
5847             try {
5848                 UserInfo userInfo = mUserManager.getUserInfo(profileId);
5849                 if (userInfo == null || !userInfo.isEnabled()) {
5850                     return false;
5851                 }
5852             } finally {
5853                 Binder.restoreCallingIdentity(identity);
5854             }
5855             return true;
5856         }
5857 
5858         /** Returns true if the caller has permission to interact across users. */
hasCallerInteractAcrossUsersPermission()5859         public boolean hasCallerInteractAcrossUsersPermission() {
5860             if (!securityPolicyInteractAcrossUsers()) {
5861                 return false;
5862             }
5863 
5864             return callerHasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
5865                     || callerHasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
5866         }
5867 
callerHasPermission(@onNull @ermissionName String permission)5868         private boolean callerHasPermission(@NonNull @PermissionName String permission) {
5869             return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
5870         }
5871     }
5872 
5873     static final class Provider {
5874 
5875         ProviderId id;
5876         AppWidgetProviderInfo info;
5877         ArrayList<Widget> widgets = new ArrayList<>();
5878         PendingIntent broadcast;
5879         String infoTag;
5880         SparseArray<RemoteViews> generatedPreviews = new SparseArray<>(3);
5881         private static final int[] WIDGET_CATEGORY_FLAGS = new int[]{
5882                 AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN,
5883                 AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
5884                 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX,
5885         };
5886 
5887         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
5888 
5889         boolean maskedByLockedProfile;
5890         boolean maskedByQuietProfile;
5891         boolean maskedBySuspendedPackage;
5892         // This provider's package has been stopped
5893         boolean maskedByStoppedPackage;
5894         // Widget IDs for which we haven't yet sent DELETED broadcasts because the package was
5895         // stopped.
5896         IntArray pendingDeletedWidgetIds = new IntArray();
5897 
5898         boolean mInfoParsed = false;
5899 
5900         int tag = TAG_UNDEFINED; // for use while saving state (the index)
5901 
getUserId()5902         public int getUserId() {
5903             return UserHandle.getUserId(id.uid);
5904         }
5905 
isInPackageForUser(String packageName, int userId)5906         public boolean isInPackageForUser(String packageName, int userId) {
5907             return getUserId() == userId
5908                     && id.componentName.getPackageName().equals(packageName);
5909         }
5910 
5911         // is there an instance of this provider hosted by the given app?
hostedByPackageForUser(String packageName, int userId)5912         public boolean hostedByPackageForUser(String packageName, int userId) {
5913             final int N = widgets.size();
5914             for (int i = 0; i < N; i++) {
5915                 Widget widget = widgets.get(i);
5916                 if (packageName.equals(widget.host.id.packageName)
5917                         && widget.host.getUserId() == userId) {
5918                     return true;
5919                 }
5920             }
5921             return false;
5922         }
5923 
5924         @GuardedBy("this.mLock")
getInfoLocked(Context context)5925         public AppWidgetProviderInfo getInfoLocked(Context context) {
5926             if (!mInfoParsed) {
5927                 // parse
5928                 if (!zombie) {
5929                     AppWidgetProviderInfo newInfo = null;
5930                     if (!TextUtils.isEmpty(infoTag)) {
5931                         newInfo = parseAppWidgetProviderInfo(
5932                                 context, id, info.providerInfo, infoTag);
5933                     }
5934                     if (newInfo == null) {
5935                         newInfo = parseAppWidgetProviderInfo(context, id, info.providerInfo,
5936                                 AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
5937                     }
5938                     if (newInfo != null) {
5939                         newInfo.generatedPreviewCategories = info.generatedPreviewCategories;
5940                         info = newInfo;
5941                         if (DEBUG) {
5942                             Objects.requireNonNull(info);
5943                         }
5944                     }
5945                 }
5946                 mInfoParsed = true;
5947             }
5948             return info;
5949         }
5950 
5951         /**
5952          * Returns the last updated AppWidgetProviderInfo for this provider. This info may not
5953          * be completely parsed and only contain placeHolder information like
5954          * {@link AppWidgetProviderInfo#providerInfo}
5955          */
5956         @GuardedBy("AppWidgetServiceImpl.mLock")
getPartialInfoLocked()5957         public AppWidgetProviderInfo getPartialInfoLocked() {
5958             return info;
5959         }
5960 
5961         @GuardedBy("AppWidgetServiceImpl.mLock")
setPartialInfoLocked(AppWidgetProviderInfo info)5962         public void setPartialInfoLocked(AppWidgetProviderInfo info) {
5963             this.info = info;
5964             if (DEBUG) {
5965                 Objects.requireNonNull(this.info);
5966             }
5967             mInfoParsed = false;
5968         }
5969 
5970         @GuardedBy("AppWidgetServiceImpl.mLock")
setInfoLocked(AppWidgetProviderInfo info)5971         public void setInfoLocked(AppWidgetProviderInfo info) {
5972             this.info = info;
5973             if (DEBUG) {
5974                 Objects.requireNonNull(this.info);
5975             }
5976             mInfoParsed = true;
5977         }
5978 
5979         @GuardedBy("this.mLock")
5980         @Nullable
getGeneratedPreviewLocked( @ppWidgetProviderInfo.CategoryFlags int widgetCategories)5981         public RemoteViews getGeneratedPreviewLocked(
5982                 @AppWidgetProviderInfo.CategoryFlags int widgetCategories) {
5983             for (int i = 0; i < generatedPreviews.size(); i++) {
5984                 if ((widgetCategories & generatedPreviews.keyAt(i)) != 0) {
5985                     return generatedPreviews.valueAt(i);
5986                 }
5987             }
5988             return null;
5989         }
5990 
5991         @GuardedBy("this.mLock")
setGeneratedPreviewLocked( @ppWidgetProviderInfo.CategoryFlags int widgetCategories, @NonNull RemoteViews preview)5992         public void setGeneratedPreviewLocked(
5993                 @AppWidgetProviderInfo.CategoryFlags int widgetCategories,
5994                 @NonNull RemoteViews preview) {
5995             for (int flag : WIDGET_CATEGORY_FLAGS) {
5996                 if ((widgetCategories & flag) != 0) {
5997                     generatedPreviews.put(flag, preview);
5998                 }
5999             }
6000             updateGeneratedPreviewCategoriesLocked(generatedPreviews);
6001         }
6002 
6003         @GuardedBy("this.mLock")
removeGeneratedPreviewLocked(int widgetCategories)6004         public boolean removeGeneratedPreviewLocked(int widgetCategories) {
6005             boolean changed = false;
6006             for (int flag : WIDGET_CATEGORY_FLAGS) {
6007                 if ((widgetCategories & flag) != 0) {
6008                     changed |= generatedPreviews.removeReturnOld(flag) != null;
6009                 }
6010             }
6011             if (changed) {
6012                 updateGeneratedPreviewCategoriesLocked(generatedPreviews);
6013             }
6014             return changed;
6015         }
6016 
6017         @GuardedBy("this.mLock")
clearGeneratedPreviewsLocked()6018         public boolean clearGeneratedPreviewsLocked() {
6019             if (generatedPreviews.size() > 0) {
6020                 generatedPreviews.clear();
6021                 updateGeneratedPreviewCategoriesLocked(generatedPreviews);
6022                 return true;
6023             }
6024             return false;
6025         }
6026         @GuardedBy("this.mLock")
updateGeneratedPreviewCategoriesLocked( @ullable SparseArray<RemoteViews> previews)6027         private void updateGeneratedPreviewCategoriesLocked(
6028                 @Nullable SparseArray<RemoteViews> previews) {
6029             info.generatedPreviewCategories = 0;
6030             if (previews != null) {
6031                 for (int i = 0; i < previews.size(); i++) {
6032                     info.generatedPreviewCategories |= previews.keyAt(i);
6033                 }
6034             }
6035         }
6036 
6037         @Override
toString()6038         public String toString() {
6039             return "Provider{" + id + (zombie ? " Z" : "") + '}';
6040         }
6041 
6042         // returns true if it's different from previous state.
setMaskedByQuietProfileLocked(boolean masked)6043         public boolean setMaskedByQuietProfileLocked(boolean masked) {
6044             boolean oldState = maskedByQuietProfile;
6045             maskedByQuietProfile = masked;
6046             return masked != oldState;
6047         }
6048 
6049         // returns true if it's different from previous state.
setMaskedByLockedProfileLocked(boolean masked)6050         public boolean setMaskedByLockedProfileLocked(boolean masked) {
6051             boolean oldState = maskedByLockedProfile;
6052             maskedByLockedProfile = masked;
6053             return masked != oldState;
6054         }
6055 
6056         // returns true if it's different from previous state.
setMaskedBySuspendedPackageLocked(boolean masked)6057         public boolean setMaskedBySuspendedPackageLocked(boolean masked) {
6058             boolean oldState = maskedBySuspendedPackage;
6059             maskedBySuspendedPackage = masked;
6060             return masked != oldState;
6061         }
6062 
setMaskedByStoppedPackageLocked(boolean masked)6063         public boolean setMaskedByStoppedPackageLocked(boolean masked) {
6064             boolean oldState = maskedByStoppedPackage;
6065             maskedByStoppedPackage = masked;
6066             return masked != oldState;
6067         }
6068 
isMaskedLocked()6069         public boolean isMaskedLocked() {
6070             return maskedByQuietProfile || maskedByLockedProfile || maskedBySuspendedPackage
6071                     || maskedByStoppedPackage;
6072         }
6073 
shouldBePersisted()6074         public boolean shouldBePersisted() {
6075             return !widgets.isEmpty() || !TextUtils.isEmpty(infoTag);
6076         }
6077     }
6078 
6079     static final class ProviderId {
6080         final int uid;
6081         final ComponentName componentName;
6082 
ProviderId(int uid, ComponentName componentName)6083         ProviderId(int uid, ComponentName componentName) {
6084             this.uid = uid;
6085             this.componentName = componentName;
6086         }
6087 
getProfile()6088         public UserHandle getProfile() {
6089             return UserHandle.getUserHandleForUid(uid);
6090         }
6091 
6092         @Override
equals(Object obj)6093         public boolean equals(Object obj) {
6094             if (this == obj) {
6095                 return true;
6096             }
6097             if (obj == null) {
6098                 return false;
6099             }
6100             if (getClass() != obj.getClass()) {
6101                 return false;
6102             }
6103             ProviderId other = (ProviderId) obj;
6104             if (uid != other.uid)  {
6105                 return false;
6106             }
6107             if (componentName == null) {
6108                 if (other.componentName != null) {
6109                     return false;
6110                 }
6111             } else if (!componentName.equals(other.componentName)) {
6112                 return false;
6113             }
6114             return true;
6115         }
6116 
6117         @Override
hashCode()6118         public int hashCode() {
6119             int result = uid;
6120             result = 31 * result + ((componentName != null)
6121                     ? componentName.hashCode() : 0);
6122             return result;
6123         }
6124 
6125         @Override
toString()6126         public String toString() {
6127             return "ProviderId{user:" + UserHandle.getUserId(uid) + ", app:"
6128                     + UserHandle.getAppId(uid) + ", cmp:" + componentName + '}';
6129         }
6130     }
6131 
6132     static final class Host {
6133         HostId id;
6134         ArrayList<Widget> widgets = new ArrayList<>();
6135         IAppWidgetHost callbacks;
6136         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
6137 
6138         private static final boolean DEBUG = true;
6139 
6140         private static final String TAG = "AppWidgetServiceHost";
6141 
6142         int tag = TAG_UNDEFINED; // for use while saving state (the index)
6143         // Sequence no for the last update successfully sent. This is updated whenever a
6144         // widget update is successfully sent to the host callbacks. As all new/undelivered updates
6145         // will have sequenceNo greater than this, all those updates will be sent when the host
6146         // callbacks are attached again.
6147         long lastWidgetUpdateSequenceNo;
6148 
getUserId()6149         public int getUserId() {
6150             return UserHandle.getUserId(id.uid);
6151         }
6152 
isInPackageForUser(String packageName, int userId)6153         public boolean isInPackageForUser(String packageName, int userId) {
6154             return getUserId() == userId && id.packageName.equals(packageName);
6155         }
6156 
hostsPackageForUser(String pkg, int userId)6157         private boolean hostsPackageForUser(String pkg, int userId) {
6158             final int N = widgets.size();
6159             for (int i = 0; i < N; i++) {
6160                 Provider provider = widgets.get(i).provider;
6161                 if (provider != null && provider.getUserId() == userId
6162                         && pkg.equals(provider.id.componentName.getPackageName())) {
6163                     return true;
6164                 }
6165             }
6166             return false;
6167         }
6168 
6169         /**
6170          * Adds all pending updates in {@param outUpdates} keys by the update time.
6171          */
6172         @GuardedBy("mLock")
getPendingUpdatesForIdLocked(Context context, int appWidgetId, LongSparseArray<PendingHostUpdate> outUpdates)6173         public void getPendingUpdatesForIdLocked(Context context, int appWidgetId,
6174                 LongSparseArray<PendingHostUpdate> outUpdates) {
6175             long updateSequenceNo = lastWidgetUpdateSequenceNo;
6176             int N = widgets.size();
6177             for (int i = 0; i < N; i++) {
6178                 Widget widget = widgets.get(i);
6179                 if (widget.appWidgetId == appWidgetId) {
6180                     for (int j = widget.updateSequenceNos.size() - 1; j >= 0; j--) {
6181                         long requestId = widget.updateSequenceNos.valueAt(j);
6182                         if (requestId <= updateSequenceNo) {
6183                             continue;
6184                         }
6185                         int id = widget.updateSequenceNos.keyAt(j);
6186                         final PendingHostUpdate update;
6187                         switch (id) {
6188                             case ID_PROVIDER_CHANGED:
6189                                 update = PendingHostUpdate.providerChanged(
6190                                         appWidgetId, widget.provider.getInfoLocked(context));
6191                                 break;
6192                             case ID_VIEWS_UPDATE:
6193                                 update = PendingHostUpdate.updateAppWidget(appWidgetId,
6194                                         cloneIfLocalBinder(widget.getEffectiveViewsLocked()));
6195                                 break;
6196                             default:
6197                                 update = PendingHostUpdate.viewDataChanged(appWidgetId, id);
6198                         }
6199                         outUpdates.put(requestId, update);
6200                     }
6201                     return;
6202                 }
6203             }
6204             outUpdates.put(lastWidgetUpdateSequenceNo,
6205                     PendingHostUpdate.appWidgetRemoved(appWidgetId));
6206         }
6207 
getWidgetUidsIfBound()6208         public SparseArray<String> getWidgetUidsIfBound() {
6209             final SparseArray<String> uids = new SparseArray<>();
6210             for (int i = widgets.size() - 1; i >= 0; i--) {
6211                 final Widget widget = widgets.get(i);
6212                 if (widget.provider == null) {
6213                     if (DEBUG) {
6214                         Slog.d(TAG, "Widget with no provider " + widget.toString());
6215                     }
6216                     continue;
6217                 }
6218                 final ProviderId providerId = widget.provider.id;
6219                 uids.put(providerId.uid, providerId.componentName.getPackageName());
6220             }
6221             return uids;
6222         }
6223 
6224         @Override
toString()6225         public String toString() {
6226             return "Host{" + id + (zombie ? " Z" : "") + '}';
6227         }
6228     }
6229 
6230     private static final class HostId {
6231         final int uid;
6232         final int hostId;
6233         final String packageName;
6234 
HostId(int uid, int hostId, String packageName)6235         public HostId(int uid, int hostId, String packageName) {
6236             this.uid = uid;
6237             this.hostId = hostId;
6238             this.packageName = packageName;
6239         }
6240 
6241         @Override
equals(Object obj)6242         public boolean equals(Object obj) {
6243             if (this == obj) {
6244                 return true;
6245             }
6246             if (obj == null) {
6247                 return false;
6248             }
6249             if (getClass() != obj.getClass()) {
6250                 return false;
6251             }
6252             HostId other = (HostId) obj;
6253             if (uid != other.uid)  {
6254                 return false;
6255             }
6256             if (hostId != other.hostId) {
6257                 return false;
6258             }
6259             if (packageName == null) {
6260                 if (other.packageName != null) {
6261                     return false;
6262                 }
6263             } else if (!packageName.equals(other.packageName)) {
6264                 return false;
6265             }
6266             return true;
6267         }
6268 
6269         @Override
hashCode()6270         public int hashCode() {
6271             int result = uid;
6272             result = 31 * result + hostId;
6273             result = 31 * result + ((packageName != null)
6274                     ? packageName.hashCode() : 0);
6275             return result;
6276         }
6277 
6278         @Override
toString()6279         public String toString() {
6280             return "HostId{user:" + UserHandle.getUserId(uid) + ", app:"
6281                     + UserHandle.getAppId(uid) + ", hostId:" + hostId
6282                     + ", pkg:" + packageName + '}';
6283         }
6284     }
6285 
6286     // These can be any constants that would not collide with a resource id.
6287     private static final int ID_VIEWS_UPDATE = 0;
6288     private static final int ID_PROVIDER_CHANGED = 1;
6289 
6290     private static final class Widget {
6291         int appWidgetId;
6292         int restoredId;  // tracking & remapping any restored state
6293         Provider provider;
6294         RemoteViews views;
6295         RemoteViews maskedViews;
6296         Bundle options;
6297         Host host;
6298         // Map of request type to updateSequenceNo.
6299         SparseLongArray updateSequenceNos = new SparseLongArray(2);
6300         boolean trackingUpdate = false;
6301 
6302         @Override
toString()6303         public String toString() {
6304             return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
6305         }
6306 
replaceWithMaskedViewsLocked(RemoteViews views)6307         private boolean replaceWithMaskedViewsLocked(RemoteViews views) {
6308             maskedViews = views;
6309             return true;
6310         }
6311 
clearMaskedViewsLocked()6312         private boolean clearMaskedViewsLocked() {
6313             if (maskedViews != null) {
6314                 maskedViews = null;
6315                 return true;
6316             } else {
6317                 return false;
6318             }
6319         }
6320 
getEffectiveViewsLocked()6321         public RemoteViews getEffectiveViewsLocked() {
6322             return maskedViews != null ? maskedViews : views;
6323         }
6324     }
6325 
6326     /**
6327      * This class keeps track of API calls and implements rate limiting. One instance of this class
6328      * tracks calls from all providers for one API, or a group of APIs that should share the same
6329      * rate limit.
6330      */
6331     static final class ApiCounter {
6332 
6333         private static final class ApiCallRecord {
6334             // Number of times the API has been called for this provider.
6335             public int apiCallCount = 0;
6336             // The last time (from SystemClock.elapsedRealtime) the api call count was reset.
6337             public long lastResetTimeMs = 0;
6338 
reset(long nowMs)6339             void reset(long nowMs) {
6340                 apiCallCount = 0;
6341                 lastResetTimeMs = nowMs;
6342             }
6343         }
6344 
6345         private final Map<ProviderId, ApiCallRecord> mCallCount = new ArrayMap<>();
6346         // The interval at which the call count is reset.
6347         private long mResetIntervalMs;
6348         // The max number of API calls per interval.
6349         private int mMaxCallsPerInterval;
6350         // The max number of providers to keep call records for. Any call to tryApiCall for new
6351         // providers will return false after this limit.
6352         private int mMaxProviders;
6353 
6354         // Returns the current time (monotonic). By default this is SystemClock.elapsedRealtime.
6355         private LongSupplier mMonotonicClock;
6356 
ApiCounter(long resetIntervalMs, int maxCallsPerInterval, int maxProviders)6357         ApiCounter(long resetIntervalMs, int maxCallsPerInterval, int maxProviders) {
6358             this(resetIntervalMs, maxCallsPerInterval, maxProviders, SystemClock::elapsedRealtime);
6359         }
6360 
ApiCounter(long resetIntervalMs, int maxCallsPerInterval, int maxProviders, LongSupplier monotonicClock)6361         ApiCounter(long resetIntervalMs, int maxCallsPerInterval, int maxProviders,
6362                 LongSupplier monotonicClock) {
6363             mResetIntervalMs = resetIntervalMs;
6364             mMaxCallsPerInterval = maxCallsPerInterval;
6365             mMaxProviders = maxProviders;
6366             mMonotonicClock = monotonicClock;
6367         }
6368 
setResetIntervalMs(long resetIntervalMs)6369         public void setResetIntervalMs(long resetIntervalMs) {
6370             mResetIntervalMs = resetIntervalMs;
6371         }
6372 
getResetIntervalMs()6373         public long getResetIntervalMs() {
6374             return mResetIntervalMs;
6375         }
6376 
setMaxCallsPerInterval(int maxCallsPerInterval)6377         public void setMaxCallsPerInterval(int maxCallsPerInterval) {
6378             mMaxCallsPerInterval = maxCallsPerInterval;
6379         }
6380 
getMaxCallsPerInterval()6381         public int getMaxCallsPerInterval() {
6382             return mMaxCallsPerInterval;
6383         }
6384 
setMaxProviders(int maxProviders)6385         public void setMaxProviders(int maxProviders) {
6386             mMaxProviders = maxProviders;
6387         }
6388 
getMaxProviders()6389         public int getMaxProviders() {
6390             return mMaxProviders;
6391         }
6392 
6393         /**
6394          * Returns true if the API call for the provider should be allowed, false if it should be
6395          * rate-limited.
6396          */
tryApiCall(@onNull ProviderId provider)6397         public boolean tryApiCall(@NonNull ProviderId provider) {
6398             if (!mCallCount.containsKey(provider)) {
6399                 if (mCallCount.size() >= mMaxProviders) {
6400                     return false;
6401                 }
6402                 mCallCount.put(provider, new ApiCallRecord());
6403             }
6404             ApiCallRecord record = mCallCount.get(provider);
6405 
6406             final long now = mMonotonicClock.getAsLong();
6407             final long timeSinceLastResetMs = now - record.lastResetTimeMs;
6408             // If the last reset was beyond the reset interval, reset now.
6409             if (timeSinceLastResetMs > mResetIntervalMs) {
6410                 record.reset(now);
6411             }
6412             if (record.apiCallCount < mMaxCallsPerInterval) {
6413                 record.apiCallCount++;
6414                 return true;
6415             }
6416             return false;
6417         }
6418 
6419         /**
6420          * Remove the provider's call record from this counter, when the provider is no longer
6421          * tracked.
6422          */
remove(@onNull ProviderId id)6423         public void remove(@NonNull ProviderId id) {
6424             mCallCount.remove(id);
6425         }
6426     }
6427 
6428     private class LoadedWidgetState {
6429         final Widget widget;
6430         final int hostTag;
6431         final int providerTag;
6432 
LoadedWidgetState(Widget widget, int hostTag, int providerTag)6433         public LoadedWidgetState(Widget widget, int hostTag, int providerTag) {
6434             this.widget = widget;
6435             this.hostTag = hostTag;
6436             this.providerTag = providerTag;
6437         }
6438     }
6439 
6440     private final class SaveStateRunnable implements Runnable {
6441         final int mUserId;
6442 
SaveStateRunnable(int userId)6443         public SaveStateRunnable(int userId) {
6444             mUserId = userId;
6445         }
6446 
6447         @Override
run()6448         public void run() {
6449             synchronized (mLock) {
6450                 // No need to enforce unlocked state when there is no caller. User can be in the
6451                 // stopping state or removed by the time the message is processed
6452                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "convert_state_and_io");
6453                 ensureGroupStateLoadedLocked(mUserId, false /* enforceUserUnlockingOrUnlocked */ );
6454                 saveStateLocked(mUserId);
6455                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
6456             }
6457         }
6458     }
6459 
6460     /**
6461      * This class encapsulates the backup and restore logic for a user group state.
6462      */
6463     final class BackupRestoreController {
6464         private static final String TAG = "BackupRestoreController";
6465 
6466         private static final boolean DEBUG = AppWidgetServiceImpl.DEBUG;
6467 
6468         // Version of backed-up widget state.
6469         private static final int WIDGET_STATE_VERSION = 2;
6470 
6471         // We need to make sure to wipe the pre-restore widget state only once for
6472         // a given package.  Keep track of what we've done so far here; the list is
6473         // cleared at the start of every system restore pass, but preserved through
6474         // any install-time restore operations.
6475         @GuardedBy("AppWidgetServiceImpl.this.mLock")
6476         private final SparseArray<Set<String>> mPrunedAppsPerUser = new SparseArray<>();
6477 
6478         @GuardedBy("AppWidgetServiceImpl.this.mLock")
6479         final Map<Provider, List<RestoreUpdateRecord>> mUpdatesByProvider =
6480                 new ArrayMap<>();
6481 
6482         @GuardedBy("AppWidgetServiceImpl.this.mLock")
6483         private final Map<Host, List<RestoreUpdateRecord>> mUpdatesByHost =
6484                 new ArrayMap<>();
6485 
6486         @GuardedBy("AppWidgetServiceImpl.this.mLock")
6487         private boolean mHasSystemRestoreFinished;
6488 
6489         @GuardedBy("AppWidgetServiceImpl.this.mLock")
requiresPersistenceLocked()6490         public boolean requiresPersistenceLocked() {
6491             if (mHasSystemRestoreFinished) {
6492                 // No need to persist intermediate states if system restore is already finished.
6493                 return false;
6494             }
6495             // If either of the internal states is non-empty, then we need to persist that
6496             return !(mPrunedAppsPerUser.size() == 0 && mUpdatesByProvider.isEmpty()
6497                     && mUpdatesByHost.isEmpty());
6498         }
6499 
getWidgetParticipants(int userId)6500         public List<String> getWidgetParticipants(int userId) {
6501             if (DEBUG) {
6502                 Slog.i(TAG, "Getting widget participants for user: " + userId);
6503             }
6504 
6505             HashSet<String> packages = new HashSet<>();
6506             synchronized (mLock) {
6507                 final int N = mWidgets.size();
6508                 for (int i = 0; i < N; i++) {
6509                     Widget widget = mWidgets.get(i);
6510 
6511                     // Skip cross-user widgets.
6512                     if (!isProviderAndHostInUser(widget, userId)) {
6513                         continue;
6514                     }
6515 
6516                     packages.add(widget.host.id.packageName);
6517                     Provider provider = widget.provider;
6518                     if (provider != null) {
6519                         packages.add(provider.id.componentName.getPackageName());
6520                     }
6521                 }
6522             }
6523             return new ArrayList<>(packages);
6524         }
6525 
getWidgetState(String backedupPackage, int userId)6526         public byte[] getWidgetState(String backedupPackage, int userId) {
6527             if (DEBUG) {
6528                 Slog.i(TAG, "Getting widget state for user: " + userId);
6529             }
6530 
6531             ByteArrayOutputStream stream = new ByteArrayOutputStream();
6532             synchronized (mLock) {
6533                 // Preflight: if this app neither hosts nor provides any live widgets
6534                 // we have no work to do.
6535                 if (!packageNeedsWidgetBackupLocked(backedupPackage, userId)) {
6536                     return null;
6537                 }
6538 
6539                 try {
6540                     TypedXmlSerializer out = Xml.newFastSerializer();
6541                     out.setOutput(stream, StandardCharsets.UTF_8.name());
6542                     out.startDocument(null, true);
6543                     out.startTag(null, "ws");      // widget state
6544                     out.attributeInt(null, "version", WIDGET_STATE_VERSION);
6545                     out.attribute(null, "pkg", backedupPackage);
6546 
6547                     // Remember all the providers that are currently hosted or published
6548                     // by this package: that is, all of the entities related to this app
6549                     // which will need to be told about id remapping.
6550                     int index = 0;
6551                     int N = mProviders.size();
6552                     for (int i = 0; i < N; i++) {
6553                         Provider provider = mProviders.get(i);
6554 
6555                         if (provider.shouldBePersisted()
6556                                 && (provider.isInPackageForUser(backedupPackage, userId)
6557                                 || provider.hostedByPackageForUser(backedupPackage, userId))) {
6558                             provider.tag = index;
6559                             serializeProvider(out, provider, false /* persistsProviderInfo*/);
6560                             index++;
6561                         }
6562                     }
6563 
6564                     N = mHosts.size();
6565                     index = 0;
6566                     for (int i = 0; i < N; i++) {
6567                         Host host = mHosts.get(i);
6568 
6569                         if (!host.widgets.isEmpty()
6570                                 && (host.isInPackageForUser(backedupPackage, userId)
6571                                 || host.hostsPackageForUser(backedupPackage, userId))) {
6572                             host.tag = index;
6573                             serializeHost(out, host);
6574                             index++;
6575                         }
6576                     }
6577 
6578                     // All widget instances involving this package,
6579                     // either as host or as provider
6580                     N = mWidgets.size();
6581                     for (int i = 0; i < N; i++) {
6582                         Widget widget = mWidgets.get(i);
6583 
6584                         Provider provider = widget.provider;
6585                         if (widget.host.isInPackageForUser(backedupPackage, userId)
6586                                 || (provider != null
6587                                 &&  provider.isInPackageForUser(backedupPackage, userId))) {
6588                             serializeAppWidget(out, widget, false);
6589                         }
6590                     }
6591 
6592                     out.endTag(null, "ws");
6593                     out.endDocument();
6594                 } catch (IOException e) {
6595                     Slog.w(TAG, "Unable to save widget state for " + backedupPackage);
6596                     return null;
6597                 }
6598             }
6599 
6600             return stream.toByteArray();
6601         }
6602 
systemRestoreStarting(int userId)6603         public void systemRestoreStarting(int userId) {
6604             if (DEBUG) {
6605                 Slog.i(TAG, "System restore starting for user: " + userId);
6606             }
6607 
6608             synchronized (mLock) {
6609                 mHasSystemRestoreFinished = false;
6610                 // We're starting a new "system" restore operation, so any widget restore
6611                 // state that we see from here on is intended to replace the current
6612                 // widget configuration of any/all of the affected apps.
6613                 getPrunedAppsLocked(userId).clear();
6614                 mUpdatesByProvider.clear();
6615                 mUpdatesByHost.clear();
6616             }
6617         }
6618 
restoreWidgetState(String packageName, byte[] restoredState, int userId)6619         public void restoreWidgetState(String packageName, byte[] restoredState, int userId) {
6620             if (DEBUG) {
6621                 Slog.i(TAG, "Restoring widget state for user:" + userId
6622                         + " package: " + packageName);
6623             }
6624 
6625             ByteArrayInputStream stream = new ByteArrayInputStream(restoredState);
6626             try {
6627                 // Providers mentioned in the widget dataset by ordinal
6628                 ArrayList<Provider> restoredProviders = new ArrayList<>();
6629 
6630                 // Hosts mentioned in the widget dataset by ordinal
6631                 ArrayList<Host> restoredHosts = new ArrayList<>();
6632 
6633                 TypedXmlPullParser parser = Xml.newFastPullParser();
6634                 parser.setInput(stream, StandardCharsets.UTF_8.name());
6635 
6636                 synchronized (mLock) {
6637                     int type;
6638                     do {
6639                         type = parser.next();
6640                         if (type == XmlPullParser.START_TAG) {
6641                             final String tag = parser.getName();
6642                             if ("ws".equals(tag)) {
6643                                 final int versionNumber = parser.getAttributeInt(null, "version");
6644                                 if (versionNumber > WIDGET_STATE_VERSION) {
6645                                     Slog.w(TAG, "Unable to process state version " + versionNumber);
6646                                     return;
6647                                 }
6648 
6649                                 // TODO: fix up w.r.t. canonical vs current package names
6650                                 String pkg = parser.getAttributeValue(null, "pkg");
6651                                 if (!packageName.equals(pkg)) {
6652                                     Slog.w(TAG, "Package mismatch in ws");
6653                                     return;
6654                                 }
6655                             } else if ("p".equals(tag)) {
6656                                 String pkg = parser.getAttributeValue(null, "pkg");
6657                                 String cl = parser.getAttributeValue(null, "cl");
6658 
6659                                 // hostedProviders index will match 'p' attribute in widget's
6660                                 // entry in the xml file being restored
6661                                 // If there's no live entry for this provider, add an inactive one
6662                                 // so that widget IDs referring to them can be properly allocated
6663 
6664                                 // Backup and restore only for the parent profile.
6665                                 ComponentName componentName = new ComponentName(pkg, cl);
6666 
6667                                 Provider p = findProviderLocked(componentName, userId);
6668                                 if (p == null) {
6669                                     AppWidgetProviderInfo info = new AppWidgetProviderInfo();
6670                                     info.provider = componentName;
6671 
6672                                     p = new Provider();
6673                                     p.id = new ProviderId(UNKNOWN_UID, componentName);
6674                                     p.setPartialInfoLocked(info);
6675                                     p.zombie = true;
6676                                     mProviders.add(p);
6677                                 }
6678                                 if (DEBUG) {
6679                                     Slog.i(TAG, "   provider " + p.id);
6680                                 }
6681                                 restoredProviders.add(p);
6682                             } else if ("h".equals(tag)) {
6683                                 // The host app may not yet exist on the device.  If it's here we
6684                                 // just use the existing Host entry, otherwise we create a
6685                                 // placeholder whose uid will be fixed up at PACKAGE_ADDED time.
6686                                 String pkg = parser.getAttributeValue(null, "pkg");
6687 
6688                                 final int uid = getUidForPackage(pkg, userId);
6689                                 final int hostId = parser.getAttributeIntHex(null, "id");
6690 
6691                                 HostId id = new HostId(uid, hostId, pkg);
6692                                 Host h = lookupOrAddHostLocked(id);
6693                                 restoredHosts.add(h);
6694 
6695                                 if (DEBUG) {
6696                                     Slog.i(TAG, "   host[" + restoredHosts.size()
6697                                             + "]: {" + h.id + "}");
6698                                 }
6699                             } else if ("g".equals(tag)) {
6700                                 int restoredId = parser.getAttributeIntHex(null, "id");
6701                                 int hostIndex = parser.getAttributeIntHex(null, "h");
6702                                 Host host = restoredHosts.get(hostIndex);
6703                                 Provider p = null;
6704                                 int which = parser.getAttributeIntHex(null, "p", -1);
6705                                 if (which != -1) {
6706                                     // could have been null if the app had allocated an id
6707                                     // but not yet established a binding under that id
6708                                     p = restoredProviders.get(which);
6709                                 }
6710 
6711                                 // We'll be restoring widget state for both the host and
6712                                 // provider sides of this widget ID, so make sure we are
6713                                 // beginning from a clean slate on both fronts.
6714                                 pruneWidgetStateLocked(host.id.packageName, userId);
6715                                 if (p != null) {
6716                                     pruneWidgetStateLocked(p.id.componentName.getPackageName(),
6717                                             userId);
6718                                 }
6719 
6720                                 // Have we heard about this ancestral widget instance before?
6721                                 Widget id = findRestoredWidgetLocked(restoredId, host, p);
6722                                 if (id == null) {
6723                                     id = new Widget();
6724                                     id.appWidgetId = incrementAndGetAppWidgetIdLocked(userId);
6725                                     id.restoredId = restoredId;
6726                                     id.options = parseWidgetIdOptions(parser);
6727                                     id.host = host;
6728                                     id.host.widgets.add(id);
6729                                     id.provider = p;
6730                                     if (id.provider != null) {
6731                                         id.provider.widgets.add(id);
6732                                     }
6733                                     if (DEBUG) {
6734                                         Slog.i(TAG, "New restored id " + restoredId
6735                                                 + " now " + id);
6736                                     }
6737                                     addWidgetLocked(id);
6738                                 }
6739                                 if (id.provider != null
6740                                         && id.provider.getPartialInfoLocked() != null) {
6741                                     stashProviderRestoreUpdateLocked(id.provider,
6742                                             restoredId, id.appWidgetId);
6743                                 } else {
6744                                     Slog.w(TAG, "Missing provider for restored widget " + id);
6745                                 }
6746                                 stashHostRestoreUpdateLocked(id.host, restoredId, id.appWidgetId);
6747 
6748                                 if (DEBUG) {
6749                                     Slog.i(TAG, "   instance: " + restoredId
6750                                             + " -> " + id.appWidgetId
6751                                             + " :: p=" + id.provider);
6752                                 }
6753                             }
6754                         }
6755                     } while (type != XmlPullParser.END_DOCUMENT);
6756 
6757                     // We've updated our own bookkeeping.  We'll need to notify the hosts and
6758                     // providers about the changes, but we can't do that yet because the restore
6759                     // target is not necessarily fully live at this moment.  Set aside the
6760                     // information for now; the backup manager will call us once more at the
6761                     // end of the process when all of the targets are in a known state, and we
6762                     // will update at that point.
6763                 }
6764             } catch (XmlPullParserException | IOException e) {
6765                 Slog.w(TAG, "Unable to restore widget state for " + packageName);
6766             } finally {
6767                 saveGroupStateAsync(userId);
6768             }
6769         }
6770 
6771         // Called once following the conclusion of a system restore operation.  This is when we
6772         // send out updates to apps involved in widget-state restore telling them about
6773         // the new widget ID space.  Apps that are not yet installed will be notifed when they are.
systemRestoreFinished(int userId)6774         public void systemRestoreFinished(int userId) {
6775             if (DEBUG) {
6776                 Slog.i(TAG, "systemRestoreFinished for " + userId);
6777             }
6778             synchronized (mLock) {
6779                 mHasSystemRestoreFinished = true;
6780                 maybeSendWidgetRestoreBroadcastsLocked(userId);
6781             }
6782         }
6783 
6784         // Called when widget components (hosts or providers) are added or changed.  If system
6785         // restore has completed, we use this opportunity to tell the apps to update to the new
6786         // widget ID space.  If system restore is still in progress, we delay the updates until
6787         // the end, to allow all participants to restore their state before updating widget IDs.
widgetComponentsChanged(int userId)6788         public void widgetComponentsChanged(int userId) {
6789             synchronized (mLock) {
6790                 if (mHasSystemRestoreFinished) {
6791                     maybeSendWidgetRestoreBroadcastsLocked(userId);
6792                 }
6793             }
6794         }
6795 
6796         // Called following the conclusion of a restore operation and when widget components
6797         // are added or changed.  This is when we send out updates to apps involved in widget-state
6798         // restore telling them about the new widget ID space.
6799         @GuardedBy("mLock")
maybeSendWidgetRestoreBroadcastsLocked(int userId)6800         private void maybeSendWidgetRestoreBroadcastsLocked(int userId) {
6801             if (DEBUG) {
6802                 Slog.i(TAG, "maybeSendWidgetRestoreBroadcasts for " + userId);
6803             }
6804 
6805             final UserHandle userHandle = new UserHandle(userId);
6806             // Build the providers' broadcasts and send them off
6807             Set<Map.Entry<Provider, List<RestoreUpdateRecord>>> providerEntries
6808                     = mUpdatesByProvider.entrySet();
6809             for (Map.Entry<Provider, List<RestoreUpdateRecord>> e : providerEntries) {
6810                 // For each provider there's a list of affected IDs
6811                 Provider provider = e.getKey();
6812                 if (provider.zombie) {
6813                     // Provider not installed, we can't send them broadcasts yet.
6814                     // We'll be called again when the provider is installed.
6815                     continue;
6816                 }
6817                 List<RestoreUpdateRecord> updates = e.getValue();
6818                 final int pending = countPendingUpdates(updates);
6819                 if (DEBUG) {
6820                     Slog.i(TAG, "Provider " + provider + " pending: " + pending);
6821                 }
6822                 if (pending > 0) {
6823                     int[] oldIds = new int[pending];
6824                     int[] newIds = new int[pending];
6825                     final int N = updates.size();
6826                     int nextPending = 0;
6827                     for (int i = 0; i < N; i++) {
6828                         RestoreUpdateRecord r = updates.get(i);
6829                         if (!r.notified) {
6830                             r.notified = true;
6831                             oldIds[nextPending] = r.oldId;
6832                             newIds[nextPending] = r.newId;
6833                             nextPending++;
6834                             if (DEBUG) {
6835                                 Slog.i(TAG, "   " + r.oldId + " => " + r.newId);
6836                             }
6837                         }
6838                     }
6839                     sendWidgetRestoreBroadcastLocked(
6840                             AppWidgetManager.ACTION_APPWIDGET_RESTORED,
6841                             provider, null, oldIds, newIds, userHandle);
6842                 }
6843             }
6844 
6845             // same thing per host
6846             Set<Map.Entry<Host, List<RestoreUpdateRecord>>> hostEntries
6847                     = mUpdatesByHost.entrySet();
6848             for (Map.Entry<Host, List<RestoreUpdateRecord>> e : hostEntries) {
6849                 Host host = e.getKey();
6850                 if (host.id.uid != UNKNOWN_UID) {
6851                     List<RestoreUpdateRecord> updates = e.getValue();
6852                     final int pending = countPendingUpdates(updates);
6853                     if (DEBUG) {
6854                         Slog.i(TAG, "Host " + host + " pending: " + pending);
6855                     }
6856                     if (pending > 0) {
6857                         int[] oldIds = new int[pending];
6858                         int[] newIds = new int[pending];
6859                         final int N = updates.size();
6860                         int nextPending = 0;
6861                         for (int i = 0; i < N; i++) {
6862                             RestoreUpdateRecord r = updates.get(i);
6863                             if (!r.notified) {
6864                                 r.notified = true;
6865                                 oldIds[nextPending] = r.oldId;
6866                                 newIds[nextPending] = r.newId;
6867                                 nextPending++;
6868                                 if (DEBUG) {
6869                                     Slog.i(TAG, "   " + r.oldId + " => " + r.newId);
6870                                 }
6871                             }
6872                         }
6873                         sendWidgetRestoreBroadcastLocked(
6874                                 AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED,
6875                                 null, host, oldIds, newIds, userHandle);
6876                     }
6877                 }
6878             }
6879         }
6880 
findProviderLocked(ComponentName componentName, int userId)6881         private Provider findProviderLocked(ComponentName componentName, int userId) {
6882             final int providerCount = mProviders.size();
6883             for (int i = 0; i < providerCount; i++) {
6884                 Provider provider = mProviders.get(i);
6885                 if (provider.getUserId() == userId
6886                         && provider.id.componentName.equals(componentName)) {
6887                     return provider;
6888                 }
6889             }
6890             return null;
6891         }
6892 
findRestoredWidgetLocked(int restoredId, Host host, Provider p)6893         private Widget findRestoredWidgetLocked(int restoredId, Host host, Provider p) {
6894             if (DEBUG) {
6895                 Slog.i(TAG, "Find restored widget: id=" + restoredId
6896                         + " host=" + host + " provider=" + p);
6897             }
6898 
6899             if (p == null || host == null) {
6900                 return null;
6901             }
6902 
6903             final int N = mWidgets.size();
6904             for (int i = 0; i < N; i++) {
6905                 Widget widget = mWidgets.get(i);
6906                 if (widget.restoredId == restoredId
6907                         && widget.host.id.equals(host.id)
6908                         && widget.provider.id.equals(p.id)) {
6909                     if (DEBUG) {
6910                         Slog.i(TAG, "   Found at " + i + " : " + widget);
6911                     }
6912                     return widget;
6913                 }
6914             }
6915             return null;
6916         }
6917 
packageNeedsWidgetBackupLocked(String packageName, int userId)6918         private boolean packageNeedsWidgetBackupLocked(String packageName, int userId) {
6919             int N = mWidgets.size();
6920             for (int i = 0; i < N; i++) {
6921                 Widget widget = mWidgets.get(i);
6922 
6923                 // Skip cross-user widgets.
6924                 if (!isProviderAndHostInUser(widget, userId)) {
6925                     continue;
6926                 }
6927 
6928                 if (widget.host.isInPackageForUser(packageName, userId)) {
6929                     // this package is hosting widgets, so it knows widget IDs.
6930                     return true;
6931                 }
6932 
6933                 Provider provider = widget.provider;
6934                 if (provider != null && provider.isInPackageForUser(packageName, userId)) {
6935                     // someone is hosting this app's widgets, so it knows widget IDs.
6936                     return true;
6937                 }
6938             }
6939             return false;
6940         }
6941 
6942         @GuardedBy("mLock")
stashProviderRestoreUpdateLocked(Provider provider, int oldId, int newId)6943         private void stashProviderRestoreUpdateLocked(Provider provider, int oldId, int newId) {
6944             List<RestoreUpdateRecord> r = mUpdatesByProvider.get(provider);
6945             if (r == null) {
6946                 r = new ArrayList<>();
6947                 mUpdatesByProvider.put(provider, r);
6948             } else {
6949                 // don't duplicate
6950                 if (alreadyStashed(r, oldId, newId)) {
6951                     if (DEBUG) {
6952                         Slog.i(TAG, "ID remap " + oldId + " -> " + newId
6953                                 + " already stashed for " + provider);
6954                     }
6955                     return;
6956                 }
6957             }
6958             r.add(new RestoreUpdateRecord(oldId, newId));
6959         }
6960 
alreadyStashed(List<RestoreUpdateRecord> stash, final int oldId, final int newId)6961         private boolean alreadyStashed(List<RestoreUpdateRecord> stash,
6962                 final int oldId, final int newId) {
6963             final int N = stash.size();
6964             for (int i = 0; i < N; i++) {
6965                 RestoreUpdateRecord r = stash.get(i);
6966                 if (r.oldId == oldId && r.newId == newId) {
6967                     return true;
6968                 }
6969             }
6970             return false;
6971         }
6972 
6973         @GuardedBy("mLock")
stashHostRestoreUpdateLocked(Host host, int oldId, int newId)6974         private void stashHostRestoreUpdateLocked(Host host, int oldId, int newId) {
6975             List<RestoreUpdateRecord> r = mUpdatesByHost.get(host);
6976             if (r == null) {
6977                 r = new ArrayList<>();
6978                 mUpdatesByHost.put(host, r);
6979             } else {
6980                 if (alreadyStashed(r, oldId, newId)) {
6981                     if (DEBUG) {
6982                         Slog.i(TAG, "ID remap " + oldId + " -> " + newId
6983                                 + " already stashed for " + host);
6984                     }
6985                     return;
6986                 }
6987             }
6988             r.add(new RestoreUpdateRecord(oldId, newId));
6989         }
6990 
sendWidgetRestoreBroadcastLocked(String action, Provider provider, Host host, int[] oldIds, int[] newIds, UserHandle userHandle)6991         private void sendWidgetRestoreBroadcastLocked(String action, Provider provider,
6992                 Host host, int[] oldIds, int[] newIds, UserHandle userHandle) {
6993             // Users expect restore to emplace widgets properly ASAP, so flag these as
6994             // being interactive broadcast dispatches
6995             Intent intent = new Intent(action);
6996             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS, oldIds);
6997             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, newIds);
6998             if (provider != null) {
6999                 intent.setComponent(provider.id.componentName);
7000                 sendBroadcastAsUser(intent, userHandle, true);
7001             }
7002             if (host != null) {
7003                 intent.setComponent(null);
7004                 intent.setPackage(host.id.packageName);
7005                 intent.putExtra(AppWidgetManager.EXTRA_HOST_ID, host.id.hostId);
7006                 sendBroadcastAsUser(intent, userHandle, true);
7007             }
7008         }
7009 
7010         // We're restoring widget state for 'pkg', so we start by wiping (a) all widget
7011         // instances that are hosted by that app, and (b) all instances in other hosts
7012         // for which 'pkg' is the provider.  We assume that we'll be restoring all of
7013         // these hosts & providers, so will be reconstructing a correct live state.
7014         @GuardedBy("mLock")
pruneWidgetStateLocked(String pkg, int userId)7015         private void pruneWidgetStateLocked(String pkg, int userId) {
7016             final Set<String> prunedApps = getPrunedAppsLocked(userId);
7017             if (!prunedApps.contains(pkg)) {
7018                 if (DEBUG) {
7019                     Slog.i(TAG, "pruning widget state for restoring package " + pkg);
7020                 }
7021                 for (int i = mWidgets.size() - 1; i >= 0; i--) {
7022                     Widget widget = mWidgets.get(i);
7023 
7024                     Host host = widget.host;
7025                     Provider provider = widget.provider;
7026 
7027                     if (host.hostsPackageForUser(pkg, userId)
7028                             || (provider != null && provider.isInPackageForUser(pkg, userId))) {
7029                         // 'pkg' is either the host or the provider for this instances,
7030                         // so we tear it down in anticipation of it (possibly) being
7031                         // reconstructed due to the restore
7032                         host.widgets.remove(widget);
7033                         if (provider != null) {
7034                             provider.widgets.remove(widget);
7035                         }
7036                         // Check if we need to destroy any services (if no other app widgets are
7037                         // referencing the same service)
7038                         decrementAppWidgetServiceRefCount(widget);
7039                         removeWidgetLocked(widget);
7040                     }
7041                 }
7042                 prunedApps.add(pkg);
7043             } else {
7044                 if (DEBUG) {
7045                     Slog.i(TAG, "already pruned " + pkg + ", continuing normally");
7046                 }
7047             }
7048         }
7049 
7050         @GuardedBy("mLock")
7051         @NonNull
getPrunedAppsLocked(int userId)7052         private Set<String> getPrunedAppsLocked(int userId) {
7053             if (!mPrunedAppsPerUser.contains(userId)) {
7054                 mPrunedAppsPerUser.set(userId, new ArraySet<>());
7055             }
7056             return mPrunedAppsPerUser.get(userId);
7057         }
7058 
isProviderAndHostInUser(Widget widget, int userId)7059         private boolean isProviderAndHostInUser(Widget widget, int userId) {
7060             // Backup only widgets hosted or provided by the owner profile.
7061             return widget.host.getUserId() == userId && (widget.provider == null
7062                     || widget.provider.getUserId() == userId);
7063         }
7064 
countPendingUpdates(List<RestoreUpdateRecord> updates)7065         private int countPendingUpdates(List<RestoreUpdateRecord> updates) {
7066             int pending = 0;
7067             final int N = updates.size();
7068             for (int i = 0; i < N; i++) {
7069                 RestoreUpdateRecord r = updates.get(i);
7070                 if (!r.notified) {
7071                     pending++;
7072                 }
7073             }
7074             return pending;
7075         }
7076 
7077         @GuardedBy("mLock")
7078         @NonNull
getStateLocked(final int userId)7079         private State getStateLocked(final int userId) {
7080             final Set<String> prunedApps = mPrunedAppsPerUser.get(userId);
7081             final SparseArray<List<RestoreUpdateRecord>> updatesByProvider = new SparseArray<>();
7082             final SparseArray<List<RestoreUpdateRecord>> updatesByHost = new SparseArray<>();
7083             mUpdatesByProvider.forEach((p, updates) -> {
7084                 if (p.getUserId() == userId) {
7085                     updatesByProvider.put(p.tag, new ArrayList<>(updates));
7086                 }
7087             });
7088             mUpdatesByHost.forEach((h, updates) -> {
7089                 if (h.getUserId() == userId) {
7090                     updatesByHost.put(h.tag, new ArrayList<>(updates));
7091                 }
7092             });
7093             return new State(prunedApps, updatesByProvider, updatesByHost);
7094         }
7095 
7096         // Accumulate a list of updates that affect the given provider for a final
7097         // coalesced notification broadcast once restore is over.
7098         static class RestoreUpdateRecord {
7099             public int oldId;
7100             public int newId;
7101             public boolean notified;
7102 
RestoreUpdateRecord(int theOldId, int theNewId)7103             public RestoreUpdateRecord(int theOldId, int theNewId) {
7104                 oldId = theOldId;
7105                 newId = theNewId;
7106                 notified = false;
7107             }
7108         }
7109 
7110         static final class State {
7111             // We need to make sure to wipe the pre-restore widget state only once for
7112             // a given package.  Keep track of what we've done so far here; the list is
7113             // cleared at the start of every system restore pass, but preserved through
7114             // any install-time restore operations.
7115             @Nullable
7116             private final Set<String> mPrunedApps;
7117 
7118             @Nullable
7119             private final SparseArray<List<RestoreUpdateRecord>> mUpdatesByProvider;
7120 
7121             @Nullable
7122             private final SparseArray<List<RestoreUpdateRecord>> mUpdatesByHost;
7123 
State( @ullable final Set<String> prunedApps, @Nullable final SparseArray<List<RestoreUpdateRecord>> updatesByProvider, @Nullable final SparseArray<List<RestoreUpdateRecord>> updatesByHost)7124             State(
7125                     @Nullable final Set<String> prunedApps,
7126                     @Nullable final SparseArray<List<RestoreUpdateRecord>> updatesByProvider,
7127                     @Nullable final SparseArray<List<RestoreUpdateRecord>> updatesByHost) {
7128                 mPrunedApps = prunedApps;
7129                 mUpdatesByProvider = updatesByProvider;
7130                 mUpdatesByHost = updatesByHost;
7131             }
7132 
7133             @Nullable
getPrunedApps()7134             Set<String> getPrunedApps() {
7135                 return mPrunedApps;
7136             }
7137 
7138             @Nullable
getUpdatesByProvider()7139             SparseArray<List<BackupRestoreController.RestoreUpdateRecord>> getUpdatesByProvider() {
7140                 return mUpdatesByProvider;
7141             }
7142 
7143             @Nullable
getUpdatesByHost()7144             SparseArray<List<BackupRestoreController.RestoreUpdateRecord>> getUpdatesByHost() {
7145                 return mUpdatesByHost;
7146             }
7147         }
7148     }
7149 
7150     private class AppWidgetManagerLocal extends AppWidgetManagerInternal {
7151         @Override
getHostedWidgetPackages(int uid)7152         public ArraySet<String> getHostedWidgetPackages(int uid) {
7153             synchronized (mLock) {
7154                 ArraySet<String> widgetPackages = null;
7155                 final int widgetCount = mWidgets.size();
7156                 for (int i = 0; i < widgetCount; i++) {
7157                     final Widget widget = mWidgets.get(i);
7158                     if  (widget.host.id.uid == uid && widget.provider != null) {
7159                         if (widgetPackages == null) {
7160                             widgetPackages = new ArraySet<>();
7161                         }
7162                         widgetPackages.add(widget.provider.id.componentName.getPackageName());
7163                     }
7164                 }
7165                 return widgetPackages;
7166             }
7167         }
7168 
7169         @Override
unlockUser(int userId)7170         public void unlockUser(int userId) {
7171             handleUserUnlocked(userId);
7172         }
7173 
7174         @Override
applyResourceOverlaysToWidgets(Set<String> packageNames, int userId, boolean updateFrameworkRes)7175         public void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId,
7176                 boolean updateFrameworkRes) {
7177             synchronized (mLock) {
7178                 applyResourceOverlaysToWidgetsLocked(new HashSet<>(packageNames), userId,
7179                         updateFrameworkRes);
7180             }
7181         }
7182     }
7183 }
7184