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