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