AppWidgetServiceImpl.java revision c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0c
1742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani/*
2742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * Copyright (C) 2011 The Android Open Source Project
3742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani *
4742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * Licensed under the Apache License, Version 2.0 (the "License");
5742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * you may not use this file except in compliance with the License.
6742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * You may obtain a copy of the License at
7742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani *
8742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani *      http://www.apache.org/licenses/LICENSE-2.0
9742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani *
10742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * Unless required by applicable law or agreed to in writing, software
11742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * distributed under the License is distributed on an "AS IS" BASIS,
12742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * See the License for the specific language governing permissions and
14742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani * limitations under the License.
15742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani */
16742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1730f8eb472e44228069c2ffb8bd0b43213edbf04eAmith Yamasanipackage com.android.server.appwidget;
18742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
19742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.app.AlarmManager;
20483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasaniimport android.app.AppGlobals;
21742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.app.PendingIntent;
22976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.app.admin.DevicePolicyManagerInternal;
23742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.appwidget.AppWidgetManager;
24742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.appwidget.AppWidgetProviderInfo;
25976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.content.BroadcastReceiver;
26742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.ComponentName;
27742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.Context;
28742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.Intent;
29742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.Intent.FilterComparison;
30976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.content.IntentFilter;
31976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.content.IntentSender;
3261a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurkaimport android.content.ServiceConnection;
33742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.ActivityInfo;
34742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.ApplicationInfo;
35483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasaniimport android.content.pm.IPackageManager;
36742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.PackageInfo;
37742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.PackageManager;
38742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.ResolveInfo;
39742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.pm.ServiceInfo;
40976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.content.pm.UserInfo;
41742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.res.Resources;
42742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.res.TypedArray;
43742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.content.res.XmlResourceParser;
44a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brownimport android.graphics.Point;
45742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.net.Uri;
46742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.Binder;
47742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.Bundle;
4861f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasaniimport android.os.Environment;
49a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohenimport android.os.Handler;
50742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.IBinder;
51976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.os.Looper;
52976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.os.Message;
53f229e4d3eb8f910c181f96416c6798f6f305a395Jim Millerimport android.os.Process;
54742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.RemoteException;
55742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.os.SystemClock;
56f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
57976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.os.UserManager;
58976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.text.TextUtils;
59976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.util.ArraySet;
6039606a007a5b1309dd000234f2b8cf156c49fd0fDianne Hackbornimport android.util.AtomicFile;
61742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.AttributeSet;
62742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.Pair;
63742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.Slog;
64976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport android.util.SparseIntArray;
65742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.TypedValue;
66742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.util.Xml;
67a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brownimport android.view.Display;
68311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohenimport android.view.WindowManager;
69742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport android.widget.RemoteViews;
70742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
71742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport com.android.internal.appwidget.IAppWidgetHost;
72976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.internal.appwidget.IAppWidgetService;
73976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.internal.os.BackgroundThread;
74976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.internal.os.SomeArgs;
75742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport com.android.internal.util.FastXmlSerializer;
76742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport com.android.internal.widget.IRemoteViewsAdapterConnection;
77742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport com.android.internal.widget.IRemoteViewsFactory;
78742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
79976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.server.LocalServices;
80976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport com.android.server.WidgetBackupProvider;
81976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport libcore.io.IoUtils;
82742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport org.xmlpull.v1.XmlPullParser;
83742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport org.xmlpull.v1.XmlPullParserException;
84742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport org.xmlpull.v1.XmlSerializer;
85742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
86adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport java.io.ByteArrayInputStream;
87adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tateimport java.io.ByteArrayOutputStream;
88742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.File;
89742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.FileDescriptor;
90742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.FileInputStream;
91742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.FileNotFoundException;
92742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.FileOutputStream;
93742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.IOException;
94742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.io.PrintWriter;
95742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.ArrayList;
96976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport java.util.Collections;
97742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.HashMap;
98742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.HashSet;
99742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.Iterator;
100742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.List;
101742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.Locale;
102976e8bd2017d0263216c62111454438cc0f130e3Svetoslavimport java.util.Map;
103742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasaniimport java.util.Set;
104742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
105976e8bd2017d0263216c62111454438cc0f130e3Svetoslavclass AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider {
106976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final String TAG = "AppWidgetServiceImpl";
107976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
108976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static boolean DEBUG = false;
109742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
110976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final String OLD_KEYGUARD_HOST_PACKAGE = "android";
111976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final String NEW_KEYGUARD_HOST_PACKAGE = "com.android.keyguard";
11239d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller    private static final int KEYGUARD_HOST_ID = 0x4b455947;
113742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
114976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final String STATE_FILENAME = "appwidgets.xml";
1158320de8e29819963845d3d386d6d087844a5ae31Amith Yamasani
116976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int MIN_UPDATE_PERIOD = DEBUG ? 0 : 30 * 60 * 1000; // 30 minutes
117742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
118976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int TAG_UNDEFINED = -1;
119742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
120976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int UNKNOWN_UID = -1;
121adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
122976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int LOADED_PROFILE_ID = -1;
123adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
124976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int DISABLED_PROFILE = -1;
125742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
126976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int UNKNOWN_USER_ID = -10;
127742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
128976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Bump if the stored widgets need to be upgraded.
129976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final int CURRENT_VERSION = 1;
130c566b43d02596cba437e9a2723e9f989297cca72Amith Yamasani
131976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
132976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void onReceive(Context context, Intent intent) {
133976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String action = intent.getAction();
134adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
135976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
136976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Received broadcast: " + action);
137adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
138adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
139976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
140976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                onConfigurationChanged();
141976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else if (Intent.ACTION_USER_STARTED.equals(action)) {
142976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                onUserStarted(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
143976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        UserHandle.USER_NULL));
144976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
145976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                onUserStopped(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
146976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        UserHandle.USER_NULL));
147976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
148976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                onPackageBroadcastReceived(intent, intent.getIntExtra(
149976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL));
150976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
151adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
152976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    };
153742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
154976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Manages active connections to RemoteViewsServices.
155976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final HashMap<Pair<Integer, FilterComparison>, ServiceConnection>
156976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mBoundRemoteViewsServices = new HashMap<>();
157adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
158976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Manages persistent references to RemoteViewsServices from different App Widgets.
159976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final HashMap<Pair<Integer, FilterComparison>, HashSet<Integer>>
160976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mRemoteViewsServicesAppWidgets = new HashMap<>();
161adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
162976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final Object mLock = new Object();
163adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
164976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final ArrayList<Widget> mWidgets = new ArrayList<>();
165976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final ArrayList<Host> mHosts = new ArrayList<>();
166976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final ArrayList<Provider> mProviders = new ArrayList<>();
167adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
168976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final ArraySet<Pair<Integer, String>> mPackagesWithBindWidgetPermission =
169976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            new ArraySet<>();
170742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
171976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final SparseIntArray mLoadedUserIds = new SparseIntArray();
172742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
173976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final BackupRestoreController mBackupRestoreController;
174742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
175976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final Context mContext;
176742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
177976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final IPackageManager mPackageManager;
178976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final AlarmManager mAlarmManager;
179976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final UserManager mUserManager;
180742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
181976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final SecurityPolicy mSecurityPolicy;
182adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
183a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen    private final Handler mSaveStateHandler;
184976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final Handler mCallbackHandler;
185a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen
186976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Locale mLocale;
187742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
188976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final SparseIntArray mNextAppWidgetIds = new SparseIntArray();
189976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
190976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean mSafeMode;
191976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int mMaxWidgetBitmapMemory;
192976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
193976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    AppWidgetServiceImpl(Context context) {
194742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        mContext = context;
195976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mPackageManager = AppGlobals.getPackageManager();
196742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
197976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
198976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSaveStateHandler = BackgroundThread.getHandler();
199976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
200976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mBackupRestoreController = new BackupRestoreController();
201976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy = new SecurityPolicy();
202311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen        computeMaximumWidgetBitmapMemory();
203976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        registerBroadcastReceiver();
204311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen    }
205311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen
206976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void computeMaximumWidgetBitmapMemory() {
207311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
208a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brown        Display display = wm.getDefaultDisplay();
209a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brown        Point size = new Point();
210a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brown        display.getRealSize(size);
211e92aad432add317793a69a34eab5d271962df220Winson Chung        // Cap memory usage at 1.5 times the size of the display
212e92aad432add317793a69a34eab5d271962df220Winson Chung        // 1.5 * 4 bytes/pixel * w * h ==> 6 * w * h
213a8b9defade5b937d4ad64f9aff4bca792298f43cJeff Brown        mMaxWidgetBitmapMemory = 6 * size.x * size.y;
214742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
215742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
216976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void registerBroadcastReceiver() {
217976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Register for configuration changes so we can update the names
218976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // of the widgets when the locale changes.
219976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IntentFilter configFilter = new IntentFilter();
220976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        configFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
221976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
222976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                configFilter, null, null);
223976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
224976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Register for broadcasts about package install, etc., so we can
225976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // update the provider list.
226976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IntentFilter packageFilter = new IntentFilter();
227976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
228976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
229976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
230976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        packageFilter.addDataScheme("package");
231976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
232976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                packageFilter, null, null);
233976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
234976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Register for events related to sdcard installation.
235976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IntentFilter sdFilter = new IntentFilter();
236976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
237976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
238976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
239976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sdFilter, null, null);
240976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
241976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IntentFilter userFilter = new IntentFilter();
242976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        userFilter.addAction(Intent.ACTION_USER_STARTED);
243976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        userFilter.addAction(Intent.ACTION_USER_STOPPED);
244976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
245976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                userFilter, null, null);
246976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
247976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
248976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void setSafeMode(boolean safeMode) {
249742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        mSafeMode = safeMode;
250742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
251742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
252976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void onConfigurationChanged() {
253976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
254976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "onConfigurationChanged()");
255976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2568320de8e29819963845d3d386d6d087844a5ae31Amith Yamasani
257742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        Locale revised = Locale.getDefault();
258976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (revised == null || mLocale == null || !revised.equals(mLocale)) {
259742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            mLocale = revised;
260742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
261976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
262976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                SparseIntArray changedGroups = null;
263976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
264a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                // Note: updateProvidersForPackageLocked() may remove providers, so we must copy the
265a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                // list of installed providers and skip providers that we don't need to update.
266a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                // Also note that remove the provider does not clear the Provider component data.
267976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ArrayList<Provider> installedProviders = new ArrayList<>(mProviders);
268976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                HashSet<ProviderId> removedProviders = new HashSet<>();
269976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
270a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                int N = installedProviders.size();
271742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                for (int i = N - 1; i >= 0; i--) {
272976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider provider = installedProviders.get(i);
273976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
274976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    ensureGroupStateLoadedLocked(provider.getUserId());
275976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
276976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (!removedProviders.contains(provider.id)) {
277976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final boolean changed = updateProvidersForPackageLocked(
278976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                provider.id.componentName.getPackageName(),
279976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                provider.getUserId(), removedProviders);
280976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
281976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (changed) {
282976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            if (changedGroups == null) {
283976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                changedGroups = new SparseIntArray();
284976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
285976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final int groupId = mSecurityPolicy.getGroupParent(
286976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    provider.getUserId());
287976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            changedGroups.put(groupId, groupId);
288976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
289976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
290976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
291976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
292976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (changedGroups != null) {
293976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int groupCount = changedGroups.size();
294976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    for (int i = 0; i < groupCount; i++) {
295976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int groupId = changedGroups.get(i);
296976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        saveGroupStateAsync(groupId);
297a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                    }
298742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
299742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
300742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
301742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
302742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
303976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void onPackageBroadcastReceived(Intent intent, int userId) {
304742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        final String action = intent.getAction();
305742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        boolean added = false;
306742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        boolean changed = false;
307976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        boolean componentsModified = false;
308976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
309742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        String pkgList[] = null;
310742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
311742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
312742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            added = true;
313742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
314742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
315742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            added = false;
316742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } else {
317742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            Uri uri = intent.getData();
318742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (uri == null) {
319742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return;
320742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
321742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            String pkgName = uri.getSchemeSpecificPart();
322742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (pkgName == null) {
323742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return;
324742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
325742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pkgList = new String[] { pkgName };
326742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            added = Intent.ACTION_PACKAGE_ADDED.equals(action);
327742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            changed = Intent.ACTION_PACKAGE_CHANGED.equals(action);
328742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
329742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        if (pkgList == null || pkgList.length == 0) {
330742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            return;
331742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
332976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
333976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
334976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
335976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
336976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Bundle extras = intent.getExtras();
337976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
338976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (added || changed) {
339976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean newPackageAdded = added && (extras == null
340976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        || !extras.getBoolean(Intent.EXTRA_REPLACING, false));
341976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
342976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (String pkgName : pkgList) {
343976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // Fix up the providers - add/remove/update.
344976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    componentsModified |= updateProvidersForPackageLocked(pkgName, userId, null);
345976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
346976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // ... and see if these are hosts we've been awaiting.
347976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // NOTE: We are backing up and restoring only the owner.
348976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (newPackageAdded && userId == UserHandle.USER_OWNER) {
349976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int uid = getUidForPackage(pkgName, userId);
350976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (uid >= 0 ) {
351976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            resolveHostUidLocked(pkgName, uid);
352adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                        }
353adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                    }
354742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
355742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            } else {
356976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // If the package is being updated, we'll receive a PACKAGE_ADDED
357976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // shortly, otherwise it is removed permanently.
358976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean packageRemovedPermanently = (extras == null
359976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        || !extras.getBoolean(Intent.EXTRA_REPLACING, false));
360976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
361976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (packageRemovedPermanently) {
362742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    for (String pkgName : pkgList) {
363976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        componentsModified |= removeHostsAndProvidersForPackageLocked(
364976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                pkgName, userId);
365742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    }
366742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
367742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
3687fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
369976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (componentsModified) {
370976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                saveGroupStateAsync(userId);
371976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
372976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // If the set of providers has been modified, notify each active AppWidgetHost
373976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                scheduleNotifyHostsForProvidersChangedLocked();
3747fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung            }
3757fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung        }
376742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
377742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
378976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void resolveHostUidLocked(String pkg, int uid) {
379adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        final int N = mHosts.size();
380adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        for (int i = 0; i < N; i++) {
381976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
382976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host.id.uid == UNKNOWN_UID && pkg.equals(host.id.packageName)) {
383976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (DEBUG) {
384976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.i(TAG, "host " + host.id + " resolved to uid " + uid);
385adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                }
386976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.id = new HostId(uid, host.id.hostId, host.id.packageName);
387976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return;
388adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
389adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
390adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
391adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
392976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void ensureGroupStateLoadedLocked(int userId) {
393976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
394742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
395976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Careful lad, we may have already loaded the state for some
396976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // group members, so check before loading and read only the
397976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // state for the new member(s).
398976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int newMemberCount = 0;
399976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int profileIdCount = profileIds.length;
400976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileIdCount; i++) {
401976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
402976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mLoadedUserIds.indexOfKey(profileId) >= 0) {
403976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                profileIds[i] = LOADED_PROFILE_ID;
404976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
405976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                newMemberCount++;
406976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
407742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
408976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
409976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (newMemberCount <= 0) {
410976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
411742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
412976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
413976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int newMemberIndex = 0;
414976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int[] newProfileIds = new int[newMemberCount];
415976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileIdCount; i++) {
416976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
417976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (profileId != LOADED_PROFILE_ID) {
418976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mLoadedUserIds.put(profileId, profileId);
419976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                newProfileIds[newMemberIndex] = profileId;
420976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                newMemberIndex++;
421976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
422742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
423976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
424976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        loadGroupWidgetProvidersLocked(newProfileIds);
425976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        loadGroupStateLocked(newProfileIds);
426742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
427742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
428976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
429976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
430742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
431742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                != PackageManager.PERMISSION_GRANTED) {
432976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            throw new SecurityException("Permission Denial: can't dump from from pid="
433742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    + Binder.getCallingPid()
434742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    + ", uid=" + Binder.getCallingUid());
435742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
436742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
437976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
438976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int N = mProviders.size();
439742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println("Providers:");
440976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
441976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                dumpProvider(mProviders.get(i), i, pw);
442742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
443742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
444976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            N = mWidgets.size();
445742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println(" ");
446976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.println("Widgets:");
447976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
448976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                dumpWidget(mWidgets.get(i), i, pw);
449742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
450742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
451742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            N = mHosts.size();
452742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println(" ");
453742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println("Hosts:");
454976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
455742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                dumpHost(mHosts.get(i), i, pw);
456742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
457742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
458742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
459976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            N = mPackagesWithBindWidgetPermission.size();
460742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            pw.println(" ");
461976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.println("Grants:");
462976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
463976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Pair<Integer, String> grant = mPackagesWithBindWidgetPermission.valueAt(i);
464976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                dumpGrant(grant, i, pw);
465742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
466742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
467742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
468742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
469976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
470976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public int[] startListening(IAppWidgetHost callbacks, String callingPackage,
471976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int hostId, List<RemoteViews> updatedViews) {
472976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
473976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
474976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
475976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "startListening() " + userId);
476742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
477742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
478976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
479976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
480742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
481976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
482976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
483742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
484976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
485976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access hosts it owns.
486976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
487976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupOrAddHostLocked(id);
488742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
489976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            host.callbacks = callbacks;
490742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
491976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            updatedViews.clear();
492742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
493976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<Widget> instances = host.widgets;
494976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int N = instances.size();
495976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int[] updatedIds = new int[N];
496976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
497976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = instances.get(i);
498976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                updatedIds[i] = widget.appWidgetId;
499976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                updatedViews.add(cloneIfLocalBinder(widget.views));
500742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
501976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
502976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return updatedIds;
503742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
504742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
505742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
506976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
507976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void stopListening(String callingPackage, int hostId) {
508976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
509976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
510976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
511976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "stopListening() " + userId);
512742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
513742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
514976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
515976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
516976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
517976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
518976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
519976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
520976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
521976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access hosts it owns.
522976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
523976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupHostLocked(id);
524976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
525976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host != null) {
526976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
527976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                pruneHostLocked(host);
528742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
529742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
530742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
531742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
532976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
533976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public int allocateAppWidgetId(String callingPackage, int hostId) {
534976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
535976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
536976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
537976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "allocateAppWidgetId() " + userId);
538742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
539742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
540976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
541976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
542742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
543976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
544976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
545742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
546976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mNextAppWidgetIds.indexOfKey(userId) < 0) {
547976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mNextAppWidgetIds.put(userId, AppWidgetManager.INVALID_APPWIDGET_ID + 1);
548976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
549742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
550976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int appWidgetId = incrementAndGetAppWidgetIdLocked(userId);
551742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
552976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
553976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access hosts it owns.
554976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
555976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupOrAddHostLocked(id);
556976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
557976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = new Widget();
558976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.appWidgetId = appWidgetId;
559976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host = host;
560976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
561976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            host.widgets.add(widget);
562976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mWidgets.add(widget);
563976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
564976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
565976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
566976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
567976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Allocated widget id " + appWidgetId
568976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for host " + host.id);
569742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
570976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
571976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return appWidgetId;
572742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
573742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
574742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
575976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
576976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void deleteAppWidgetId(String callingPackage, int appWidgetId) {
577976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
578976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
579976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
580976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "deleteAppWidgetId() " + userId);
581742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
582742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
583976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
584976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
585742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
586976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
587976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
5880aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen
589976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
590976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
591976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
592976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
5930aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen
594976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
595976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return;
596976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
597742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
598976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            deleteAppWidgetLocked(widget);
599742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
600976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
601976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
602976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
603976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Deleted widget id " + appWidgetId
604976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for host " + widget.host.id);
605742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
606742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
607742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
608742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
609976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
610976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public boolean hasBindAppWidgetPermission(String packageName, int grantId) {
611976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
612976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "hasBindAppWidgetPermission() " + UserHandle.getCallingUserId());
613119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
614976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
615976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // A special permission is required for managing white listing.
616976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceModifyAppWidgetBindPermissions(packageName);
617976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
618976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
619976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // The grants are stored in user state wich gets the grant.
620976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(grantId);
621976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
622976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int packageUid = getUidForPackage(packageName, grantId);
623976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageUid < 0) {
62461a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                return false;
62561a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka            }
626976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
627976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, String> packageId = Pair.create(grantId, packageName);
628976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return mPackagesWithBindWidgetPermission.contains(packageId);
62961a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka        }
63061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka    }
63161a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
632976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
633976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void setBindAppWidgetPermission(String packageName, int grantId,
634976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            boolean grantPermission) {
635976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
636976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "setBindAppWidgetPermission() " + UserHandle.getCallingUserId());
63761a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka        }
638976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
639976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // A special permission is required for managing white listing.
640976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceModifyAppWidgetBindPermissions(packageName);
641976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
642976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
643976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // The grants are stored in user state wich gets the grant.
644976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(grantId);
645976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
646976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int packageUid = getUidForPackage(packageName, grantId);
647976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageUid < 0) {
648976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return;
649976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
650976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
651976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, String> packageId = Pair.create(grantId, packageName);
652976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (grantPermission) {
653976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mPackagesWithBindWidgetPermission.add(packageId);
654976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
655976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mPackagesWithBindWidgetPermission.remove(packageId);
656976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
657976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
658976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(grantId);
65961a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka        }
66061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka    }
66161a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
662976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
663976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public IntentSender createAppWidgetConfigIntentSender(String callingPackage, Intent intent) {
664976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
665976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
666976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
667976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "createAppWidgetConfigIntentSender() " + userId);
668119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
66961a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
670976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
671976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
672976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
673976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // The only allowed action is the one to start the configure activity.
674976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
675976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            throw new IllegalArgumentException("Only allowed action is "
676976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
67761a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka        }
67861a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
679976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Verify that widget id is provided.
680976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
681976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                AppWidgetManager.INVALID_APPWIDGET_ID);
682976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
683976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            throw new IllegalArgumentException("Widget id required");
684119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
68561a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
686976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure a component name is provided.
687976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ComponentName component = intent.getComponent();
688976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (component == null) {
689976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            throw new IllegalArgumentException("Component name required");
69061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka        }
69161a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
692976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Verify the user handle.
693976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        UserHandle userHandle = intent.getParcelableExtra(
694976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE);
695976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (userHandle != null) {
696976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove the profile extra as the receiver already runs under this
697976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // user and this information is of no use to this receiver.
698976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.removeExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE);
699976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
700976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // If the user handle is not the caller, check if it is an enabled
701976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // profile for which the package is white-listed.
702976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = userHandle.getIdentifier();
703976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (profileId != userId) {
704976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Make sure the passed user handle is a profile in the group.
705976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int[] profileIds = mSecurityPolicy.resolveCallerEnabledGroupProfiles(
706976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        new int[]{profileId});
707976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (profileIds.length <= 0) {
708976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // The profile is not in the group or not enabled, done.
709976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return null;
710976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
711976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
712976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Make sure the provider is white-listed.
713976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed(
714976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        component.getPackageName(), profileId)) {
715976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    throw new IllegalArgumentException("Cannot access provider "
716976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            + component + " in user " + profileIds);
717976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
718119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
719976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } else {
720976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // If a profile is not specified use the caller user id.
721976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            userHandle = new UserHandle(userId);
722976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
723976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
724976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
725976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
726976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
727976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
728976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
729976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
730976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
731976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
732976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
733976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("Bad widget id " + appWidgetId);
734742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
735976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
736976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = widget.provider;
737976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider == null) {
738976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("Widget not bound " + appWidgetId);
739742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
740742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
741976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Make sure the component refers to the provider config activity.
742976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!component.equals(provider.info.configure)
743976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    || !provider.info.getProfile().equals(userHandle)) {
744976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("No component" + component
745976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for user " + userHandle.getIdentifier());
7461c5bffbf5bae6762c8df07350abca61e460653bbAdam Cohen            }
7471c5bffbf5bae6762c8df07350abca61e460653bbAdam Cohen
748976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // All right, create the sender.
749976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
750742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            try {
751976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return PendingIntent.getActivityAsUser(
752976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
753976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                | PendingIntent.FLAG_CANCEL_CURRENT, null, userHandle)
754976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        .getIntentSender();
755742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            } finally {
756976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
757742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
758742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
759742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
760742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
761976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
762976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public boolean bindAppWidgetId(String callingPackage, int appWidgetId,
763976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int providerProfileId, ComponentName providerComponent, Bundle options) {
764976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
765976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
766976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
767976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "bindAppWidgetId() " + userId);
768976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
769976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
770976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
771976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
772976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
773976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Check that if a cross-profile binding is attempted, it is allowed.
774976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int[] profileIds = mSecurityPolicy.resolveCallerEnabledGroupProfiles(
775976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                new int[] {providerProfileId});
776976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (profileIds.length <= 0) {
777976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
778976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
779976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
780976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // If the provider is not under the calling user, make sure this
781976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // provider is white listed for access from the parent.
782976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed(
783976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                providerComponent.getPackageName(), providerProfileId)) {
784976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
785976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
786976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
787976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
788976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
789976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
790976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // A special permission or white listing is required to bind widgets.
791976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!mSecurityPolicy.hasCallerBindPermissionOrBindWhiteListedLocked(
792976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    callingPackage)) {
793976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
794119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
795742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
796976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
797976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
798976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
799976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
800976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
801976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
802976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Bad widget id " + appWidgetId);
803976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
804742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
805742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
806976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.provider != null) {
807976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Widget id " + appWidgetId
808976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " already bound to: " + widget.provider.id);
809976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
810742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
811742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
812976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int providerUid = getUidForPackage(providerComponent.getPackageName(),
813976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    providerProfileId);
814976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (providerUid < 0) {
815976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Package " + providerComponent.getPackageName() + " not installed "
816976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for profile " + providerProfileId);
817976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
818976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
819742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
820976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
821976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the provider is in the already vetted user profile.
822976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ProviderId providerId = new ProviderId(providerUid, providerComponent);
823976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = lookupProviderLocked(providerId);
824976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
825976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider == null) {
826976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "No widget provider " + providerComponent + " for profile "
827976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + providerProfileId);
828976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
829742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
830742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
831976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider.zombie) {
832976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Can't bind to a 3rd party provider in"
833976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " safe mode " + provider);
834976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
835742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
836742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
837976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.provider = provider;
838976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle();
839976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
840976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // We need to provide a default value for the widget category if it is not specified
841976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
842976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
843976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
844976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
845976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
846976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.widgets.add(widget);
847976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
848976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int widgetCount = provider.widgets.size();
849976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widgetCount == 1) {
850976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Tell the provider that it's ready.
851976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sendEnableIntentLocked(provider);
852976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
853976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
854976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Send an update now -- We need this update now, and just for this appWidgetId.
855976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // It's less critical when the next one happens, so when we schedule the next one,
856976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // we add updatePeriodMillis to its start time. That time will have some slop,
857976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // but that's okay.
858976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            sendUpdateIntentLocked(provider, new int[] {appWidgetId});
859976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
860976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Schedule the future updates.
861976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            registerForBroadcastsLocked(provider, getWidgetIds(provider.widgets));
862976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
863976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
864976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
865976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
866976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Bound widget " + appWidgetId + " to provider " + provider.id);
867976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
868742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
869976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
870976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return true;
871742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
872742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
873976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
874976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public int[] getAppWidgetIds(ComponentName componentName) {
875976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
876976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
877976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
878976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetIds() " + userId);
879742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
880742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
881976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
882976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
883976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
884976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
885976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
886976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
887976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
888976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can access only its providers.
889976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
890976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = lookupProviderLocked(providerId);
891976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
892976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider != null) {
893976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return getWidgetIds(provider.widgets);
894742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
895976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
896976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return new int[0];
897742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
898742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
899742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
900976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
901976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public int[] getAppWidgetIdsForHost(String callingPackage, int hostId) {
902976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
903976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
904976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
905976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetIdsForHost() " + userId);
906976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
907976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
908976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
909976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
910976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
911976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
912976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
913976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
914976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
915976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access its hosts.
916976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
917976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupHostLocked(id);
918976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
919976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host != null) {
920976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return getWidgetIds(host.widgets);
921742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
922976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
923976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return new int[0];
924742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
925742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
926742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
927976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
928976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void bindRemoteViewsService(String callingPackage, int appWidgetId,
929976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Intent intent, IBinder callbacks) {
930976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
931976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
932976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
933976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "bindRemoteViewsService() " + userId);
934976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
935976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
936976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
937976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
938976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
939976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
940976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
941976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
942976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
943976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
944976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
945976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("Bad widget id");
946119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
947976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
948976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Make sure the widget has a provider.
949976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.provider == null) {
950976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("No provider for widget "
951976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + appWidgetId);
952742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
953742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
954976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ComponentName componentName = intent.getComponent();
955976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
956976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Ensure that the service belongs to the same package as the provider.
957976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // But this is not enough as they may be under different users - see below...
958976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String providerPackage = widget.provider.id.componentName.getPackageName();
959976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String servicePackage = componentName.getPackageName();
960976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!servicePackage.equals(providerPackage)) {
961976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new SecurityException("The taget service not in the same package"
962976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " as the widget provider");
963119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
964976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
965976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Make sure this service exists under the same user as the provider and
966976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // requires a permission which allows only the system to bind to it.
967976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mSecurityPolicy.enforceServiceExistsAndRequiresBindRemoteViewsPermission(
968976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    componentName, widget.provider.getUserId());
969976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
970976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Good to go - the service pakcage is correct, it exists for the correct
971976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // user, and requires the bind permission.
972976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
973976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // If there is already a connection made for this service intent, then
974976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // disconnect from that first. (This does not allow multiple connections
975976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // to the same service under the same key).
976976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ServiceConnectionProxy connection = null;
977976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            FilterComparison fc = new FilterComparison(intent);
978976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId, fc);
979976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
980976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mBoundRemoteViewsServices.containsKey(key)) {
981976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                connection = (ServiceConnectionProxy) mBoundRemoteViewsServices.get(key);
982976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                connection.disconnect();
983976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                unbindService(connection);
984976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mBoundRemoteViewsServices.remove(key);
985742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
986976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
987976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Bind to the RemoteViewsService (which will trigger a callback to the
988976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // RemoteViewsAdapter.onServiceConnected())
989976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            connection = new ServiceConnectionProxy(callbacks);
990976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            bindService(intent, connection, widget.provider.info.getProfile());
991976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mBoundRemoteViewsServices.put(key, connection);
992976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
993976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Add it to the mapping of RemoteViewsService to appWidgetIds so that we
994976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // can determine when we can call back to the RemoteViewsService later to
995976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // destroy associated factories.
996976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, FilterComparison> serviceId = Pair.create(widget.provider.id.uid, fc);
997976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            incrementAppWidgetServiceRefCount(appWidgetId, serviceId);
998742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
999742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1000742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1001976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1002976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void unbindRemoteViewsService(String callingPackage, int appWidgetId, Intent intent) {
1003976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1004311c79c3e93589c6fc720fe6c58ed522af591376Adam Cohen
1005976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1006976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "unbindRemoteViewsService() " + userId);
1007742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1008742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1009976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1010976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1011976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1012976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1013976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1014976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1015976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Unbind from the RemoteViewsService (which will trigger a callback to the bound
1016976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // RemoteViewsAdapter)
1017976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, FilterComparison> key = Pair.create(appWidgetId,
1018976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    new FilterComparison(intent));
1019976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mBoundRemoteViewsServices.containsKey(key)) {
1020976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // We don't need to use the appWidgetId until after we are sure there is something
1021976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // to unbind. Note that this may mask certain issues with apps calling unbind()
1022976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // more than necessary.
1023976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1024976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // NOTE: The lookup is enforcing security across users by making
1025976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // sure the caller can only access widgets it hosts or provides.
1026976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = lookupWidgetLocked(appWidgetId,
1027976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Binder.getCallingUid(), callingPackage);
1028976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1029976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget == null) {
1030976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    throw new IllegalArgumentException("Bad widget id " + appWidgetId);
1031976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1032976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1033976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ServiceConnectionProxy connection = (ServiceConnectionProxy)
1034976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        mBoundRemoteViewsServices.get(key);
1035976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                connection.disconnect();
1036976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mContext.unbindService(connection);
1037976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mBoundRemoteViewsServices.remove(key);
1038742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1039742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1040742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1041742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1042976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1043976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void deleteHost(String callingPackage, int hostId) {
1044976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1045a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen
1046976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1047976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "deleteHost() " + userId);
1048a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen        }
1049a1a2f967e2a0de4c4190a775ac314ad32288727eAdam Cohen
1050976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1051976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1052976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1053976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1054976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1055976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1056976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1057976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access hosts in its uid and package.
1058976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId id = new HostId(Binder.getCallingUid(), hostId, callingPackage);
1059976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupHostLocked(id);
1060e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen
1061976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host == null) {
1062e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen                return;
1063e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen            }
10640aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen
1065976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            deleteHostLocked(host);
1066e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen
1067976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
1068e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen
1069976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
1070976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Deleted host " + host.id);
1071e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen            }
1072e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen        }
1073e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen    }
1074e8724c82ab1479f13c85a2c6219841e1fd95f2d2Adam Cohen
1075976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1076976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void deleteAllHosts() {
1077976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1078976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1079976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1080976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "deleteAllHosts() " + userId);
1081742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1082742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1083976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1084976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1085976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1086976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            boolean changed = false;
1087976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1088976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = mHosts.size();
1089976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = N - 1; i >= 0; i--) {
1090976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Host host = mHosts.get(i);
1091976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1092976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Delete only hosts in the calling uid.
1093976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (host.id.uid == Binder.getCallingUid()) {
1094976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    deleteHostLocked(host);
1095976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    changed = true;
1096976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1097976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
1098976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "Deleted host " + host.id);
1099976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
11006611988429d1d70ec429f87bbf2b093cf1e2e31fWinson Chung                }
1101742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1102976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1103976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (changed) {
1104976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                saveGroupStateAsync(userId);
1105976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1106742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1107742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1108742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1109976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1110976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public AppWidgetProviderInfo getAppWidgetInfo(String callingPackage, int appWidgetId) {
1111976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1112976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1113976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1114976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetInfo() " + userId);
1115119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
1116976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1117976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1118976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1119976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1120976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1121976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1122976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1123976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1124976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
1125976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
1126976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
1127976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1128976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget != null && widget.provider != null && !widget.provider.zombie) {
1129976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return cloneIfLocalBinder(widget.provider.info);
1130976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1131976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1132976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
1133742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1134976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1135976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1136976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1137976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public RemoteViews getAppWidgetViews(String callingPackage, int appWidgetId) {
1138976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1139976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1140976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1141976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetViews() " + userId);
1142742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1143742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1144976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1145976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1146976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1147976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1148976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1149976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1150976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1151976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
1152976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
1153976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
1154976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1155976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget != null) {
1156976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return cloneIfLocalBinder(widget.views);
1157742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1158976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1159976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
1160742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1161742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1162742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1163976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1164976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void updateAppWidgetOptions(String callingPackage, int appWidgetId, Bundle options) {
1165976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1166976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1167976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1168976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "updateAppWidgetOptions() " + userId);
1169119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
1170976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1171976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1172976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1173976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1174976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1175976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1176976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1177976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1178976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
1179976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
1180976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
1181976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1182976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget == null) {
1183742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return;
1184742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1185976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1186976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Merge the options.
1187976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.options.putAll(options);
1188976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1189976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Send the broacast to notify the provider that options changed.
1190976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            sendOptionsChangedIntentLocked(widget);
1191976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1192976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            saveGroupStateAsync(userId);
1193742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1194742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1195742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1196976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1197976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public Bundle getAppWidgetOptions(String callingPackage, int appWidgetId) {
1198976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1199742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1200976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1201976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getAppWidgetOptions() " + userId);
1202976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1203742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1204976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1205976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1206742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1207976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1208976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1209976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1210976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1211976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can only access widgets it hosts or provides.
1212976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = lookupWidgetLocked(appWidgetId,
1213976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Binder.getCallingUid(), callingPackage);
1214976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1215976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget != null && widget.options != null) {
1216976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return cloneIfLocalBinder(widget.options);
1217742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1218976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1219976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return Bundle.EMPTY;
1220742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1221742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1222742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1223976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1224976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void updateAppWidgetIds(String callingPackage, int[] appWidgetIds,
1225976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            RemoteViews views) {
1226976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1227976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "updateAppWidgetIds() " + UserHandle.getCallingUserId());
1228976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1229742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1230976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        updateAppWidgetIds(callingPackage, appWidgetIds, views, false);
1231976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1232742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1233976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1234976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void partiallyUpdateAppWidgetIds(String callingPackage, int[] appWidgetIds,
1235976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            RemoteViews views) {
1236976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1237976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "partiallyUpdateAppWidgetIds() " + UserHandle.getCallingUserId());
1238742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1239742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1240976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        updateAppWidgetIds(callingPackage, appWidgetIds, views, true);
12413ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen    }
12423ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen
1243976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1244976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void notifyAppWidgetViewDataChanged(String callingPackage, int[] appWidgetIds,
1245976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int viewId) {
1246976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
12473ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen
1248976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1249976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "notifyAppWidgetViewDataChanged() " + userId);
12503ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen        }
12513ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen
1252976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1253976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
12543ff2d867d46067132890a5a6ad68be8a4314d7f6Adam Cohen
1255976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (appWidgetIds == null || appWidgetIds.length == 0) {
1256976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1257119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
1258742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1259976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1260976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1261742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1262976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = appWidgetIds.length;
1263742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
1264976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int appWidgetId = appWidgetIds[i];
1265976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1266976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // NOTE: The lookup is enforcing security across users by making
1267976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // sure the caller can only access widgets it hosts or provides.
1268976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = lookupWidgetLocked(appWidgetId,
1269976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Binder.getCallingUid(), callingPackage);
1270976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1271976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget != null) {
1272976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    scheduleNotifyAppWidgetViewDataChanged(widget, viewId);
1273976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1274742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1275742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1276742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1277742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1278976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1279976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void updateAppWidgetProvider(ComponentName componentName, RemoteViews views) {
1280976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1281976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1282976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1283976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "updateAppWidgetProvider() " + userId);
1284976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1285976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1286976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1287976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(componentName.getPackageName());
1288976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1289976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1290976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1291976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1292976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // NOTE: The lookup is enforcing security across users by making
1293976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // sure the caller can access only its providers.
1294976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ProviderId providerId = new ProviderId(Binder.getCallingUid(), componentName);
1295976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = lookupProviderLocked(providerId);
1296976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1297976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider == null) {
1298976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.w(TAG, "Provider doesn't exist " + providerId);
1299119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn                return;
1300119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn            }
1301976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1302976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<Widget> instances = provider.widgets;
1303976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = instances.size();
1304976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
1305976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = instances.get(i);
1306976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                updateAppWidgetInstanceLocked(widget, views, false);
1307742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1308742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1309742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1310742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1311976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
1312976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int[] profileIds) {
1313976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1314976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1315976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1316976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "getInstalledProvidersForProfiles() " + userId);
1317742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1318976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1319976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (profileIds != null && profileIds.length > 0) {
1320976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Make sure the profile ids are children of the calling user.
1321976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            profileIds = mSecurityPolicy.resolveCallerEnabledGroupProfiles(profileIds);
1322976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } else {
1323976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            profileIds = new int[] {userId};
1324742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1325742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1326976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (profileIds.length == 0) {
1327976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
1328742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1329742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1330976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1331976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1332adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1333976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<AppWidgetProviderInfo> result = new ArrayList<>();
1334742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1335976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int providerCount = mProviders.size();
1336976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < providerCount; i++) {
1337976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
1338976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                AppWidgetProviderInfo info = provider.info;
1339976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1340976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Ignore an invalid provider or one not matching the filter.
1341976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.zombie || (info.widgetCategory & categoryFilter) == 0) {
1342976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
1343976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1344976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1345976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Add providers only for the requested profiles ...
1346976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int providerProfileId = info.getProfile().getIdentifier();
1347976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int profileCount = profileIds.length;
1348976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (int j = 0; j < profileCount; j++) {
1349976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int profileId = profileIds[j];
1350976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (providerProfileId == profileId) {
1351976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // ... that are white-listed by the profile manager.
1352976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed(
1353976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                provider.id.componentName.getPackageName(), providerProfileId)) {
1354976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            result.add(cloneIfLocalBinder(info));
1355976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
1356976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        break;
1357976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
1358976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1359742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1360976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1361976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return result;
1362742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1363742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1364742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1365976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void updateAppWidgetIds(String callingPackage, int[] appWidgetIds,
1366976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            RemoteViews views, boolean partially) {
1367976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int userId = UserHandle.getCallingUserId();
1368976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1369976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (appWidgetIds == null || appWidgetIds.length == 0) {
1370976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1371742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1372742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1373976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Make sure the package runs under the caller uid.
1374976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSecurityPolicy.enforceCallFromPackage(callingPackage);
1375976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1376976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int bitmapMemoryUsage = (views != null) ? views.estimateMemoryUsage() : 0;
1377976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (bitmapMemoryUsage > mMaxWidgetBitmapMemory) {
1378976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            throw new IllegalArgumentException("RemoteViews for widget update exceeds"
1379976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + " maximum bitmap memory usage (used: " + bitmapMemoryUsage
1380976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + ", max: " + mMaxWidgetBitmapMemory + ")");
1381742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1382742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1383976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1384976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
1385742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1386976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = appWidgetIds.length;
1387483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            for (int i = 0; i < N; i++) {
1388976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int appWidgetId = appWidgetIds[i];
1389976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1390976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // NOTE: The lookup is enforcing security across users by making
1391976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // sure the caller can only access widgets it hosts or provides.
1392976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = lookupWidgetLocked(appWidgetId,
1393976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Binder.getCallingUid(), callingPackage);
1394976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1395976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget != null) {
1396976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    updateAppWidgetInstanceLocked(widget, views, partially);
1397976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1398483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            }
1399742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1400742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1401742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1402976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int incrementAndGetAppWidgetIdLocked(int userId) {
1403976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int appWidgetId = peekNextAppWidgetIdLocked(userId) + 1;
1404976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mNextAppWidgetIds.put(userId, appWidgetId);
1405976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return appWidgetId;
1406976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1407976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1408976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void setMinAppWidgetIdLocked(int userId, int minWidgetId) {
1409976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int nextAppWidgetId = peekNextAppWidgetIdLocked(userId);
1410976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (nextAppWidgetId < minWidgetId) {
1411976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mNextAppWidgetIds.put(userId, minWidgetId);
1412742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1413976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1414976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1415976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int peekNextAppWidgetIdLocked(int userId) {
1416976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (mNextAppWidgetIds.indexOfKey(userId) < 0) {
1417976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return AppWidgetManager.INVALID_APPWIDGET_ID + 1;
1418742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } else {
1419976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return mNextAppWidgetIds.get(userId);
1420742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1421742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1422742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1423976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Host lookupOrAddHostLocked(HostId id) {
1424976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Host host = lookupHostLocked(id);
1425976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (host != null) {
1426976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return host;
1427976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1428976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1429976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        host = new Host();
1430976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        host.id = id;
1431976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mHosts.add(host);
1432976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1433976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return host;
1434742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1435742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1436976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void deleteHostLocked(Host host) {
1437976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = host.widgets.size();
1438976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = N - 1; i >= 0; i--) {
1439976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = host.widgets.remove(i);
1440976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            deleteAppWidgetLocked(widget);
1441976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1442976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mHosts.remove(host);
1443976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1444976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // it's gone or going away, abruptly drop the callback connection
1445976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        host.callbacks = null;
1446742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1447742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1448976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void deleteAppWidgetLocked(Widget widget) {
1449976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We first unbind all services that are bound to this id
1450976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        unbindAppWidgetRemoteViewsServicesLocked(widget);
1451976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1452976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Host host = widget.host;
1453976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        host.widgets.remove(widget);
1454976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pruneHostLocked(host);
1455976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1456976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mWidgets.remove(widget);
1457976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1458976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Provider provider = widget.provider;
1459976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (provider != null) {
1460976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.widgets.remove(widget);
1461976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!provider.zombie) {
1462976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // send the broacast saying that this appWidgetId has been deleted
1463976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sendDeletedIntentLocked(widget);
1464976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1465976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.widgets.isEmpty()) {
1466976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // cancel the future updates
1467976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    cancelBroadcasts(provider);
1468976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1469976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // send the broacast saying that the provider is not in use any more
1470976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    sendDisabledIntentLocked(provider);
1471976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1472976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1473742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1474742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1475742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1476976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void cancelBroadcasts(Provider provider) {
1477976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (DEBUG) {
1478976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.i(TAG, "cancelBroadcasts() for " + provider);
1479976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1480976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (provider.broadcast != null) {
1481976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mAlarmManager.cancel(provider.broadcast);
1482742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            long token = Binder.clearCallingIdentity();
1483742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            try {
1484976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                provider.broadcast.cancel();
1485742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            } finally {
1486742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                Binder.restoreCallingIdentity(token);
1487742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1488976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.broadcast = null;
1489742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1490742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1491742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1492976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Unbinds from a RemoteViewsService when we delete an app widget
1493976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void unbindAppWidgetRemoteViewsServicesLocked(Widget widget) {
1494976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int appWidgetId = widget.appWidgetId;
1495976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Unbind all connections to Services bound to this AppWidgetId
1496976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Iterator<Pair<Integer, Intent.FilterComparison>> it = mBoundRemoteViewsServices.keySet()
1497976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                .iterator();
1498976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        while (it.hasNext()) {
1499976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final Pair<Integer, Intent.FilterComparison> key = it.next();
1500976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (key.first == appWidgetId) {
1501976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final ServiceConnectionProxy conn = (ServiceConnectionProxy)
1502976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        mBoundRemoteViewsServices.get(key);
1503976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                conn.disconnect();
1504976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mContext.unbindService(conn);
1505976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                it.remove();
1506976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1507742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1508976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1509976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Check if we need to destroy any services (if no other app widgets are
1510976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // referencing the same service)
1511976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        decrementAppWidgetServiceRefCount(widget);
1512742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1513742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1514976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Destroys the cached factory on the RemoteViewsService's side related to the specified intent
1515976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void destroyRemoteViewsService(final Intent intent, Widget widget) {
1516976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final ServiceConnection conn = new ServiceConnection() {
1517976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            @Override
1518976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public void onServiceConnected(ComponentName name, IBinder service) {
1519976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final IRemoteViewsFactory cb = IRemoteViewsFactory.Stub.asInterface(service);
1520976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                try {
1521976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    cb.onDestroy(intent);
1522976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } catch (RemoteException re) {
1523976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.e(TAG, "Error calling remove view factory", re);
1524976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1525976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mContext.unbindService(this);
1526742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
1527976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1528976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            @Override
1529976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public void onServiceDisconnected(ComponentName name) {
1530976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Do nothing
1531976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1532976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        };
1533976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1534976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Bind to the service and remove the static intent->factory mapping in the
1535976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // RemoteViewsService.
1536976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long token = Binder.clearCallingIdentity();
1537976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1538976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE,
1539976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    widget.provider.info.getProfile());
1540976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
1541976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(token);
1542742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
1543742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
1544742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
1545976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Adds to the ref-count for a given RemoteViewsService intent
1546976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void incrementAppWidgetServiceRefCount(int appWidgetId,
1547976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Pair<Integer, FilterComparison> serviceId) {
1548976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        HashSet<Integer> appWidgetIds = null;
1549976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (mRemoteViewsServicesAppWidgets.containsKey(serviceId)) {
1550976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            appWidgetIds = mRemoteViewsServicesAppWidgets.get(serviceId);
1551976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } else {
1552976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            appWidgetIds = new HashSet<>();
1553976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mRemoteViewsServicesAppWidgets.put(serviceId, appWidgetIds);
155475b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka        }
1555976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        appWidgetIds.add(appWidgetId);
155675b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka    }
155775b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka
1558976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
1559976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    // the ref-count reaches zero.
1560976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void decrementAppWidgetServiceRefCount(Widget widget) {
1561976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Iterator<Pair<Integer, FilterComparison>> it = mRemoteViewsServicesAppWidgets
1562976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                .keySet().iterator();
1563976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        while (it.hasNext()) {
1564976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final Pair<Integer, FilterComparison> key = it.next();
1565976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
1566976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (ids.remove(widget.appWidgetId)) {
1567976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // If we have removed the last app widget referencing this service, then we
1568976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // should destroy it and remove it from this set
1569976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (ids.isEmpty()) {
1570976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    destroyRemoteViewsService(key.second.getIntent(), widget);
1571976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    it.remove();
1572976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
157375b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka            }
157475b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka        }
157575b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka    }
157675b5cfb4a41030333820d072578a288d4ec9899cMichael Jurka
1577976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void saveGroupStateAsync(int groupId) {
1578976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mSaveStateHandler.post(new SaveStateRunnable(groupId));
1579976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1580976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1581976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void updateAppWidgetInstanceLocked(Widget widget, RemoteViews views,
1582976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            boolean isPartialUpdate) {
1583976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget != null && widget.provider != null
1584976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                && !widget.provider.zombie && !widget.host.zombie) {
1585976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1586976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (isPartialUpdate && widget.views != null) {
1587976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // For a partial update, we merge the new RemoteViews with the old.
1588976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                widget.views.mergeRemoteViews(views);
1589976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
1590976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // For a full update we replace the RemoteViews completely.
1591976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                widget.views = views;
1592adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1593976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1594976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            scheduleNotifyUpdateAppWidgetLocked(widget);
1595adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1596adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1597adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1598976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) {
1599976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget == null || widget.host == null || widget.host.zombie
1600976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                || widget.host.callbacks == null || widget.provider == null
1601976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                || widget.provider.zombie) {
1602976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1603976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1604976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1605976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        SomeArgs args = SomeArgs.obtain();
1606976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg1 = widget.host;
1607976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg2 = widget.host.callbacks;
1608976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.argi1 = widget.appWidgetId;
1609976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.argi2 = viewId;
1610976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1611976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mCallbackHandler.obtainMessage(
1612976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                CallbackHandler.MSG_NOTIFY_VIEW_DATA_CHANGED,
1613976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                args).sendToTarget();
1614adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1615adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1616976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1617976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
1618976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int appWidgetId, int viewId) {
1619976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1620976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks.viewDataChanged(appWidgetId, viewId);
1621976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
1622976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // It failed; remove the callback. No need to prune because
1623976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // we know that this host is still referenced by this instance.
1624976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks = null;
1625976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1626976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1627976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // If the host is unavailable, then we call the associated
1628976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // RemoteViewsFactory.onDataSetChanged() directly
1629976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
1630976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (callbacks == null) {
1631976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
1632976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1633976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Set<Pair<Integer, FilterComparison>> keys = mRemoteViewsServicesAppWidgets.keySet();
1634976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (Pair<Integer, FilterComparison> key : keys) {
1635976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (mRemoteViewsServicesAppWidgets.get(key).contains(appWidgetId)) {
1636976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final ServiceConnection connection = new ServiceConnection() {
1637976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            @Override
1638976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            public void onServiceConnected(ComponentName name, IBinder service) {
1639976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                IRemoteViewsFactory cb = IRemoteViewsFactory.Stub
1640976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        .asInterface(service);
1641976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                try {
1642976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    cb.onDataSetChangedAsync();
1643976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                } catch (RemoteException e) {
1644976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.e(TAG, "Error calling onDataSetChangedAsync()", e);
1645976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
1646976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                mContext.unbindService(this);
1647976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
1648976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1649976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            @Override
1650976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            public void onServiceDisconnected(android.content.ComponentName name) {
1651976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // Do nothing
1652976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
1653976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        };
1654976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1655976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int userId = UserHandle.getUserId(key.first);
1656976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Intent intent = key.second.getIntent();
1657976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1658976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // Bind to the service and call onDataSetChanged()
1659976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        bindService(intent, connection, new UserHandle(userId));
1660976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
1661976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
1662976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1663976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1664adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1665adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1666976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void scheduleNotifyUpdateAppWidgetLocked(Widget widget) {
1667976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget == null || widget.provider == null || widget.provider.zombie
1668976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                || widget.host.callbacks == null || widget.host.zombie) {
1669976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1670976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1671976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1672976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        SomeArgs args = SomeArgs.obtain();
1673976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg1 = widget.host;
1674976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg2 = widget.host.callbacks;
1675976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg3 = widget.views;
1676976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.argi1 = widget.appWidgetId;
1677976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1678976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mCallbackHandler.obtainMessage(
1679976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                CallbackHandler.MSG_NOTIFY_UPDATE_APP_WIDGET,
1680976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                args).sendToTarget();
1681976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1682976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1683976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
1684976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int appWidgetId, RemoteViews views) {
1685976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1686976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks.updateAppWidget(appWidgetId, views);
1687976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
1688976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
1689976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Widget host dead: " + host.id, re);
1690976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
1691976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1692adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1693adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1694adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1695976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void scheduleNotifyProviderChangedLocked(Widget widget) {
1696976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget == null || widget.provider == null || widget.provider.zombie
1697976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                || widget.host.callbacks == null || widget.host.zombie) {
1698976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return;
1699976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1700976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1701976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        SomeArgs args = SomeArgs.obtain();
1702976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg1 = widget.host;
1703976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg2 = widget.host.callbacks;
1704976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.arg3 = widget.provider.info;
1705976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        args.argi1 = widget.appWidgetId;
1706976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1707976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mCallbackHandler.obtainMessage(
1708976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                CallbackHandler.MSG_NOTIFY_PROVIDER_CHANGED,
1709976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                args).sendToTarget();
1710976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1711976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1712976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
1713976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int appWidgetId, AppWidgetProviderInfo info) {
1714976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1715976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks.providerChanged(appWidgetId, info);
1716976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
1717976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock){
1718976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Widget host dead: " + host.id, re);
1719976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
1720976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1721976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1722976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1723976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1724976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void scheduleNotifyHostsForProvidersChangedLocked() {
1725976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = mHosts.size();
1726976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = N - 1; i >= 0; i--) {
1727976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
1728976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1729976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host == null || host.zombie || host.callbacks == null) {
1730976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                continue;
1731976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1732976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1733976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            SomeArgs args = SomeArgs.obtain();
1734976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            args.arg1 = host;
1735976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            args.arg2 = host.callbacks;
1736976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1737976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mCallbackHandler.obtainMessage(
1738976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    CallbackHandler.MSG_NOTIFY_PROVIDERS_CHANGED,
1739976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args).sendToTarget();
1740adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1741976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1742976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1743976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void handleNotifyProvidersChanged(Host host, IAppWidgetHost callbacks) {
1744976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
1745976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            callbacks.providersChanged();
1746976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
1747976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
1748976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Widget host dead: " + host.id, re);
1749976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                host.callbacks = null;
1750976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1751adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1752976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1753976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1754976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static boolean isLocalBinder() {
1755976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return Process.myPid() == Binder.getCallingPid();
1756976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1757976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1758976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static RemoteViews cloneIfLocalBinder(RemoteViews rv) {
1759976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (isLocalBinder() && rv != null) {
1760976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return rv.clone();
1761adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1762976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return rv;
1763976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1764976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1765976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static AppWidgetProviderInfo cloneIfLocalBinder(AppWidgetProviderInfo info) {
1766976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (isLocalBinder() && info != null) {
1767976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return info.clone();
1768adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1769976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return info;
1770976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1771976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1772976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static Bundle cloneIfLocalBinder(Bundle bundle) {
1773976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Note: this is only a shallow copy. For now this will be fine, but it could be problematic
1774976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // if we start adding objects to the options. Further, it would only be an issue if keyguard
1775976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // used such options.
1776976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (isLocalBinder() && bundle != null) {
1777976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return (Bundle) bundle.clone();
1778adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1779976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return bundle;
1780adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1781adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1782976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Widget lookupWidgetLocked(int appWidgetId, int uid, String packageName) {
1783976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = mWidgets.size();
1784adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        for (int i = 0; i < N; i++) {
1785976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = mWidgets.get(i);
1786976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.appWidgetId == appWidgetId
1787976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && mSecurityPolicy.canAccessAppWidget(widget, uid, packageName)) {
1788976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return widget;
1789adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1790976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1791976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
1792976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1793976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1794976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Provider lookupProviderLocked(ProviderId id) {
1795976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = mProviders.size();
1796976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < N; i++) {
1797976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
1798976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider.id.equals(id)) {
1799976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return provider;
1800adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1801adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1802976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
1803adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1804adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1805976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Host lookupHostLocked(HostId hostId) {
1806976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = mHosts.size();
1807976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < N; i++) {
1808976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
1809976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host.id.equals(hostId)) {
1810976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return host;
1811976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1812adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1813976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
1814976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1815adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1816976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void pruneHostLocked(Host host) {
1817976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (host.widgets.size() == 0 && host.callbacks == null) {
1818976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
1819976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Pruning host " + host.id);
1820adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1821976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mHosts.remove(host);
1822976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1823976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1824adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1825976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void loadGroupWidgetProvidersLocked(int[] profileIds) {
1826976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        List<ResolveInfo> allReceivers = null;
1827976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1828adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1829976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int profileCount = profileIds.length;
1830976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileCount; i++) {
1831976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
1832adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1833976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            List<ResolveInfo> receivers = queryIntentReceivers(intent, profileId);
1834976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (receivers != null && !receivers.isEmpty()) {
1835976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (allReceivers == null) {
1836976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    allReceivers = new ArrayList<>();
1837adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                }
1838976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                allReceivers.addAll(receivers);
1839adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1840976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
1841adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1842976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int N = (allReceivers == null) ? 0 : allReceivers.size();
1843976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < N; i++) {
1844976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ResolveInfo receiver = allReceivers.get(i);
1845976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            addProviderLocked(receiver);
1846adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1847adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1848adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1849976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean addProviderLocked(ResolveInfo ri) {
1850976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if ((ri.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
1851976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
1852adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1853976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1854976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!ri.activityInfo.isEnabled()) {
1855976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
1856adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1857adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1858976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ComponentName componentName = new ComponentName(ri.activityInfo.packageName,
1859976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ri.activityInfo.name);
1860976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName);
1861976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1862976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Provider provider = parseProviderInfoXml(providerId, ri);
1863976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (provider != null) {
1864976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // we might have an inactive entry for this provider already due to
1865976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // a preceding restore operation.  if so, fix it up in place; otherwise
1866976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // just add this new one.
1867976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider existing = lookupProviderLocked(providerId);
1868976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1869976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // If the provider was not found it may be because it was restored and
1870976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // we did not know its UID so let us find if there is such one.
1871976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (existing == null) {
1872976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                providerId = new ProviderId(UNKNOWN_UID, componentName);
1873976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                existing = lookupProviderLocked(providerId);
1874adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1875adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1876976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (existing != null) {
1877976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (existing.zombie && !mSafeMode) {
1878976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // it's a placeholder that was set up during an app restore
1879976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    existing.zombie = false;
1880976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    existing.info = provider.info; // the real one filled out from the ResolveInfo
1881976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
1882976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "Provider placeholder now reified: " + existing);
1883976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
1884adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                }
1885976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
1886976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mProviders.add(provider);
1887adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1888976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
1889adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1890adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1891976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return false;
1892976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1893adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1894976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void deleteProviderLocked(Provider provider) {
1895976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int N = provider.widgets.size();
1896976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < N; i++) {
1897976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = provider.widgets.remove(i);
1898976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Call back with empty RemoteViews
1899976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            updateAppWidgetInstanceLocked(widget, null, false);
1900976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // clear out references to this appWidgetId
1901976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host.widgets.remove(widget);
1902976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mWidgets.remove(widget);
1903976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.provider = null;
1904976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pruneHostLocked(widget.host);
1905976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host = null;
1906adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1907976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mProviders.remove(provider);
1908976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1909976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // no need to send the DISABLE broadcast, since the receiver is gone anyway
1910976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        cancelBroadcasts(provider);
1911adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1912adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1913976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendEnableIntentLocked(Provider p) {
1914976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
1915976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(p.info.provider);
1916976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, p.info.getProfile());
1917976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1918adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1919976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds) {
1920976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1921976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
1922976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(provider.info.provider);
1923976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, provider.info.getProfile());
1924adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1925adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1926976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendDeletedIntentLocked(Widget widget) {
1927976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
1928976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(widget.provider.info.provider);
1929976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
1930976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, widget.provider.info.getProfile());
1931976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1932976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1933976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendDisabledIntentLocked(Provider provider) {
1934976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
1935976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(provider.info.provider);
1936976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, provider.info.getProfile());
1937976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1938976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1939976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void sendOptionsChangedIntentLocked(Widget widget) {
1940976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED);
1941976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(widget.provider.info.provider);
1942976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
1943976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, widget.options);
1944976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        sendBroadcastAsUser(intent, widget.provider.info.getProfile());
1945976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
1946976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
1947976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) {
1948976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (provider.info.updatePeriodMillis > 0) {
1949976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // if this is the first instance, set the alarm. otherwise,
1950976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // rely on the fact that we've already set it and that
1951976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // PendingIntent.getBroadcast will update the extras.
1952976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            boolean alreadyRegistered = provider.broadcast != null;
1953976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
1954976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
1955976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.setComponent(provider.info.provider);
1956976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            long token = Binder.clearCallingIdentity();
1957976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
1958976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                provider.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
1959976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        PendingIntent.FLAG_UPDATE_CURRENT, provider.info.getProfile());
1960976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
1961976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(token);
1962976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
1963976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!alreadyRegistered) {
1964976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                long period = provider.info.updatePeriodMillis;
1965976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (period < MIN_UPDATE_PERIOD) {
1966976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    period = MIN_UPDATE_PERIOD;
1967adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                }
1968976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1969976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        SystemClock.elapsedRealtime() + period, period, provider.broadcast);
1970adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate            }
1971adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1972adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1973adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1974976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static int[] getWidgetIds(ArrayList<Widget> widgets) {
1975976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int instancesSize = widgets.size();
1976976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int appWidgetIds[] = new int[instancesSize];
1977976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < instancesSize; i++) {
1978976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            appWidgetIds[i] = widgets.get(i).appWidgetId;
1979adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
1980976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return appWidgetIds;
1981adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate    }
1982adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
1983976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void dumpProvider(Provider provider, int index, PrintWriter pw) {
1984976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        AppWidgetProviderInfo info = provider.info;
1985976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("  ["); pw.print(index); pw.print("] provider ");
1986976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.println(provider.id);
1987976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("    min=("); pw.print(info.minWidth);
1988976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("x"); pw.print(info.minHeight);
1989976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(")   minResize=("); pw.print(info.minResizeWidth);
1990976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("x"); pw.print(info.minResizeHeight);
1991976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(") updatePeriodMillis=");
1992976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(info.updatePeriodMillis);
1993976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" resizeMode=");
1994976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(info.resizeMode);
1995976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(info.widgetCategory);
1996976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" autoAdvanceViewId=");
1997976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(info.autoAdvanceViewId);
1998976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" initialLayout=#");
1999976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(Integer.toHexString(info.initialLayout));
2000976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" initialKeyguardLayout=#");
2001976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(Integer.toHexString(info.initialKeyguardLayout));
2002976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" zombie="); pw.println(provider.zombie);
2003976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2004976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2005976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void dumpHost(Host host, int index, PrintWriter pw) {
2006976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("  ["); pw.print(index); pw.print("] hostId=");
2007976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.println(host.id);
2008976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("    callbacks="); pw.println(host.callbacks);
2009976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("    widgets.size="); pw.print(host.widgets.size());
2010976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" zombie="); pw.println(host.zombie);
2011976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2012976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2013976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void dumpGrant(Pair<Integer, String> grant, int index, PrintWriter pw) {
2014976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("  ["); pw.print(index); pw.print(']');
2015976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" user="); pw.print(grant.first);
2016976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print(" package="); pw.println(grant.second);
2017976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2018976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2019976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void dumpWidget(Widget widget, int index, PrintWriter pw) {
2020976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("  ["); pw.print(index); pw.print("] id=");
2021976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.println(widget.appWidgetId);
2022976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.print("    host=");
2023976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        pw.println(widget.host.id);
2024976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.provider != null) {
2025976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.print("    provider="); pw.println(widget.provider.id);
2026adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
2027976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.host != null) {
2028976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.print("    host.callbacks="); pw.println(widget.host.callbacks);
2029976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2030976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.views != null) {
2031976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pw.print("    views="); pw.println(widget.views);
2032976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2033976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2034976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2035976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void serializeProvider(XmlSerializer out, Provider p) throws IOException {
2036976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.startTag(null, "p");
2037976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "pkg", p.info.provider.getPackageName());
2038976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "cl", p.info.provider.getClassName());
2039976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "tag", Integer.toHexString(p.tag));
2040976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.endTag(null, "p");
2041976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2042976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2043976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void serializeHost(XmlSerializer out, Host host) throws IOException {
2044976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.startTag(null, "h");
2045976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "pkg", host.id.packageName);
2046976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "id", Integer.toHexString(host.id.hostId));
2047976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "tag", Integer.toHexString(host.tag));
2048976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.endTag(null, "h");
2049976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2050adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2051976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static void serializeAppWidget(XmlSerializer out, Widget widget) throws IOException {
2052976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.startTag(null, "g");
2053976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "id", Integer.toHexString(widget.appWidgetId));
2054976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "rid", Integer.toHexString(widget.restoredId));
2055976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.attribute(null, "h", Integer.toHexString(widget.host.tag));
2056976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.provider != null) {
2057976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "p", Integer.toHexString(widget.provider.tag));
2058976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2059976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (widget.options != null) {
2060976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "min_width", Integer.toHexString(widget.options.getInt(
2061976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)));
2062976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "min_height", Integer.toHexString(widget.options.getInt(
2063976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)));
2064976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "max_width", Integer.toHexString(widget.options.getInt(
2065976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)));
2066976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "max_height", Integer.toHexString(widget.options.getInt(
2067976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)));
2068976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            out.attribute(null, "host_category", Integer.toHexString(widget.options.getInt(
2069976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)));
2070adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate        }
2071976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        out.endTag(null, "g");
2072976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2073adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2074976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2075976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public List<String> getWidgetParticipants(int userId) {
2076976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return mBackupRestoreController.getWidgetParticipants(userId);
2077976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2078adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2079976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2080976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public byte[] getWidgetState(String packageName, int userId) {
2081976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return mBackupRestoreController.getWidgetState(packageName, userId);
2082976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2083adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2084976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2085976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void restoreStarting(int userId) {
2086976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mBackupRestoreController.restoreStarting(userId);
2087976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2088adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2089976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2090976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void restoreWidgetState(String packageName, byte[] restoredState, int userId) {
2091976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mBackupRestoreController.restoreWidgetState(packageName, restoredState, userId);
2092976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2093adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2094976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @Override
2095976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    public void restoreFinished(int userId) {
2096976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        mBackupRestoreController.restoreFinished(userId);
2097976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2098adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
2099976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    @SuppressWarnings("deprecation")
2100976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri) {
2101976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Provider provider = null;
2102742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2103742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        ActivityInfo activityInfo = ri.activityInfo;
2104742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        XmlResourceParser parser = null;
2105742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        try {
2106483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(),
2107742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    AppWidgetManager.META_DATA_APPWIDGET_PROVIDER);
2108742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (parser == null) {
2109742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER
2110976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " meta-data for " + "AppWidget provider '" + providerId + '\'');
2111742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return null;
2112742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2113742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2114742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            AttributeSet attrs = Xml.asAttributeSet(parser);
2115742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2116742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            int type;
2117742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2118742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    && type != XmlPullParser.START_TAG) {
2119742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                // drain whitespace, comments, etc.
2120742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2121742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2122742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            String nodeName = parser.getName();
2123742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (!"appwidget-provider".equals(nodeName)) {
2124742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                Slog.w(TAG, "Meta-data does not start with appwidget-provider tag for"
2125976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " AppWidget provider " + providerId.componentName
2126976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for user " + providerId.uid);
2127742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                return null;
2128742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2129742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2130976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider = new Provider();
2131976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.id = providerId;
2132976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            AppWidgetProviderInfo info = provider.info = new AppWidgetProviderInfo();
2133976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            info.provider = providerId.componentName;
2134976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            info.providerInfo = activityInfo;
2135742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2136976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final Resources resources;
2137976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
2138976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
2139976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                resources = mContext.getPackageManager()
2140976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        .getResourcesForApplicationAsUser(activityInfo.packageName,
2141976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                UserHandle.getUserId(providerId.uid));
2142976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
2143976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
2144976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2145742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2146976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            TypedArray sa = resources.obtainAttributes(attrs,
2147742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo);
2148742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2149742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // These dimensions has to be resolved in the application's context.
2150742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // We simply send back the raw complex data, which will be
2151742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // converted to dp in {@link AppWidgetManager#getAppWidgetInfo}.
2152742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            TypedValue value = sa
2153742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    .peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minWidth);
2154742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.minWidth = value != null ? value.data : 0;
2155742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            value = sa.peekValue(com.android.internal.R.styleable.AppWidgetProviderInfo_minHeight);
2156742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.minHeight = value != null ? value.data : 0;
2157742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            value = sa.peekValue(
2158742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeWidth);
2159742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.minResizeWidth = value != null ? value.data : info.minWidth;
2160742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            value = sa.peekValue(
2161742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_minResizeHeight);
2162742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.minResizeHeight = value != null ? value.data : info.minHeight;
2163742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.updatePeriodMillis = sa.getInt(
2164742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_updatePeriodMillis, 0);
2165742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.initialLayout = sa.getResourceId(
2166742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_initialLayout, 0);
21670aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen            info.initialKeyguardLayout = sa.getResourceId(com.android.internal.R.styleable.
21680aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                    AppWidgetProviderInfo_initialKeyguardLayout, 0);
2169976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2170742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            String className = sa
2171742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    .getString(com.android.internal.R.styleable.AppWidgetProviderInfo_configure);
2172742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if (className != null) {
2173976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                info.configure = new ComponentName(providerId.componentName.getPackageName(),
2174976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        className);
2175742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2176483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString();
2177742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.icon = ri.getIconResource();
2178742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.previewImage = sa.getResourceId(
2179742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0);
2180742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.autoAdvanceViewId = sa.getResourceId(
2181742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_autoAdvanceViewId, -1);
2182742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            info.resizeMode = sa.getInt(
2183742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    com.android.internal.R.styleable.AppWidgetProviderInfo_resizeMode,
2184742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    AppWidgetProviderInfo.RESIZE_NONE);
21850aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen            info.widgetCategory = sa.getInt(
2186ca5e341574774379f157a4ea579a1732bd4cf7fbMichael Jurka                    com.android.internal.R.styleable.AppWidgetProviderInfo_widgetCategory,
21870aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                    AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN);
2188742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2189742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            sa.recycle();
2190976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (IOException | PackageManager.NameNotFoundException | XmlPullParserException e) {
2191742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // Ok to catch Exception here, because anything going wrong because
2192742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // of what a client process passes to us should not be fatal for the
2193742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            // system process.
2194976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.w(TAG, "XML parsing failed for AppWidget provider "
2195976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + providerId.componentName + " for user " + providerId.uid, e);
2196742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            return null;
2197742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } finally {
2198976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (parser != null) {
2199742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                parser.close();
2200976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2201742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2202976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return provider;
2203742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2204742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2205976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int getUidForPackage(String packageName, int userId) {
2206483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani        PackageInfo pkgInfo = null;
2207976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2208976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long identity = Binder.clearCallingIdentity();
2209483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani        try {
2210976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            pkgInfo = mPackageManager.getPackageInfo(packageName, 0, userId);
2211483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani        } catch (RemoteException re) {
2212483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani            // Shouldn't happen, local call
2213976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2214976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(identity);
2215483f3b06ea84440a082e21b68ec2c2e54046f5a6Amith Yamasani        }
2216976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2217742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        if (pkgInfo == null || pkgInfo.applicationInfo == null) {
2218976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return -1;
2219742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2220976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2221742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        return pkgInfo.applicationInfo.uid;
2222742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2223742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2224976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private ActivityInfo getProviderInfo(ComponentName componentName, int userId) {
2225976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
2226976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setComponent(componentName);
2227976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2228976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        List<ResolveInfo> receivers = queryIntentReceivers(intent, userId);
2229976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We are setting component, so there is only one or none.
2230976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!receivers.isEmpty()) {
2231976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return receivers.get(0).activityInfo;
2232f229e4d3eb8f910c181f96416c6798f6f305a395Jim Miller        }
2233976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2234976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
2235f229e4d3eb8f910c181f96416c6798f6f305a395Jim Miller    }
2236f229e4d3eb8f910c181f96416c6798f6f305a395Jim Miller
2237976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private List<ResolveInfo> queryIntentReceivers(Intent intent, int userId) {
2238976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long identity = Binder.clearCallingIdentity();
2239742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        try {
2240976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return mPackageManager.queryIntentReceivers(intent,
2241976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    intent.resolveTypeIfNeeded(mContext.getContentResolver()),
2242976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    PackageManager.GET_META_DATA, userId);
2243976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (RemoteException re) {
2244976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return Collections.emptyList();
2245976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2246976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(identity);
2247742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2248742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2249742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2250976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void onUserStarted(int userId) {
2251976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
2252976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ensureGroupStateLoadedLocked(userId);
2253976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2254976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = mProviders.size();
2255742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
2256976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
2257976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2258976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Send broadcast only to the providers of the user.
2259976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.getUserId() != userId) {
2260976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2261976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2262976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2263976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.widgets.size() > 0) {
2264976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    sendEnableIntentLocked(provider);
2265976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    int[] appWidgetIds = getWidgetIds(provider.widgets);
2266976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    sendUpdateIntentLocked(provider, appWidgetIds);
2267976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    registerForBroadcastsLocked(provider, appWidgetIds);
2268742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
2269742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2270742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2271742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2272742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2273742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    // only call from initialization -- it assumes that the data structures are all empty
2274976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void loadGroupStateLocked(int[] profileIds) {
2275976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We can bind the widgets to host and providers only after
2276976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // reading the host and providers for all users since a widget
2277976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // can have a host and a provider in different users.
2278976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        List<LoadedWidgetState> loadedWidgets = new ArrayList<>();
2279742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2280976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int version = 0;
2281976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2282976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int profileIdCount = profileIds.length;
2283976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileIdCount; i++) {
2284976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
2285976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2286976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // No file written for this user - nothing to do.
2287976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            AtomicFile file = getSavedStateFile(profileId);
2288976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
2289976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                FileInputStream stream = file.openRead();
2290976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                version = readProfileStateFromFileLocked(stream, profileId, loadedWidgets);
2291976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                IoUtils.closeQuietly(stream);
2292976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (FileNotFoundException e) {
2293976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.w(TAG, "Failed to read state: " + e);
2294976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2295976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2296976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2297976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (version >= 0) {
2298976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Hooke'm up...
2299976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            bindLoadedWidgets(loadedWidgets);
2300976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2301976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // upgrade the database if needed
2302976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            performUpgradeLocked(version);
2303976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } else {
2304976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // failed reading, clean up
2305976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
2306976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mWidgets.clear();
2307976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mHosts.clear();
2308976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = mProviders.size();
2309976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
2310976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mProviders.get(i).widgets.clear();
2311742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2312742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2313742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2314742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2315976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void bindLoadedWidgets(List<LoadedWidgetState> loadedWidgets) {
2316976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int loadedWidgetCount = loadedWidgets.size();
2317976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = loadedWidgetCount - 1; i >= 0; i--) {
2318976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            LoadedWidgetState loadedWidget = loadedWidgets.remove(i);
2319976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Widget widget = loadedWidget.widget;
2320976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2321976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.provider = findProviderByTag(loadedWidget.providerTag);
2322976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.provider == null) {
2323976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // This provider is gone. We just let the host figure out
2324976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // that this happened when it fails to load it.
2325976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                continue;
2326976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2327976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2328976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host = findHostByTag(loadedWidget.hostTag);
2329976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (widget.host == null) {
2330976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // This host is gone.
2331976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                continue;
2332976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2333976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2334976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.provider.widgets.add(widget);
2335976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            widget.host.widgets.add(widget);
2336976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mWidgets.add(widget);
2337119bbc378d3c836f1196e14b847e564205a29728Dianne Hackborn        }
2338976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2339976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2340976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Provider findProviderByTag(int tag) {
2341976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (tag < 0) {
2342976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
2343976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2344976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int providerCount = mProviders.size();
2345976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < providerCount; i++) {
2346976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
2347976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider.tag == tag) {
2348976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return provider;
2349976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2350976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2351976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
2352976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2353976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2354976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private Host findHostByTag(int tag) {
2355976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (tag < 0) {
2356976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
2357976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2358976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int hostCount = mHosts.size();
2359976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < hostCount; i++) {
2360976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
2361976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host.tag == tag) {
2362976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return host;
2363742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2364976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2365976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
2366976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2367976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2368976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void saveStateLocked(int userId) {
2369976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        tagProvidersAndHosts();
2370976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2371976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
2372976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2373976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int profileCount = profileIds.length;
2374976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < profileCount; i++) {
2375976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileId = profileIds[i];
2376976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2377976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            AtomicFile file = getSavedStateFile(profileId);
2378976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            FileOutputStream stream;
2379976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
2380976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                stream = file.startWrite();
2381976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (writeProfileStateToFileLocked(stream, profileId)) {
2382976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    file.finishWrite(stream);
2383976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } else {
2384976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    file.failWrite(stream);
2385976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.w(TAG, "Failed to save state, restoring backup.");
2386976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2387976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (IOException e) {
2388976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.w(TAG, "Failed open state file for write: " + e);
2389976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2390976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2391976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2392976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2393976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void tagProvidersAndHosts() {
2394976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int providerCount = mProviders.size();
2395976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < providerCount; i++) {
2396976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
2397976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            provider.tag = i;
2398976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2399976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2400976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int hostCount = mHosts.size();
2401976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        for (int i = 0; i < hostCount; i++) {
2402976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = mHosts.get(i);
2403976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            host.tag = i;
2404742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2405742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2406742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2407976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean writeProfileStateToFileLocked(FileOutputStream stream, int userId) {
2408742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        int N;
2409742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2410742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        try {
2411742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            XmlSerializer out = new FastXmlSerializer();
2412742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.setOutput(stream, "utf-8");
2413742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.startDocument(null, true);
2414742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.startTag(null, "gs");
241539d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller            out.attribute(null, "version", String.valueOf(CURRENT_VERSION));
2416976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2417976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            N = mProviders.size();
2418742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
2419976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
2420976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Save only providers for the user.
2421976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.getUserId() != userId) {
2422976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2423976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2424976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.widgets.size() > 0) {
2425976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    serializeProvider(out, provider);
2426742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
2427742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2428742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2429742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            N = mHosts.size();
2430742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
2431742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                Host host = mHosts.get(i);
2432976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Save only hosts for the user.
2433976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (host.getUserId() != userId) {
2434976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2435976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2436adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                serializeHost(out, host);
2437742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2438742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2439976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            N = mWidgets.size();
2440742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            for (int i = 0; i < N; i++) {
2441976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = mWidgets.get(i);
2442976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Save only widgets hosted by the user.
2443976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget.host.getUserId() != userId) {
2444976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2445976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2446976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                serializeAppWidget(out, widget);
2447742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2448742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2449976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Iterator<Pair<Integer, String>> it = mPackagesWithBindWidgetPermission.iterator();
245061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka            while (it.hasNext()) {
2451976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Pair<Integer, String> binding = it.next();
2452976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Save only white listings for the user.
2453976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (binding.first != userId) {
2454976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
2455976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
245661a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                out.startTag(null, "b");
2457976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                out.attribute(null, "packageName", binding.second);
245861a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                out.endTag(null, "b");
245961a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka            }
246061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka
2461742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.endTag(null, "gs");
2462742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            out.endDocument();
2463742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            return true;
2464742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        } catch (IOException e) {
2465742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            Slog.w(TAG, "Failed to write state: " + e);
2466742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            return false;
2467742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2468742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2469742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2470976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private int readProfileStateFromFileLocked(FileInputStream stream, int userId,
2471976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            List<LoadedWidgetState> outLoadedWidgets) {
2472976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int version = -1;
2473742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        try {
2474742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            XmlPullParser parser = Xml.newPullParser();
2475742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            parser.setInput(stream, null);
2476742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2477976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int legacyProviderIndex = -1;
2478976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int legacyHostIndex = -1;
2479742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            int type;
2480742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            do {
2481742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                type = parser.next();
2482742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                if (type == XmlPullParser.START_TAG) {
2483742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    String tag = parser.getName();
248439d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                    if ("gs".equals(tag)) {
248539d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                        String attributeValue = parser.getAttributeValue(null, "version");
248639d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                        try {
248739d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                            version = Integer.parseInt(attributeValue);
248839d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                        } catch (NumberFormatException e) {
248939d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                            version = 0;
249039d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                        }
249139d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                    } else if ("p".equals(tag)) {
2492976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        legacyProviderIndex++;
2493742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // TODO: do we need to check that this package has the same signature
2494742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // as before?
2495742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        String pkg = parser.getAttributeValue(null, "pkg");
2496742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        String cl = parser.getAttributeValue(null, "cl");
2497742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2498976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        pkg = getCanonicalPackageName(pkg, cl, userId);
2499976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (pkg == null) {
2500976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            continue;
2501742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2502742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2503976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int uid = getUidForPackage(pkg, userId);
2504976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (uid < 0) {
2505976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            continue;
2506976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
2507976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2508976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        ComponentName componentName = new ComponentName(pkg, cl);
2509976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2510976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        ActivityInfo providerInfo = getProviderInfo(componentName, userId);
2511976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (providerInfo == null) {
2512976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            continue;
2513742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2514976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2515976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        ProviderId providerId = new ProviderId(uid, componentName);
2516976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Provider provider = lookupProviderLocked(providerId);
2517976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2518976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (provider == null && mSafeMode) {
2519976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            // if we're in safe mode, make a temporary one
2520976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider = new Provider();
2521976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.info = new AppWidgetProviderInfo();
2522976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.info.provider = providerId.componentName;
2523976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.info.providerInfo = providerInfo;
2524976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.zombie = true;
2525976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.id = providerId;
2526976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            mProviders.add(provider);
2527742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2528976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2529976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        String tagAttribute = parser.getAttributeValue(null, "tag");
2530976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int providerTag = !TextUtils.isEmpty(tagAttribute)
2531976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                ? Integer.parseInt(tagAttribute, 16) : legacyProviderIndex;
2532976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        provider.tag = providerTag;
2533742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    } else if ("h".equals(tag)) {
2534976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        legacyHostIndex++;
2535742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        Host host = new Host();
2536742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // TODO: do we need to check that this package has the same signature
2537742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // as before?
2538976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        String pkg = parser.getAttributeValue(null, "pkg");
2539976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2540976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int uid = getUidForPackage(pkg, userId);
2541976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (uid < 0) {
2542742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            host.zombie = true;
2543742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2544976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2545742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        if (!host.zombie || mSafeMode) {
2546742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // In safe mode, we don't discard the hosts we don't recognize
2547742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // so that they're not pruned from our list. Otherwise, we do.
2548976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final int hostId = Integer.parseInt(parser.getAttributeValue(
2549976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    null, "id"), 16);
2550976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2551976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            String tagAttribute = parser.getAttributeValue(null, "tag");
2552976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final int hostTag = !TextUtils.isEmpty(tagAttribute)
2553976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    ? Integer.parseInt(tagAttribute, 16) : legacyHostIndex;
2554976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2555976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            host.tag = hostTag;
2556976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            host.id = new HostId(uid, hostId, pkg);
2557742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            mHosts.add(host);
2558742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
255961a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                    } else if ("b".equals(tag)) {
256061a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                        String packageName = parser.getAttributeValue(null, "packageName");
2561976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int uid = getUidForPackage(packageName, userId);
2562976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (uid >= 0) {
2563976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            Pair<Integer, String> packageId = Pair.create(userId, packageName);
2564976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            mPackagesWithBindWidgetPermission.add(packageId);
256561a5b0160d9f2e53ef4d4b451212a63032dad32dMichael Jurka                        }
2566742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    } else if ("g".equals(tag)) {
2567976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Widget widget = new Widget();
2568976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.appWidgetId = Integer.parseInt(parser.getAttributeValue(
2569976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                null, "id"), 16);
2570976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        setMinAppWidgetIdLocked(userId, widget.appWidgetId + 1);
2571742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2572adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                        // restored ID is allowed to be absent
2573adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                        String restoredIdString = parser.getAttributeValue(null, "rid");
2574976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.restoredId = (restoredIdString == null) ? 0
2575adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate                                : Integer.parseInt(restoredIdString, 16);
2576adfe8b86e9178a553b6db9722340fa4ff5201cf1Christopher Tate
25770aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        Bundle options = new Bundle();
25780aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        String minWidthString = parser.getAttributeValue(null, "min_width");
25790aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        if (minWidthString != null) {
25800aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
25810aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(minWidthString, 16));
25820aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
25830aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        String minHeightString = parser.getAttributeValue(null, "min_height");
2584db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        if (minHeightString != null) {
25850aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
25860aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(minHeightString, 16));
25870aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
2588db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        String maxWidthString = parser.getAttributeValue(null, "max_width");
2589db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        if (maxWidthString != null) {
25900aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
25910aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(maxWidthString, 16));
25920aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
25930aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        String maxHeightString = parser.getAttributeValue(null, "max_height");
2594db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        if (maxHeightString != null) {
25950aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
25960aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(maxHeightString, 16));
25970aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
25980aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        String categoryString = parser.getAttributeValue(null, "host_category");
2599db38d8a4ff28caef8f2565a8ba5dca2a7efe9d83Adam Cohen                        if (categoryString != null) {
26000aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                            options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
26010aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                                    Integer.parseInt(categoryString, 16));
26020aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen                        }
2603976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.options = options;
26040aa2d42e87e4a1ed5b83f356690e465d6a3587ccAdam Cohen
2605976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int hostTag = Integer.parseInt(parser.getAttributeValue(
2606976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                null, "h"), 16);
2607742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        String providerString = parser.getAttributeValue(null, "p");
2608976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int providerTag = (providerString != null) ? Integer.parseInt(
2609976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                parser.getAttributeValue(null, "p"), 16) : TAG_UNDEFINED;
2610976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2611976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // We can match widgets with hosts and providers only after hosts
2612976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // and providers for all users have been loaded since the widget
2613976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // host and provider can be in different user profiles.
2614976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        LoadedWidgetState loadedWidgets = new LoadedWidgetState(widget,
2615976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                hostTag, providerTag);
2616976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        outLoadedWidgets.add(loadedWidgets);
2617742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    }
2618742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
2619742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            } while (type != XmlPullParser.END_DOCUMENT);
2620976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } catch (NullPointerException
2621976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                | NumberFormatException
2622976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                | XmlPullParserException
2623976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                | IOException
2624976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                | IndexOutOfBoundsException e) {
2625742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            Slog.w(TAG, "failed parsing " + e);
2626976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return -1;
2627742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2628742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2629976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return version;
2630976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2631742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2632976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void performUpgradeLocked(int fromVersion) {
263339d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        if (fromVersion < CURRENT_VERSION) {
2634976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Slog.v(TAG, "Upgrading widget database from " + fromVersion + " to "
2635976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + CURRENT_VERSION);
263639d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        }
263739d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller
263839d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        int version = fromVersion;
263939d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller
264039d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        // Update 1: keyguard moved from package "android" to "com.android.keyguard"
264139d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        if (version == 0) {
2642976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId oldHostId = new HostId(Process.myUid(),
2643976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    KEYGUARD_HOST_ID, OLD_KEYGUARD_HOST_PACKAGE);
2644976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2645976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Host host = lookupHostLocked(oldHostId);
2646976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host != null) {
2647976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int uid = getUidForPackage(NEW_KEYGUARD_HOST_PACKAGE,
2648976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        UserHandle.USER_OWNER);
2649976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (uid >= 0) {
2650976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    host.id = new HostId(uid, KEYGUARD_HOST_ID, NEW_KEYGUARD_HOST_PACKAGE);
265139d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller                }
265239d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller            }
2653976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
265439d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller            version = 1;
265539d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        }
265639d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller
265739d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        if (version != CURRENT_VERSION) {
265839d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller            throw new IllegalStateException("Failed to upgrade widget database");
265939d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller        }
266039d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller    }
266139d129e59a1c3985cb1e68f8da6deeea7b2bcbe9Jim Miller
2662976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static File getStateFile(int userId) {
2663976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return new File(Environment.getUserSystemDirectory(userId), STATE_FILENAME);
2664135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    }
2665135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
2666976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static AtomicFile getSavedStateFile(int userId) {
2667976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        File dir = Environment.getUserSystemDirectory(userId);
2668976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        File settingsFile = getStateFile(userId);
2669976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        if (!settingsFile.exists() && userId == UserHandle.USER_OWNER) {
2670e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            if (!dir.exists()) {
2671e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani                dir.mkdirs();
2672e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            }
2673e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            // Migrate old data
2674976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            File oldFile = new File("/data/system/" + STATE_FILENAME);
2675e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            // Method doesn't throw an exception on failure. Ignore any errors
2676e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            // in moving the file (like non-existence)
2677e0eb39b54812b9403496f0d300395eee73ffa57aAmith Yamasani            oldFile.renameTo(settingsFile);
2678742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2679742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        return new AtomicFile(settingsFile);
2680742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2681742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2682976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void onUserStopped(int userId) {
2683976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        synchronized (mLock) {
2684976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove widgets that have both host and provider in the user.
2685976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int widgetCount = mWidgets.size();
2686976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = widgetCount - 1; i >= 0; i--) {
2687976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = mWidgets.get(i);
2688976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2689976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean hostInUser = widget.host.getUserId() == userId;
2690976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean hasProvider = widget.provider != null;
2691976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final boolean providerInUser = hasProvider && widget.provider.getUserId() == userId;
2692976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2693976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // If both host and provider are in the user, just drop the widgets
2694976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // as we do not want to make host callbacks and provider broadcasts
2695976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // as the host and the provider will be killed.
2696976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (hostInUser && (!hasProvider || providerInUser)) {
2697976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    mWidgets.remove(i);
2698976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    widget.host.widgets.remove(widget);
2699976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    widget.host = null;
2700976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (hasProvider) {
2701976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.provider.widgets.remove(widget);
2702976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        widget.provider = null;
2703976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
2704976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2705976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2706756901d82b41f50610a63b7cf4c7747a70f1f724Amith Yamasani
2707976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove hosts and notify providers in other profiles.
2708976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int hostCount = mHosts.size();
2709976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = hostCount - 1; i >= 0; i--) {
2710976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Host host = mHosts.get(i);
2711976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (host.getUserId() == userId) {
2712976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    deleteHostLocked(host);
2713976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2714976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2715135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
2716976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove the providers and notify hosts in other profiles.
2717976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int providerCount = mProviders.size();
2718976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = providerCount - 1; i >= 0; i--) {
2719976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
2720976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.getUserId() == userId) {
2721976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    deleteProviderLocked(provider);
2722976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2723976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2724976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2725976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove grants for this user.
2726976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int grantCount = mPackagesWithBindWidgetPermission.size();
2727976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = grantCount - 1; i >= 0; i--) {
2728976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Pair<Integer, String> packageId = mPackagesWithBindWidgetPermission.valueAt(i);
2729976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (packageId.first == userId) {
2730976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    mPackagesWithBindWidgetPermission.removeAt(i);
2731976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2732742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2733976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2734976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Take a note we no longer have state for this user.
2735c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            final int userIndex = mLoadedUserIds.indexOfKey(userId);
2736c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            if (userIndex >= 0) {
2737c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav                mLoadedUserIds.removeAt(userIndex);
2738742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
27397fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
2740976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Remove the widget id counter.
2741c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            final int nextIdIndex = mNextAppWidgetIds.indexOfKey(userId);
2742c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            if (nextIdIndex >= 0) {
2743c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav                mNextAppWidgetIds.removeAt(nextIdIndex);
2744c71c42fdb2ee54a419dc8eb0a5f4f82532b16c0cSvetoslav            }
2745976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2746742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2747742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2748a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung    /**
2749a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     * Updates all providers with the specified package names, and records any providers that were
2750a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     * pruned.
2751a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     *
2752a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     * @return whether any providers were updated
2753a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung     */
2754976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean updateProvidersForPackageLocked(String packageName, int userId,
2755976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Set<ProviderId> removedProviders) {
27567fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung        boolean providersUpdated = false;
2757976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2758976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        HashSet<ProviderId> keep = new HashSet<>();
2759742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
2760976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        intent.setPackage(packageName);
2761976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        List<ResolveInfo> broadcastReceivers = queryIntentReceivers(intent, userId);
2762742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2763742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // add the missing ones and collect which ones to keep
2764742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        int N = broadcastReceivers == null ? 0 : broadcastReceivers.size();
2765742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        for (int i = 0; i < N; i++) {
2766742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            ResolveInfo ri = broadcastReceivers.get(i);
2767742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            ActivityInfo ai = ri.activityInfo;
2768976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2769742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            if ((ai.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
2770742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                continue;
2771742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2772976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2773976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageName.equals(ai.packageName)) {
2774976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ProviderId providerId = new ProviderId(ai.applicationInfo.uid,
2775976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        new ComponentName(ai.packageName, ai.name));
2776976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2777976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = lookupProviderLocked(providerId);
2778976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider == null) {
2779742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    if (addProviderLocked(ri)) {
2780976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        keep.add(providerId);
27817fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung                        providersUpdated = true;
2782742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    }
2783742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                } else {
2784976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider parsed = parseProviderInfoXml(providerId, ri);
2785742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    if (parsed != null) {
2786976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        keep.add(providerId);
2787742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // Use the new AppWidgetProviderInfo.
2788976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        provider.info = parsed.info;
2789742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        // If it's enabled
2790976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int M = provider.widgets.size();
2791742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        if (M > 0) {
2792976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            int[] appWidgetIds = getWidgetIds(provider.widgets);
2793742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // Reschedule for the new updatePeriodMillis (don't worry about handling
2794742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // it specially if updatePeriodMillis didn't change because we just sent
2795742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // an update, and the next one will be updatePeriodMillis from now).
2796976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            cancelBroadcasts(provider);
2797976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            registerForBroadcastsLocked(provider, appWidgetIds);
2798742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // If it's currently showing, call back with the new
2799742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // AppWidgetProviderInfo.
2800742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            for (int j = 0; j < M; j++) {
2801976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Widget widget = provider.widgets.get(j);
2802976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                widget.views = null;
2803976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                scheduleNotifyProviderChangedLocked(widget);
2804742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            }
2805742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                            // Now that we've told the host, push out an update.
2806976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            sendUpdateIntentLocked(provider, appWidgetIds);
28077fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung                            providersUpdated = true;
2808742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                        }
2809742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                    }
2810742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                }
2811742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2812742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2813742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2814742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // prune the ones we don't want to keep
2815976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        N = mProviders.size();
2816742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        for (int i = N - 1; i >= 0; i--) {
2817976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
2818976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageName.equals(provider.info.provider.getPackageName())
2819976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && provider.getUserId() == userId
2820976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && !keep.contains(provider.id)) {
2821a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                if (removedProviders != null) {
2822976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    removedProviders.add(provider.id);
2823a3195057fc5874d158cc8ea053aa75d5e016bdcfWinson Chung                }
2824976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                deleteProviderLocked(provider);
28257fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung                providersUpdated = true;
2826742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2827742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
28287fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
28297fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung        return providersUpdated;
2830742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
2831742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2832976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private boolean removeHostsAndProvidersForPackageLocked(String pkgName, int userId) {
2833976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        boolean removed = false;
2834976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2835976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int N = mProviders.size();
2836742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        for (int i = N - 1; i >= 0; i--) {
2837976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Provider provider = mProviders.get(i);
2838976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (pkgName.equals(provider.info.provider.getPackageName())
2839976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && provider.getUserId() == userId) {
2840976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                deleteProviderLocked(provider);
2841976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                removed = true;
2842742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2843742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
2844742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani
2845742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // Delete the hosts for this package too
2846742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // By now, we have removed any AppWidgets that were in any hosts here,
2847742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        // so we don't need to worry about sending DISABLE broadcasts to them.
2848742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        N = mHosts.size();
2849742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        for (int i = N - 1; i >= 0; i--) {
2850742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            Host host = mHosts.get(i);
2851976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (pkgName.equals(host.id.packageName)
2852976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && host.getUserId() == userId) {
2853742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani                deleteHostLocked(host);
2854976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                removed = true;
2855742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani            }
2856742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani        }
28577fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
2858976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return removed;
28597fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung    }
28607fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung
2861976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private String getCanonicalPackageName(String packageName, String className, int userId) {
2862976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long identity = Binder.clearCallingIdentity();
2863976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
28647fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung            try {
2865976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                AppGlobals.getPackageManager().getReceiverInfo(new ComponentName(packageName,
2866976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        className), 0, userId);
2867976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return packageName;
2868976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (RemoteException re) {
2869976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                String[] packageNames = mContext.getPackageManager()
2870976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        .currentToCanonicalPackageNames(new String[]{packageName});
2871976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (packageNames != null && packageNames.length > 0) {
2872976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return packageNames[0];
28737fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung                }
2874976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2875976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2876976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(identity);
2877976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2878976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        return null;
2879976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2880976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2881976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void sendBroadcastAsUser(Intent intent, UserHandle userHandle) {
2882976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long identity = Binder.clearCallingIdentity();
2883976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
2884976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.sendBroadcastAsUser(intent, userHandle);
2885976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2886976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(identity);
2887976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2888976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2889976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2890976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void bindService(Intent intent, ServiceConnection connection,
2891976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            UserHandle userHandle) {
2892976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long token = Binder.clearCallingIdentity();
2893976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
2894976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
2895976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    userHandle);
2896976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2897976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(token);
2898976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2899976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2900976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2901976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private void unbindService(ServiceConnection connection) {
2902976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final long token = Binder.clearCallingIdentity();
2903976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        try {
2904976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.unbindService(connection);
2905976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        } finally {
2906976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Binder.restoreCallingIdentity(token);
2907976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2908976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2909976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2910976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final class CallbackHandler extends Handler {
2911976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1;
2912976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2;
2913976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public static final int MSG_NOTIFY_PROVIDERS_CHANGED = 3;
2914976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public static final int MSG_NOTIFY_VIEW_DATA_CHANGED = 4;
2915976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2916976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public CallbackHandler(Looper looper) {
2917976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            super(looper, null, false);
2918976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2919976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2920976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
2921976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void handleMessage(Message message) {
2922976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            switch (message.what) {
2923976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                case MSG_NOTIFY_UPDATE_APP_WIDGET: {
2924976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    SomeArgs args = (SomeArgs) message.obj;
2925976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = (Host) args.arg1;
2926976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
2927976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    RemoteViews views = (RemoteViews) args.arg3;
2928976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int appWidgetId = args.argi1;
2929976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args.recycle();
2930976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2931976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views);
2932976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } break;
2933976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2934976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                case MSG_NOTIFY_PROVIDER_CHANGED: {
2935976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    SomeArgs args = (SomeArgs) message.obj;
2936976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = (Host) args.arg1;
2937976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
2938976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3;
2939976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int appWidgetId = args.argi1;
2940976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args.recycle();
2941976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2942976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    handleNotifyProviderChanged(host, callbacks, appWidgetId, info);
2943976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } break;
2944976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2945976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                case MSG_NOTIFY_PROVIDERS_CHANGED: {
2946976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    SomeArgs args = (SomeArgs) message.obj;
2947976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = (Host) args.arg1;
2948976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
2949976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args.recycle();
2950976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2951976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    handleNotifyProvidersChanged(host, callbacks);
2952976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } break;
2953976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2954976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                case MSG_NOTIFY_VIEW_DATA_CHANGED: {
2955976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    SomeArgs args = (SomeArgs) message.obj;
2956976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = (Host) args.arg1;
2957976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
2958976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int appWidgetId = args.argi1;
2959976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int viewId = args.argi2;
2960976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    args.recycle();
2961976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2962976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId);
2963976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } break;
2964976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2965976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
2966976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
2967976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2968976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final class SecurityPolicy {
2969976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2970976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int[] resolveCallerEnabledGroupProfiles(int[] profileIds) {
2971976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int parentId = UserHandle.getCallingUserId();
2972976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2973976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int enabledProfileCount = 0;
2974976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileCount = profileIds.length;
2975976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < profileCount; i++) {
2976976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int profileId = profileIds[i];
2977976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!isParentOrProfile(parentId, profileId)) {
2978976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    throw new SecurityException("Not the current user or"
2979976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            + " a child profile: " + profileId);
2980976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2981976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!isProfileEnabled(profileId)) {
2982976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    profileIds[i] = DISABLED_PROFILE;
2983976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } else {
2984976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    enabledProfileCount++;
2985976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2986976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2987976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2988976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int resolvedProfileIndex = 0;
2989976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int[] resolvedProfiles = new int[enabledProfileCount];
2990976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < profileCount; i++) {
2991976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int profileId = profileIds[i];
2992976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (profileId != DISABLED_PROFILE) {
2993976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    resolvedProfiles[resolvedProfileIndex] = profileId;
2994976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    resolvedProfileIndex++;
2995976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
2996976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
2997976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
2998976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return resolvedProfiles;
2999976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3000976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3001976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int[] getEnabledGroupProfileIds(int userId) {
3002976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int parentId = getGroupParent(userId);
3003976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3004976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final List<UserInfo> profiles;
3005976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
3006976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3007976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                profiles = mUserManager.getProfiles(parentId);
3008976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3009976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
3010976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3011976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3012976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int enabledProfileCount = 0;
3013976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int profileCount = profiles.size();
3014976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < profileCount; i++) {
3015976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (profiles.get(i).isEnabled()) {
3016976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    enabledProfileCount++;
3017976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3018976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3019976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3020976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int enabledProfileIndex = 0;
3021976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int[] profileIds = new int[enabledProfileCount];
3022976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < profileCount; i++) {
3023976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                UserInfo profile = profiles.get(i);
3024976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (profile.isEnabled()) {
3025976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    profileIds[enabledProfileIndex] = profile.getUserHandle().getIdentifier();
3026976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    enabledProfileIndex++;
3027976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3028976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3029976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3030976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return profileIds;
3031976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3032976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3033976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void enforceServiceExistsAndRequiresBindRemoteViewsPermission(
3034976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ComponentName componentName, int userId) {
3035976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
3036976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3037976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ServiceInfo serviceInfo = mPackageManager.getServiceInfo(componentName,
3038976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        PackageManager.GET_PERMISSIONS, userId);
3039976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (serviceInfo == null) {
3040976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    throw new SecurityException("Service " + componentName
3041976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            + " not installed for user " + userId);
3042976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3043976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!android.Manifest.permission.BIND_REMOTEVIEWS.equals(serviceInfo.permission)) {
3044976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    throw new SecurityException("Service " + componentName
3045976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            + " in user " + userId + "does not require "
3046976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            + android.Manifest.permission.BIND_REMOTEVIEWS);
3047976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3048976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (RemoteException re) {
3049976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Local call - shouldn't happen.
3050976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3051976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
3052976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3053976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3054976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3055976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void enforceModifyAppWidgetBindPermissions(String packageName) {
3056976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mContext.enforceCallingPermission(
3057976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    android.Manifest.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS,
3058976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    "hasBindAppWidgetPermission packageName=" + packageName);
3059976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3060976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3061976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void enforceCallFromPackage(String packageName) {
3062976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!isCallFromPackage(packageName)) {
3063976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new SecurityException("Package " + packageName
3064976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " not running under user " + UserHandle.getCallingUserId());
3065976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3066976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3067976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3068976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isCallFromPackage(String packageName) {
3069976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // System and root call all from anywhere they want.
3070976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int callingUid = Binder.getCallingUid();
3071976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (callingUid == Process.SYSTEM_UID || callingUid == 0 /* root */) {
3072976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3073976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3074976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Check if the package is present for the given profile.
3075976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int packageUid = getUidForPackage(packageName,
3076976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    UserHandle.getUserId(callingUid));
3077976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageUid < 0) {
3078976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3079976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3080976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Check if the call for a package is coming from that package.
3081976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return UserHandle.isSameApp(callingUid, packageUid);
3082976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3083976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3084976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean hasCallerBindPermissionOrBindWhiteListedLocked(String packageName) {
3085976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3086976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mContext.enforceCallingOrSelfPermission(
3087976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        android.Manifest.permission.BIND_APPWIDGET, null);
3088976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (SecurityException se) {
3089976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!isCallerBindAppWidgetWhiteListedLocked(packageName)) {
3090976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return false;
3091976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3092976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3093976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
3094976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3095976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3096976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean isCallerBindAppWidgetWhiteListedLocked(String packageName) {
3097976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int userId = UserHandle.getCallingUserId();
3098976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int packageUid = getUidForPackage(packageName, userId);
3099976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageUid < 0) {
3100976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                throw new IllegalArgumentException("No package " + packageName
3101976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " for user " + userId);
3102976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3103976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3104976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ensureGroupStateLoadedLocked(userId);
3105976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3106976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Pair<Integer, String> packageId = Pair.create(userId, packageName);
3107976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (mPackagesWithBindWidgetPermission.contains(packageId)) {
3108976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3109976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3110976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3111976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3112976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3113976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3114976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3115976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean canAccessAppWidget(Widget widget, int uid, String packageName) {
3116976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (isHostInPackageForUid(widget.host, uid, packageName)) {
3117976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Apps hosting the AppWidget have access to it.
3118976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3119976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3120976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (isProviderInPackageForUid(widget.provider, uid, packageName)) {
3121976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Apps providing the AppWidget have access to it.
3122976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3123976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3124976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (isHostAccessingProvider(widget.host, widget.provider, uid, packageName)) {
3125976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Apps hosting the AppWidget get to bind to a remote view service in the provider.
3126976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3127976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3128976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (mContext.checkCallingPermission(android.Manifest.permission.BIND_APPWIDGET)
3129976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    == PackageManager.PERMISSION_GRANTED) {
3130976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Apps that can bind have access to all appWidgetIds.
3131976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3132976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3133976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3134976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3135976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3136976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean isParentOrProfile(int parentId, int profileId) {
3137976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (parentId == profileId) {
3138976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3139976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3140976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return getProfileParent(profileId) == parentId;
3141976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3142976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3143976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isProviderInCallerOrInProfileAndWhitelListed(String packageName,
3144976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                int profileId) {
3145976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int callerId = UserHandle.getCallingUserId();
3146976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (profileId == callerId) {
3147976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3148976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3149976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int parentId = getProfileParent(profileId);
3150976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (parentId != callerId) {
3151976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3152976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3153976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return isProviderWhitelListed(packageName, profileId);
3154976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3155976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3156976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isProviderWhitelListed(String packageName, int profileId) {
3157976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
3158976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    DevicePolicyManagerInternal.class);
3159976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3160976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // If the policy manager is not available on the device we deny it all.
3161976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (devicePolicyManager == null) {
3162976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3163976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3164976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3165976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            List<String> crossProfilePackages = devicePolicyManager
3166976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    .getCrossProfileWidgetProviders(profileId);
3167976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3168976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return crossProfilePackages.contains(packageName);
3169976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3170976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3171976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int getProfileParent(int profileId) {
3172976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
3173976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3174976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                UserInfo parent = mUserManager.getProfileParent(profileId);
3175976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (parent != null) {
3176976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return parent.getUserHandle().getIdentifier();
3177976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3178976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3179976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
3180976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3181976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return UNKNOWN_USER_ID;
3182976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3183976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3184976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int getGroupParent(int profileId) {
3185976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int parentId = mSecurityPolicy.getProfileParent(profileId);
3186976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return (parentId != UNKNOWN_USER_ID) ? parentId : profileId;
3187976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3188976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3189976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isHostInPackageForUid(Host host, int uid, String packageName) {
3190976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (UserHandle.getAppId(uid) == Process.myUid()) {
3191976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // For a host that's in the system process, ignore the user id.
3192976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return UserHandle.isSameApp(host.id.uid, uid)
3193976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && host.id.packageName.equals(packageName);
3194976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
3195976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return host.id.uid == uid
3196976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && host.id.packageName.equals(packageName);
3197976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3198976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3199976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3200976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isProviderInPackageForUid(Provider provider, int uid,
3201976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                String packageName) {
3202976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Packages providing the AppWidget have access to it.
3203976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return provider != null && provider.id.uid == uid
3204976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && provider.id.componentName.getPackageName().equals(packageName);
3205976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3206976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3207976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isHostAccessingProvider(Host host, Provider provider, int uid,
3208976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                String packageName) {
3209976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // The host creates a package context to bind to remote views service in the provider.
3210976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return host.id.uid == uid && provider != null
3211976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && provider.id.componentName.getPackageName().equals(packageName);
3212976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3213976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3214976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean isProfileEnabled(int profileId) {
3215976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final long identity = Binder.clearCallingIdentity();
3216976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3217976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                UserInfo userInfo = mUserManager.getUserInfo(profileId);
3218976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (userInfo == null || !userInfo.isEnabled()) {
3219976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return false;
3220976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3221976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3222976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Binder.restoreCallingIdentity(identity);
3223976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3224976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
3225976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3226976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3227976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3228976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class Provider {
3229976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ProviderId id;
3230976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        AppWidgetProviderInfo info;
3231976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ArrayList<Widget> widgets = new ArrayList<>();
3232976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        PendingIntent broadcast;
3233976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
3234976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3235976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int tag = TAG_UNDEFINED; // for use while saving state (the index)
3236976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3237976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int getUserId() {
3238976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return UserHandle.getUserId(id.uid);
3239976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3240976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3241976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isInPackageForUser(String packageName, int userId) {
3242976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return getUserId() == userId
3243976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    && id.componentName.getPackageName().equals(packageName);
3244976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3245976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3246976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // is there an instance of this provider hosted by the given app?
3247976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean hostedByPackageForUser(String packageName, int userId) {
3248976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = widgets.size();
3249976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3250976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = widgets.get(i);
3251976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (packageName.equals(widget.host.id.packageName)
3252976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && widget.host.getUserId() == userId) {
3253976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3254976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3255976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3256976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3257976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3258976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3259976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3260976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3261976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "Provider{" + id + (zombie ? " Z" : "") + '}';
3262976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3263976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3264976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3265976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class ProviderId {
3266976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int uid;
3267976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final ComponentName componentName;
3268976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3269976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private ProviderId(int uid, ComponentName componentName) {
3270976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.uid = uid;
3271976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.componentName = componentName;
3272976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3273976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3274976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3275976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean equals(Object obj) {
3276976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (this == obj) {
3277976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3278976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3279976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (obj == null) {
3280976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3281976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3282976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (getClass() != obj.getClass()) {
3283976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3284976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3285976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ProviderId other = (ProviderId) obj;
3286976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (uid != other.uid)  {
3287976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3288976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3289976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (componentName == null) {
3290976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (other.componentName != null) {
3291976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return false;
3292976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3293976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else if (!componentName.equals(other.componentName)) {
3294976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3295976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3296976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
3297976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3298976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3299976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3300976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int hashCode() {
3301976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int result = uid;
3302976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            result = 31 * result + ((componentName != null)
3303976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    ? componentName.hashCode() : 0);
3304976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return result;
3305976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3306976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3307976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3308976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3309976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "ProviderId{user:" + UserHandle.getUserId(uid) + ", app:"
3310976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + UserHandle.getAppId(uid) + ", cmp:" + componentName + '}';
3311976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3312976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3313976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3314976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class Host {
3315976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        HostId id;
3316976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ArrayList<Widget> widgets = new ArrayList<>();
3317976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        IAppWidgetHost callbacks;
3318976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
3319976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3320976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int tag = TAG_UNDEFINED; // for use while saving state (the index)
3321976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3322976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int getUserId() {
3323976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return UserHandle.getUserId(id.uid);
3324976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3325976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3326976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean isInPackageForUser(String packageName, int userId) {
3327976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return getUserId() == userId && id.packageName.equals(packageName);
3328976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3329976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3330976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean hostsPackageForUser(String pkg, int userId) {
3331976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = widgets.size();
3332976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3333976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = widgets.get(i).provider;
3334976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider != null && provider.getUserId() == userId && provider.info != null
3335976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && pkg.equals(provider.info.provider.getPackageName())) {
3336976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3337976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3338976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3339976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3340976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3341976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3342976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3343976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3344976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "Host{" + id + (zombie ? " Z" : "") + '}';
3345976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3346976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3347976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3348976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class HostId {
3349976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int uid;
3350976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int hostId;
3351976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final String packageName;
3352976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3353976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public HostId(int uid, int hostId, String packageName) {
3354976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.uid = uid;
3355976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.hostId = hostId;
3356976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.packageName = packageName;
3357976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3358976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3359976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3360976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public boolean equals(Object obj) {
3361976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (this == obj) {
3362976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return true;
3363976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3364976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (obj == null) {
3365976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3366976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3367976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (getClass() != obj.getClass()) {
3368976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3369976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3370976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HostId other = (HostId) obj;
3371976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (uid != other.uid)  {
3372976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3373976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3374976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (hostId != other.hostId) {
3375976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3376976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3377976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (packageName == null) {
3378976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (other.packageName != null) {
3379976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return false;
3380976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3381976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else if (!packageName.equals(other.packageName)) {
3382976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return false;
3383976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3384976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return true;
3385976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3386976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3387976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3388976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public int hashCode() {
3389976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int result = uid;
3390976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            result = 31 * result + hostId;
3391976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            result = 31 * result + ((packageName != null)
3392976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    ? packageName.hashCode() : 0);
3393976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return result;
3394976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3395976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3396976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3397976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3398976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "HostId{user:" + UserHandle.getUserId(uid) + ", app:"
3399976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + UserHandle.getAppId(uid) + ", hostId:" + hostId
3400976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    + ", pkg:" + packageName + '}';
3401976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3402976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3403976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3404976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class Widget {
3405976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int appWidgetId;
3406976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        int restoredId;  // tracking & remapping any restored state
3407976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Provider provider;
3408976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        RemoteViews views;
3409976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Bundle options;
3410976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        Host host;
3411976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3412976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3413976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public String toString() {
3414976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
3415976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3416976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3417976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3418976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    /**
3419976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     * Acts as a proxy between the ServiceConnection and the RemoteViewsAdapterConnection. This
3420976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     * needs to be a static inner class since a reference to the ServiceConnection is held globally
3421976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     * and may lead us to leak AppWidgetService instances (if there were more than one).
3422976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     */
3423976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private static final class ServiceConnectionProxy implements ServiceConnection {
3424976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private final IRemoteViewsAdapterConnection mConnectionCb;
3425976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3426976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        ServiceConnectionProxy(IBinder connectionCb) {
3427976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mConnectionCb = IRemoteViewsAdapterConnection.Stub
3428976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    .asInterface(connectionCb);
3429976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3430976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3431976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void onServiceConnected(ComponentName name, IBinder service) {
3432976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3433976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mConnectionCb.onServiceConnected(service);
3434976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (RemoteException re) {
3435976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Error passing service interface", re);
3436976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3437976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3438976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3439976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void onServiceDisconnected(ComponentName name) {
3440976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            disconnect();
3441976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3442976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3443976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void disconnect() {
3444976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3445976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mConnectionCb.onServiceDisconnected();
3446976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (RemoteException re) {
3447976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.e(TAG, "Error clearing service interface", re);
3448976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3449976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3450976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3451976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3452976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private class LoadedWidgetState {
3453976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final Widget widget;
3454976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int hostTag;
3455976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int providerTag;
3456976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3457976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public LoadedWidgetState(Widget widget, int hostTag, int providerTag) {
3458976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.widget = widget;
3459976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.hostTag = hostTag;
3460976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            this.providerTag = providerTag;
3461976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3462976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3463976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3464976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final class SaveStateRunnable implements Runnable {
3465976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        final int mUserId;
3466976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3467976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public SaveStateRunnable(int userId) {
3468976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            mUserId = userId;
3469976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3470976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3471976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        @Override
3472976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void run() {
3473976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3474976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ensureGroupStateLoadedLocked(mUserId);
3475976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                saveStateLocked(mUserId);
3476976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3477976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3478976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    }
3479976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3480976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    /**
3481976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     * This class encapsulates the backup and restore logic for a user group state.
3482976e8bd2017d0263216c62111454438cc0f130e3Svetoslav     */
3483976e8bd2017d0263216c62111454438cc0f130e3Svetoslav    private final class BackupRestoreController {
3484976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private static final String TAG = "BackupRestoreController";
3485976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3486976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private static final boolean DEBUG = true;
3487976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3488976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Version of backed-up widget state.
3489976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private static final int WIDGET_STATE_VERSION = 2;
3490976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3491976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We need to make sure to wipe the pre-restore widget state only once for
3492976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // a given package.  Keep track of what we've done so far here; the list is
3493976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // cleared at the start of every system restore pass, but preserved through
3494976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // any install-time restore operations.
3495976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private final HashSet<String> mPrunedApps = new HashSet<>();
3496976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3497976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private final HashMap<Provider, ArrayList<RestoreUpdateRecord>> mUpdatesByProvider =
3498976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                new HashMap<>();
3499976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private final HashMap<Host, ArrayList<RestoreUpdateRecord>> mUpdatesByHost =
3500976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                new HashMap<>();
3501976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3502976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public List<String> getWidgetParticipants(int userId) {
3503976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3504976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Getting widget participants for user: " + userId);
3505976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3506976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3507976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            HashSet<String> packages = new HashSet<>();
3508976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3509976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int N = mWidgets.size();
3510976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (int i = 0; i < N; i++) {
3511976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Widget widget = mWidgets.get(i);
3512976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3513976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // Skip cross-user widgets.
3514976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (!isProviderAndHostInUser(widget, userId)) {
3515976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        continue;
3516976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3517976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3518976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    packages.add(widget.host.id.packageName);
3519976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider provider = widget.provider;
3520976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (provider != null) {
3521976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        packages.add(provider.id.componentName.getPackageName());
3522976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3523976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3524976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3525976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return new ArrayList<>(packages);
3526976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3527976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3528976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public byte[] getWidgetState(String backedupPackage, int userId) {
3529976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3530976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Getting widget state for user: " + userId);
3531976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3532976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3533976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ByteArrayOutputStream stream = new ByteArrayOutputStream();
3534976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3535976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Preflight: if this app neither hosts nor provides any live widgets
3536976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // we have no work to do.
3537976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!packageNeedsWidgetBackupLocked(backedupPackage, userId)) {
3538976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return null;
3539976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3540976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3541976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                try {
3542976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    XmlSerializer out = new FastXmlSerializer();
3543976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.setOutput(stream, "utf-8");
3544976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.startDocument(null, true);
3545976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.startTag(null, "ws");      // widget state
3546976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.attribute(null, "version", String.valueOf(WIDGET_STATE_VERSION));
3547976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.attribute(null, "pkg", backedupPackage);
3548976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3549976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // Remember all the providers that are currently hosted or published
3550976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // by this package: that is, all of the entities related to this app
3551976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // which will need to be told about id remapping.
3552976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    int index = 0;
3553976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    int N = mProviders.size();
3554976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    for (int i = 0; i < N; i++) {
3555976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Provider provider = mProviders.get(i);
3556976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3557976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (!provider.widgets.isEmpty()
3558976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                && (provider.isInPackageForUser(backedupPackage, userId)
3559976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                || provider.hostedByPackageForUser(backedupPackage, userId))) {
3560976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            provider.tag = index;
3561976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            serializeProvider(out, provider);
3562976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            index++;
3563976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3564976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3565976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3566976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    N = mHosts.size();
3567976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    index = 0;
3568976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    for (int i = 0; i < N; i++) {
3569976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Host host = mHosts.get(i);
3570976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3571976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (!host.widgets.isEmpty()
3572976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                && (host.isInPackageForUser(backedupPackage, userId)
3573976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                || host.hostsPackageForUser(backedupPackage, userId))) {
3574976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            host.tag = index;
3575976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            serializeHost(out, host);
3576976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            index++;
3577976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3578976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3579976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3580976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // All widget instances involving this package,
3581976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // either as host or as provider
3582976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    N = mWidgets.size();
3583976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    for (int i = 0; i < N; i++) {
3584976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Widget widget = mWidgets.get(i);
3585976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3586976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Provider provider = widget.provider;
3587976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (widget.host.isInPackageForUser(backedupPackage, userId)
3588976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                || (provider != null
3589976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                &&  provider.isInPackageForUser(backedupPackage, userId))) {
3590976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            serializeAppWidget(out, widget);
3591976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3592976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3593976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3594976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.endTag(null, "ws");
3595976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    out.endDocument();
3596976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                } catch (IOException e) {
3597976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.w(TAG, "Unable to save widget state for " + backedupPackage);
3598976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return null;
3599976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3600976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3601976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3602976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return stream.toByteArray();
3603976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3604976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3605976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void restoreStarting(int userId) {
3606976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3607976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Restore starting for user: " + userId);
3608976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3609976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3610976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3611976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // We're starting a new "system" restore operation, so any widget restore
3612976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // state that we see from here on is intended to replace the current
3613976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // widget configuration of any/all of the affected apps.
3614976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mPrunedApps.clear();
3615976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mUpdatesByProvider.clear();
3616976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mUpdatesByHost.clear();
3617976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3618976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3619976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3620976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void restoreWidgetState(String packageName, byte[] restoredState, int userId) {
3621976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3622976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Restoring widget state for user:" + userId
3623976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " package: " + packageName);
3624976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3625976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3626976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ByteArrayInputStream stream = new ByteArrayInputStream(restoredState);
3627976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            try {
3628976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Providers mentioned in the widget dataset by ordinal
3629976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ArrayList<Provider> restoredProviders = new ArrayList<>();
3630976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3631976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Hosts mentioned in the widget dataset by ordinal
3632976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                ArrayList<Host> restoredHosts = new ArrayList<>();
3633976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3634976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                XmlPullParser parser = Xml.newPullParser();
3635976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                parser.setInput(stream, null);
3636976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3637976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                synchronized (mLock) {
3638976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    int type;
3639976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    do {
3640976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        type = parser.next();
3641976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (type == XmlPullParser.START_TAG) {
3642976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final String tag = parser.getName();
3643976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            if ("ws".equals(tag)) {
3644976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String version = parser.getAttributeValue(null, "version");
3645976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3646976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                final int versionNumber = Integer.parseInt(version);
3647976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (versionNumber > WIDGET_STATE_VERSION) {
3648976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.w(TAG, "Unable to process state version " + version);
3649976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    return;
3650976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3651976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3652976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // TODO: fix up w.r.t. canonical vs current package names
3653976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String pkg = parser.getAttributeValue(null, "pkg");
3654976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (!packageName.equals(pkg)) {
3655976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.w(TAG, "Package mismatch in ws");
3656976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    return;
3657976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3658976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            } else if ("p".equals(tag)) {
3659976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String pkg = parser.getAttributeValue(null, "pkg");
3660976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String cl = parser.getAttributeValue(null, "cl");
3661976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3662976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // hostedProviders index will match 'p' attribute in widget's
3663976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // entry in the xml file being restored
3664976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // If there's no live entry for this provider, add an inactive one
3665976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // so that widget IDs referring to them can be properly allocated
3666976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3667976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // Backup and resotre only for the parent profile.
3668976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                ComponentName componentName = new ComponentName(pkg, cl);
3669976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3670976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Provider p = findProviderLocked(componentName, userId);
3671976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (p == null) {
3672976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p = new Provider();
3673976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p.id = new ProviderId(UNKNOWN_UID, componentName);
3674976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p.info = new AppWidgetProviderInfo();
3675976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p.info.provider = componentName;
3676976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p.zombie = true;
3677976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    mProviders.add(p);
3678976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3679976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (DEBUG) {
3680976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.i(TAG, "   provider " + p.id);
3681976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3682976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                restoredProviders.add(p);
3683976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            } else if ("h".equals(tag)) {
3684976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // The host app may not yet exist on the device.  If it's here we
3685976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // just use the existing Host entry, otherwise we create a
3686976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // placeholder whose uid will be fixed up at PACKAGE_ADDED time.
3687976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String pkg = parser.getAttributeValue(null, "pkg");
3688976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3689976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                final int uid = getUidForPackage(pkg, userId);
3690976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                final int hostId = Integer.parseInt(
3691976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        parser.getAttributeValue(null, "id"), 16);
3692976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3693976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                HostId id = new HostId(uid, hostId, pkg);
3694976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Host h = lookupOrAddHostLocked(id);
3695976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                restoredHosts.add(h);
3696976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3697976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (DEBUG) {
3698976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.i(TAG, "   host[" + restoredHosts.size()
3699976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            + "]: {" + h.id + "}");
3700976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3701976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            } else if ("g".equals(tag)) {
3702976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                int restoredId = Integer.parseInt(
3703976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        parser.getAttributeValue(null, "id"), 16);
3704976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                int hostIndex = Integer.parseInt(
3705976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        parser.getAttributeValue(null, "h"), 16);
3706976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Host host = restoredHosts.get(hostIndex);
3707976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Provider p = null;
3708976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                String prov = parser.getAttributeValue(null, "p");
3709976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (prov != null) {
3710976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    // could have been null if the app had allocated an id
3711976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    // but not yet established a binding under that id
3712976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    int which = Integer.parseInt(prov, 16);
3713976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    p = restoredProviders.get(which);
3714976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3715976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3716976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // We'll be restoring widget state for both the host and
3717976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // provider sides of this widget ID, so make sure we are
3718976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // beginning from a clean slate on both fronts.
3719976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                pruneWidgetStateLocked(host.id.packageName, userId);
3720976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (p != null) {
3721976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    pruneWidgetStateLocked(p.id.componentName.getPackageName(),
3722976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            userId);
3723976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3724976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3725976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                // Have we heard about this ancestral widget instance before?
3726976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                Widget id = findRestoredWidgetLocked(restoredId, host, p);
3727976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (id == null) {
3728976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id = new Widget();
3729976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.appWidgetId = incrementAndGetAppWidgetIdLocked(userId);
3730976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.restoredId = restoredId;
3731976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.options = parseWidgetIdOptions(parser);
3732976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.host = host;
3733976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.host.widgets.add(id);
3734976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    id.provider = p;
3735976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    if (id.provider != null) {
3736976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        id.provider.widgets.add(id);
3737976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    }
3738976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    if (DEBUG) {
3739976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        Slog.i(TAG, "New restored id " + restoredId
3740976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                                + " now " + id);
3741976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    }
3742976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    mWidgets.add(id);
3743976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3744976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (id.provider.info != null) {
3745976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    stashProviderRestoreUpdateLocked(id.provider,
3746976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            restoredId, id.appWidgetId);
3747976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                } else {
3748976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.w(TAG, "Missing provider for restored widget " + id);
3749976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3750976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                stashHostRestoreUpdateLocked(id.host, restoredId, id.appWidgetId);
3751976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3752976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (DEBUG) {
3753976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.i(TAG, "   instance: " + restoredId
3754976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            + " -> " + id.appWidgetId
3755976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                            + " :: p=" + id.provider);
3756976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3757976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
3758976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3759976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    } while (type != XmlPullParser.END_DOCUMENT);
3760976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3761976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // We've updated our own bookkeeping.  We'll need to notify the hosts and
3762976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // providers about the changes, but we can't do that yet because the restore
3763976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // target is not necessarily fully live at this moment.  Set aside the
3764976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // information for now; the backup manager will call us once more at the
3765976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // end of the process when all of the targets are in a known state, and we
3766976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // will update at that point.
3767976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3768976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } catch (XmlPullParserException | IOException e) {
3769976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.w(TAG, "Unable to restore widget state for " + packageName);
3770976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } finally {
3771976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                saveGroupStateAsync(userId);
3772976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3773976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3774976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3775976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Called once following the conclusion of a restore operation.  This is when we
3776976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // send out updates to apps involved in widget-state restore telling them about
3777976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // the new widget ID space.
3778976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        public void restoreFinished(int userId) {
3779976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3780976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "restoreFinished for " + userId);
3781976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3782976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3783976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final UserHandle userHandle = new UserHandle(userId);
3784976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            synchronized (mLock) {
3785976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Build the providers' broadcasts and send them off
3786976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries
3787976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        = mUpdatesByProvider.entrySet();
3788976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) {
3789976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // For each provider there's a list of affected IDs
3790976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider provider = e.getKey();
3791976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    ArrayList<RestoreUpdateRecord> updates = e.getValue();
3792976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    final int pending = countPendingUpdates(updates);
3793976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
3794976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "Provider " + provider + " pending: " + pending);
3795976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3796976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (pending > 0) {
3797976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        int[] oldIds = new int[pending];
3798976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        int[] newIds = new int[pending];
3799976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int N = updates.size();
3800976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        int nextPending = 0;
3801976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        for (int i = 0; i < N; i++) {
3802976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            RestoreUpdateRecord r = updates.get(i);
3803976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            if (!r.notified) {
3804976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                r.notified = true;
3805976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                oldIds[nextPending] = r.oldId;
3806976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                newIds[nextPending] = r.newId;
3807976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                nextPending++;
3808976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (DEBUG) {
3809976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    Slog.i(TAG, "   " + r.oldId + " => " + r.newId);
3810976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3811976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
3812976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3813976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        sendWidgetRestoreBroadcastLocked(
3814976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                AppWidgetManager.ACTION_APPWIDGET_RESTORED,
3815976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                provider, null, oldIds, newIds, userHandle);
3816976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3817976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3818976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3819976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // same thing per host
3820976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries
3821976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        = mUpdatesByHost.entrySet();
3822976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) {
3823976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = e.getKey();
3824976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (host.id.uid != UNKNOWN_UID) {
3825976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        ArrayList<RestoreUpdateRecord> updates = e.getValue();
3826976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        final int pending = countPendingUpdates(updates);
3827976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (DEBUG) {
3828976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            Slog.i(TAG, "Host " + host + " pending: " + pending);
3829976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3830976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        if (pending > 0) {
3831976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            int[] oldIds = new int[pending];
3832976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            int[] newIds = new int[pending];
3833976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            final int N = updates.size();
3834976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            int nextPending = 0;
3835976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            for (int i = 0; i < N; i++) {
3836976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                RestoreUpdateRecord r = updates.get(i);
3837976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                if (!r.notified) {
3838976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    r.notified = true;
3839976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    oldIds[nextPending] = r.oldId;
3840976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    newIds[nextPending] = r.newId;
3841976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    nextPending++;
3842976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    if (DEBUG) {
3843976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                        Slog.i(TAG, "   " + r.oldId + " => " + r.newId);
3844976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    }
3845976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                }
3846976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            }
3847976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            sendWidgetRestoreBroadcastLocked(
3848976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED,
3849976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                    null, host, oldIds, newIds, userHandle);
3850976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        }
3851976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3852976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3853976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3854976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3855976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3856976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private Provider findProviderLocked(ComponentName componentName, int userId) {
3857976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int providerCount = mProviders.size();
3858976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < providerCount; i++) {
3859976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = mProviders.get(i);
3860976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider.getUserId() == userId
3861976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && provider.id.componentName.equals(componentName)) {
3862976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return provider;
3863976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3864976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3865976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
3866976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3867976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3868976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private Widget findRestoredWidgetLocked(int restoredId, Host host, Provider p) {
3869976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (DEBUG) {
3870976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Slog.i(TAG, "Find restored widget: id=" + restoredId
3871976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        + " host=" + host + " provider=" + p);
3872976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3873976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3874976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (p == null || host == null) {
3875976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                return null;
3876976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3877976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3878976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = mWidgets.size();
3879976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3880976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = mWidgets.get(i);
3881976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget.restoredId == restoredId
3882976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && widget.host.id.equals(host.id)
3883976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        && widget.provider.id.equals(p.id)) {
3884976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
3885976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "   Found at " + i + " : " + widget);
3886976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3887976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return widget;
3888976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3889976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3890976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return null;
3891976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3892976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3893976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean packageNeedsWidgetBackupLocked(String packageName, int userId) {
3894976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int N = mWidgets.size();
3895976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3896976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Widget widget = mWidgets.get(i);
3897976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3898976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // Skip cross-user widgets.
3899976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!isProviderAndHostInUser(widget, userId)) {
3900976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    continue;
3901976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3902976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3903976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (widget.host.isInPackageForUser(packageName, userId)) {
3904976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // this package is hosting widgets, so it knows widget IDs.
3905976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3906976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3907976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3908976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Provider provider = widget.provider;
3909976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (provider != null && provider.isInPackageForUser(packageName, userId)) {
3910976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    // someone is hosting this app's widgets, so it knows widget IDs.
3911976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3912976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3913976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3914976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3915976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3916976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3917976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private void stashProviderRestoreUpdateLocked(Provider provider, int oldId, int newId) {
3918976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<RestoreUpdateRecord> r = mUpdatesByProvider.get(provider);
3919976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (r == null) {
3920976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                r = new ArrayList<>();
3921976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mUpdatesByProvider.put(provider, r);
3922976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
3923976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                // don't duplicate
3924976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (alreadyStashed(r, oldId, newId)) {
3925976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
3926976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "ID remap " + oldId + " -> " + newId
3927976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                + " already stashed for " + provider);
3928976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3929976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return;
3930976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3931976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3932976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            r.add(new RestoreUpdateRecord(oldId, newId));
3933976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3934976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3935976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean alreadyStashed(ArrayList<RestoreUpdateRecord> stash,
3936976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                final int oldId, final int newId) {
3937976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = stash.size();
3938976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
3939976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                RestoreUpdateRecord r = stash.get(i);
3940976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (r.oldId == oldId && r.newId == newId) {
3941976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return true;
3942976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3943976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3944976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return false;
3945976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3946976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3947976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private void stashHostRestoreUpdateLocked(Host host, int oldId, int newId) {
3948976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            ArrayList<RestoreUpdateRecord> r = mUpdatesByHost.get(host);
3949976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (r == null) {
3950976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                r = new ArrayList<>();
3951976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mUpdatesByHost.put(host, r);
3952976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
3953976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (alreadyStashed(r, oldId, newId)) {
3954976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (DEBUG) {
3955976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Slog.i(TAG, "ID remap " + oldId + " -> " + newId
3956976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                                + " already stashed for " + host);
3957976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
3958976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    return;
3959976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3960976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3961976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            r.add(new RestoreUpdateRecord(oldId, newId));
3962976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3963976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3964976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private void sendWidgetRestoreBroadcastLocked(String action, Provider provider,
3965976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                Host host, int[] oldIds, int[] newIds, UserHandle userHandle) {
3966976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Intent intent = new Intent(action);
3967976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS, oldIds);
3968976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, newIds);
3969976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (provider != null) {
3970976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                intent.setComponent(provider.info.provider);
3971976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sendBroadcastAsUser(intent, userHandle);
3972976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3973976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (host != null) {
3974976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                intent.setComponent(null);
3975976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                intent.setPackage(host.id.packageName);
3976976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                intent.putExtra(AppWidgetManager.EXTRA_HOST_ID, host.id.hostId);
3977976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                sendBroadcastAsUser(intent, userHandle);
3978976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
3979976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
3980976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3981976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // We're restoring widget state for 'pkg', so we start by wiping (a) all widget
3982976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // instances that are hosted by that app, and (b) all instances in other hosts
3983976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // for which 'pkg' is the provider.  We assume that we'll be restoring all of
3984976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // these hosts & providers, so will be reconstructing a correct live state.
3985976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private void pruneWidgetStateLocked(String pkg, int userId) {
3986976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (!mPrunedApps.contains(pkg)) {
3987976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (DEBUG) {
3988976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.i(TAG, "pruning widget state for restoring package " + pkg);
3989976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
3990976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                for (int i = mWidgets.size() - 1; i >= 0; i--) {
3991976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Widget widget = mWidgets.get(i);
3992976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3993976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Host host = widget.host;
3994976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Provider provider = widget.provider;
3995976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
3996976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    if (host.hostsPackageForUser(pkg, userId)
3997976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                            || (provider != null && provider.isInPackageForUser(pkg, userId))) {
3998976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // 'pkg' is either the host or the provider for this instances,
3999976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // so we tear it down in anticipation of it (possibly) being
4000976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        // reconstructed due to the restore
4001976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        host.widgets.remove(widget);
4002976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        provider.widgets.remove(widget);
4003976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        unbindAppWidgetRemoteViewsServicesLocked(widget);
4004976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        mWidgets.remove(i);
4005976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    }
4006976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
4007976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                mPrunedApps.add(pkg);
4008976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            } else {
4009976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (DEBUG) {
4010976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    Slog.i(TAG, "already pruned " + pkg + ", continuing normally");
4011976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
4012976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4013976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
4014976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4015976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private boolean isProviderAndHostInUser(Widget widget, int userId) {
4016976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            // Backup only widgets hosted or provided by the owner profile.
4017976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return widget.host.getUserId() == userId && (widget.provider == null
4018976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    || widget.provider.getUserId() == userId);
4019976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
4020976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4021976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private Bundle parseWidgetIdOptions(XmlPullParser parser) {
4022976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            Bundle options = new Bundle();
4023976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String minWidthString = parser.getAttributeValue(null, "min_width");
4024976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (minWidthString != null) {
4025976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
4026976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(minWidthString, 16));
4027976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4028976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String minHeightString = parser.getAttributeValue(null, "min_height");
4029976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (minHeightString != null) {
4030976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
4031976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(minHeightString, 16));
4032976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4033976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String maxWidthString = parser.getAttributeValue(null, "max_width");
4034976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (maxWidthString != null) {
4035976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
4036976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(maxWidthString, 16));
4037976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4038976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String maxHeightString = parser.getAttributeValue(null, "max_height");
4039976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (maxHeightString != null) {
4040976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
4041976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(maxHeightString, 16));
4042976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4043976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            String categoryString = parser.getAttributeValue(null, "host_category");
4044976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            if (categoryString != null) {
4045976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
4046976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                        Integer.parseInt(categoryString, 16));
4047976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4048976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return options;
4049976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
4050976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4051976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private int countPendingUpdates(ArrayList<RestoreUpdateRecord> updates) {
4052976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            int pending = 0;
4053976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            final int N = updates.size();
4054976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            for (int i = 0; i < N; i++) {
4055976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                RestoreUpdateRecord r = updates.get(i);
4056976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                if (!r.notified) {
4057976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                    pending++;
4058976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                }
4059976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            }
4060976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            return pending;
4061976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        }
4062976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4063976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // Accumulate a list of updates that affect the given provider for a final
4064976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        // coalesced notification broadcast once restore is over.
4065976e8bd2017d0263216c62111454438cc0f130e3Svetoslav        private class RestoreUpdateRecord {
4066976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public int oldId;
4067976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public int newId;
4068976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public boolean notified;
4069976e8bd2017d0263216c62111454438cc0f130e3Svetoslav
4070976e8bd2017d0263216c62111454438cc0f130e3Svetoslav            public RestoreUpdateRecord(int theOldId, int theNewId) {
4071976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                oldId = theOldId;
4072976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                newId = theNewId;
4073976e8bd2017d0263216c62111454438cc0f130e3Svetoslav                notified = false;
40747fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung            }
40757fbd28438c2322973c77f31f0721a24fe1c35039Winson Chung        }
4076742a67127366c376fdf188ff99ba30b27d3bf90cAmith Yamasani    }
4077976e8bd2017d0263216c62111454438cc0f130e3Svetoslav}