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