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