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