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