OSDN Git Service

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