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