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