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