From 9912a46371d781c0801ebc7fb5fef02bd2484634 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 20 Jan 2021 14:38:48 -0800 Subject: [PATCH] Lazily loading the widget providers to avoid loading app-resources on userUnlock Bug: 177931115 Test: atest FrameworksServicesTests Change-Id: I879b2b83b2d249b7175ab364a78a92bd3ec12f31 --- .../appwidget/AppWidgetServiceImpl.java | 290 ++++++++++-------- 1 file changed, 164 insertions(+), 126 deletions(-) diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index d4bd5adb7b250..10b2f78452482 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -89,10 +89,12 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.AtomicFile; import android.util.AttributeSet; +import android.util.IntArray; import android.util.LongSparseArray; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.TypedValue; @@ -105,6 +107,7 @@ import android.view.View; import android.widget.RemoteViews; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.app.SuspendedAppActivity; import com.android.internal.app.UnlaunchableAppActivity; import com.android.internal.appwidget.IAppWidgetHost; @@ -161,8 +164,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private static final int UNKNOWN_UID = -1; - private static final int LOADED_PROFILE_ID = -1; - private static final int UNKNOWN_USER_ID = -10; // Bump if the stored widgets need to be upgraded. @@ -220,7 +221,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private final ArraySet> mPackagesWithBindWidgetPermission = new ArraySet<>(); - private final SparseIntArray mLoadedUserIds = new SparseIntArray(); + private final SparseBooleanArray mLoadedUserIds = new SparseBooleanArray(); private final Object mWidgetPackagesLock = new Object(); private final SparseArray> mWidgetPackages = new SparseArray<>(); @@ -525,7 +526,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku boolean suspended; try { suspended = mPackageManager.isPackageSuspendedForUser( - provider.info.provider.getPackageName(), provider.getUserId()); + provider.id.componentName.getPackageName(), provider.getUserId()); } catch (IllegalArgumentException ex) { // Package not found. suspended = false; @@ -563,7 +564,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Provider provider = mProviders.get(i); int providerUserId = provider.getUserId(); if (providerUserId != profileId - || !packages.contains(provider.info.provider.getPackageName())) { + || !packages.contains(provider.id.componentName.getPackageName())) { continue; } if (provider.setMaskedBySuspendedPackageLocked(suspended)) { @@ -624,7 +625,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (widgetCount == 0) { return; } - final String providerPackage = provider.info.provider.getPackageName(); + final String providerPackage = provider.id.componentName.getPackageName(); final int providerUserId = provider.getUserId(); Bitmap iconBitmap = createMaskedWidgetBitmap(providerPackage, providerUserId); if (iconBitmap == null) { @@ -725,35 +726,17 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId); - // Careful lad, we may have already loaded the state for some - // group members, so check before loading and read only the - // state for the new member(s). - int newMemberCount = 0; - final int profileIdCount = profileIds.length; - for (int i = 0; i < profileIdCount; i++) { - final int profileId = profileIds[i]; - if (mLoadedUserIds.indexOfKey(profileId) >= 0) { - profileIds[i] = LOADED_PROFILE_ID; - } else { - newMemberCount++; + IntArray newIds = new IntArray(1); + for (int profileId : profileIds) { + if (!mLoadedUserIds.get(profileId)) { + mLoadedUserIds.put(profileId, true); + newIds.add(profileId); } } - - if (newMemberCount <= 0) { + if (newIds.size() <= 0) { return; } - - int newMemberIndex = 0; - final int[] newProfileIds = new int[newMemberCount]; - for (int i = 0; i < profileIdCount; i++) { - final int profileId = profileIds[i]; - if (profileId != LOADED_PROFILE_ID) { - mLoadedUserIds.put(profileId, profileId); - newProfileIds[newMemberIndex] = profileId; - newMemberIndex++; - } - } - + final int[] newProfileIds = newIds.toArray(); clearProvidersAndHostsTagsLocked(); loadGroupWidgetProvidersLocked(newProfileIds); @@ -772,7 +755,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (args.length > 0 && "--proto".equals(args[0])) { dumpProto(fd); } else { - dumpInternal(pw); + dumpInternalLocked(pw); } } } @@ -816,11 +799,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku proto.end(token); } - private void dumpInternal(PrintWriter pw) { + private void dumpInternalLocked(PrintWriter pw) { int N = mProviders.size(); pw.println("Providers:"); for (int i = 0; i < N; i++) { - dumpProvider(mProviders.get(i), i, pw); + dumpProviderLocked(mProviders.get(i), i, pw); } N = mWidgets.size(); @@ -850,7 +833,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku public ParceledListSlice startListening(IAppWidgetHost callbacks, String callingPackage, int hostId, int[] appWidgetIds) { final int userId = UserHandle.getCallingUserId(); - if (DEBUG) { Slog.i(TAG, "startListening() " + userId); } @@ -879,7 +861,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku LongSparseArray updatesMap = new LongSparseArray<>(); for (int i = 0; i < N; i++) { updatesMap.clear(); - host.getPendingUpdatesForId(appWidgetIds[i], updatesMap); + host.getPendingUpdatesForIdLocked(mContext, appWidgetIds[i], updatesMap); // We key the updates based on request id, so that the values are sorted in the // order they were received. int m = updatesMap.size(); @@ -1090,7 +1072,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); - intent.setComponent(provider.info.configure); + intent.setComponent(provider.getInfoLocked(mContext).configure); intent.setFlags(secureFlags); // All right, create the sender. @@ -1434,7 +1416,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Binder.getCallingUid(), callingPackage); if (widget != null && widget.provider != null && !widget.provider.zombie) { - return cloneIfLocalBinder(widget.provider.info); + return cloneIfLocalBinder(widget.provider.getInfoLocked(mContext)); } return null; @@ -1644,14 +1626,14 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku String keyToUse = metadataKey == null ? AppWidgetManager.META_DATA_APPWIDGET_PROVIDER : metadataKey; - AppWidgetProviderInfo info = - parseAppWidgetProviderInfo(providerId, provider.info.providerInfo, keyToUse); + AppWidgetProviderInfo info = parseAppWidgetProviderInfo(mContext, providerId, + provider.getPartialInfoLocked().providerInfo, keyToUse); if (info == null) { throw new IllegalArgumentException("Unable to parse " + keyToUse + " meta-data to a valid AppWidget provider"); } - provider.info = info; + provider.setInfoLocked(info); provider.infoTag = metadataKey; // Update all widgets for this provider @@ -1701,7 +1683,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (provider == null || provider.zombie) { return false; } - info = provider.info; + info = provider.getInfoLocked(mContext); if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) == 0) { return false; } @@ -1739,7 +1721,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int providerCount = mProviders.size(); for (int i = 0; i < providerCount; i++) { Provider provider = mProviders.get(i); - AppWidgetProviderInfo info = provider.info; + AppWidgetProviderInfo info = provider.getInfoLocked(mContext); // Ignore an invalid provider, one not matching the filter, // or one that isn't in the given package, if any. @@ -1907,7 +1889,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku try { mContext.bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, - widget.provider.info.getProfile()); + widget.provider.id.getProfile()); } finally { Binder.restoreCallingIdentity(token); } @@ -2102,7 +2084,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku SomeArgs args = SomeArgs.obtain(); args.arg1 = widget.host; args.arg2 = widget.host.callbacks; - args.arg3 = widget.provider.info; + args.arg3 = widget.provider.getInfoLocked(mContext); args.arg4 = requestId; args.argi1 = widget.appWidgetId; @@ -2312,31 +2294,34 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku ri.activityInfo.name); ProviderId providerId = new ProviderId(ri.activityInfo.applicationInfo.uid, componentName); - Provider provider = parseProviderInfoXml(providerId, ri, null); - if (provider != null) { - // we might have an inactive entry for this provider already due to - // a preceding restore operation. if so, fix it up in place; otherwise - // just add this new one. - Provider existing = lookupProviderLocked(providerId); + // we might have an inactive entry for this provider already due to + // a preceding restore operation. if so, fix it up in place; otherwise + // just add this new one. + Provider existing = lookupProviderLocked(providerId); - // If the provider was not found it may be because it was restored and - // we did not know its UID so let us find if there is such one. - if (existing == null) { - ProviderId restoredProviderId = new ProviderId(UNKNOWN_UID, componentName); - existing = lookupProviderLocked(restoredProviderId); - } + // If the provider was not found it may be because it was restored and + // we did not know its UID so let us find if there is such one. + if (existing == null) { + ProviderId restoredProviderId = new ProviderId(UNKNOWN_UID, componentName); + existing = lookupProviderLocked(restoredProviderId); + } + AppWidgetProviderInfo info = createPartialProviderInfo(providerId, ri, existing); + if (info != null) { if (existing != null) { if (existing.zombie && !mSafeMode) { // it's a placeholder that was set up during an app restore existing.id = providerId; existing.zombie = false; - existing.info = provider.info; // the real one filled out from the ResolveInfo + existing.setPartialInfoLocked(info); if (DEBUG) { Slog.i(TAG, "Provider placeholder now reified: " + existing); } } } else { + Provider provider = new Provider(); + provider.id = providerId; + provider.setPartialInfoLocked(info); mProviders.add(provider); } return true; @@ -2375,60 +2360,61 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private void sendEnableIntentLocked(Provider p) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); - intent.setComponent(p.info.provider); - sendBroadcastAsUser(intent, p.info.getProfile()); + intent.setComponent(p.id.componentName); + sendBroadcastAsUser(intent, p.id.getProfile()); } private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); - intent.setComponent(provider.info.provider); - sendBroadcastAsUser(intent, provider.info.getProfile()); + intent.setComponent(provider.id.componentName); + sendBroadcastAsUser(intent, provider.id.getProfile()); } private void sendDeletedIntentLocked(Widget widget) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); - intent.setComponent(widget.provider.info.provider); + intent.setComponent(widget.provider.id.componentName); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId); - sendBroadcastAsUser(intent, widget.provider.info.getProfile()); + sendBroadcastAsUser(intent, widget.provider.id.getProfile()); } private void sendDisabledIntentLocked(Provider provider) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); - intent.setComponent(provider.info.provider); - sendBroadcastAsUser(intent, provider.info.getProfile()); + intent.setComponent(provider.id.componentName); + sendBroadcastAsUser(intent, provider.id.getProfile()); } public void sendOptionsChangedIntentLocked(Widget widget) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED); - intent.setComponent(widget.provider.info.provider); + intent.setComponent(widget.provider.id.componentName); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, widget.options); - sendBroadcastAsUser(intent, widget.provider.info.getProfile()); + sendBroadcastAsUser(intent, widget.provider.id.getProfile()); } private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) { - if (provider.info.updatePeriodMillis > 0) { + AppWidgetProviderInfo info = provider.getInfoLocked(mContext); + if (info.updatePeriodMillis > 0) { // if this is the first instance, set the alarm. otherwise, // rely on the fact that we've already set it and that // PendingIntent.getBroadcast will update the extras. boolean alreadyRegistered = provider.broadcast != null; Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); - intent.setComponent(provider.info.provider); + intent.setComponent(info.provider); final long token = Binder.clearCallingIdentity(); try { // Broadcast alarms sent by system are immutable provider.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE, - provider.info.getProfile()); + info.getProfile()); } finally { Binder.restoreCallingIdentity(token); } if (!alreadyRegistered) { // Set the alarm outside of our locks; we've latched the first-time // invariant and established the PendingIntent safely. - final long period = Math.max(provider.info.updatePeriodMillis, MIN_UPDATE_PERIOD); + final long period = Math.max(info.updatePeriodMillis, MIN_UPDATE_PERIOD); final PendingIntent broadcast = provider.broadcast; mSaveStateHandler.post(() -> mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, @@ -2447,8 +2433,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return appWidgetIds; } - private static void dumpProvider(Provider provider, int index, PrintWriter pw) { - AppWidgetProviderInfo info = provider.info; + private static void dumpProviderLocked(Provider provider, int index, PrintWriter pw) { + AppWidgetProviderInfo info = provider.getPartialInfoLocked(); pw.print(" ["); pw.print(index); pw.print("] provider "); pw.println(provider.id); pw.print(" min=("); pw.print(info.minWidth); @@ -2467,7 +2453,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku pw.print(Integer.toHexString(info.initialLayout)); pw.print(" initialKeyguardLayout=#"); pw.print(Integer.toHexString(info.initialKeyguardLayout)); - pw.print(" zombie="); pw.println(provider.zombie); + pw.print(" zombie="); pw.println(provider.zombie); } private static void dumpHost(Host host, int index, PrintWriter pw) { @@ -2502,8 +2488,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku private static void serializeProvider(TypedXmlSerializer out, Provider p) throws IOException { out.startTag(null, "p"); - out.attribute(null, "pkg", p.info.provider.getPackageName()); - out.attribute(null, "cl", p.info.provider.getClassName()); + out.attribute(null, "pkg", p.id.componentName.getPackageName()); + out.attribute(null, "cl", p.id.componentName.getClassName()); out.attributeIntHex(null, "tag", p.tag); if (!TextUtils.isEmpty(p.infoTag)) { out.attribute(null, "info_tag", p.infoTag); @@ -2604,30 +2590,32 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @SuppressWarnings("deprecation") - private Provider parseProviderInfoXml(ProviderId providerId, ResolveInfo ri, - Provider oldProvider) { - AppWidgetProviderInfo info = null; - if (oldProvider != null && !TextUtils.isEmpty(oldProvider.infoTag)) { - info = parseAppWidgetProviderInfo(providerId, ri.activityInfo, oldProvider.infoTag); - } - if (info == null) { - info = parseAppWidgetProviderInfo(providerId, ri.activityInfo, - AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); - } - if (info == null) { + private AppWidgetProviderInfo createPartialProviderInfo(ProviderId providerId, ResolveInfo ri, + Provider provider) { + boolean hasXmlDefinition = false; + Bundle metaData = ri.activityInfo.metaData; + if (metaData == null) { return null; } - Provider provider = new Provider(); - provider.id = providerId; - provider.info = info; - return provider; + if (provider != null && !TextUtils.isEmpty(provider.infoTag)) { + hasXmlDefinition = metaData.getInt(provider.infoTag) != 0; + } + hasXmlDefinition |= metaData.getInt(AppWidgetManager.META_DATA_APPWIDGET_PROVIDER) != 0; + + if (hasXmlDefinition) { + AppWidgetProviderInfo info = new AppWidgetProviderInfo(); + info.provider = providerId.componentName; + info.providerInfo = ri.activityInfo; + return info; + } + return null; } - private AppWidgetProviderInfo parseAppWidgetProviderInfo( + private static AppWidgetProviderInfo parseAppWidgetProviderInfo(Context context, ProviderId providerId, ActivityInfo activityInfo, String metadataKey) { - try (XmlResourceParser parser = - activityInfo.loadXmlMetaData(mContext.getPackageManager(), metadataKey)) { + final PackageManager pm = context.getPackageManager(); + try (XmlResourceParser parser = activityInfo.loadXmlMetaData(pm, metadataKey)) { if (parser == null) { Slog.w(TAG, "No " + metadataKey + " meta-data for AppWidget provider '" + providerId + '\''); @@ -2657,7 +2645,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final Resources resources; final long identity = Binder.clearCallingIdentity(); try { - final PackageManager pm = mContext.getPackageManager(); final int userId = UserHandle.getUserId(providerId.uid); final ApplicationInfo app = pm.getApplicationInfoAsUser(activityInfo.packageName, 0, userId); @@ -2696,7 +2683,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku info.configure = new ComponentName(providerId.componentName.getPackageName(), className); } - info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString(); + info.label = activityInfo.loadLabel(pm).toString(); info.icon = activityInfo.getIconResource(); info.previewImage = sa.getResourceId( com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); @@ -2819,7 +2806,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (provider.widgets.size() > 0) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, - "appwidget init " + provider.info.provider.getPackageName()); + "appwidget init " + provider.id.componentName.getPackageName()); sendEnableIntentLocked(provider); int[] appWidgetIds = getWidgetIds(provider.widgets); sendUpdateIntentLocked(provider, appWidgetIds); @@ -2947,7 +2934,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (packages == null) { mWidgetPackages.put(userId, packages = new ArraySet()); } - packages.add(widget.provider.info.provider.getPackageName()); + packages.add(widget.provider.id.componentName.getPackageName()); } // If we are adding a widget it might be for a provider that @@ -2974,7 +2961,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (widget.provider == null) return; final int userId = widget.provider.getUserId(); - final String packageName = widget.provider.info.provider.getPackageName(); + final String packageName = widget.provider.id.componentName.getPackageName(); synchronized (mWidgetPackagesLock) { ArraySet packages = mWidgetPackages.get(userId); if (packages == null) { @@ -2987,7 +2974,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Widget w = mWidgets.get(i); if (w.provider == null) continue; if (w.provider.getUserId() == userId - && packageName.equals(w.provider.info.provider.getPackageName())) { + && packageName.equals(w.provider.id.componentName.getPackageName())) { return; } } @@ -3183,10 +3170,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (provider == null && mSafeMode) { // if we're in safe mode, make a temporary one + AppWidgetProviderInfo info = new AppWidgetProviderInfo(); + info.provider = providerId.componentName; + info.providerInfo = providerInfo; + provider = new Provider(); - provider.info = new AppWidgetProviderInfo(); - provider.info.provider = providerId.componentName; - provider.info.providerInfo = providerInfo; + provider.setPartialInfoLocked(info); provider.zombie = true; provider.id = providerId; mProviders.add(provider); @@ -3195,15 +3184,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int providerTag = parser.getAttributeIntHex(null, "tag", legacyProviderIndex); provider.tag = providerTag; - provider.infoTag = parser.getAttributeValue(null, "info_tag"); - if (!TextUtils.isEmpty(provider.infoTag) && !mSafeMode) { - AppWidgetProviderInfo info = parseAppWidgetProviderInfo( - providerId, providerInfo, provider.infoTag); - if (info != null) { - provider.info = info; - } - } } else if ("h".equals(tag)) { legacyHostIndex++; Host host = new Host(); @@ -3424,11 +3405,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku providersUpdated = true; } } else { - Provider parsed = parseProviderInfoXml(providerId, ri, provider); - if (parsed != null) { + AppWidgetProviderInfo info = + createPartialProviderInfo(providerId, ri, provider); + if (info != null) { keep.add(providerId); // Use the new AppWidgetProviderInfo. - provider.info = parsed.info; + provider.setPartialInfoLocked(info); // If it's enabled final int M = provider.widgets.size(); if (M > 0) { @@ -3458,7 +3440,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku N = mProviders.size(); for (int i = N - 1; i >= 0; i--) { Provider provider = mProviders.get(i); - if (packageName.equals(provider.info.provider.getPackageName()) + if (packageName.equals(provider.id.componentName.getPackageName()) && provider.getUserId() == userId && !keep.contains(provider.id)) { if (removedProviders != null) { @@ -3477,7 +3459,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int N = mProviders.size(); for (int i = 0; i < N; ++i) { Provider provider = mProviders.get(i); - if (pkgName.equals(provider.info.provider.getPackageName()) + if (pkgName.equals(provider.id.componentName.getPackageName()) && provider.getUserId() == userId && provider.widgets.size() > 0) { deleteWidgetsLocked(provider, parentUserId); @@ -3491,7 +3473,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int N = mProviders.size(); for (int i = N - 1; i >= 0; i--) { Provider provider = mProviders.get(i); - if (pkgName.equals(provider.info.provider.getPackageName()) + if (pkgName.equals(provider.id.componentName.getPackageName()) && provider.getUserId() == userId) { deleteProviderLocked(provider); removed = true; @@ -3970,17 +3952,21 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } private static final class Provider { + ProviderId id; AppWidgetProviderInfo info; ArrayList widgets = new ArrayList<>(); PendingIntent broadcast; String infoTag; + boolean zombie; // if we're in safe mode, don't prune this just because nobody references it boolean maskedByLockedProfile; boolean maskedByQuietProfile; boolean maskedBySuspendedPackage; + boolean mInfoParsed = false; + int tag = TAG_UNDEFINED; // for use while saving state (the index) public int getUserId() { @@ -4005,6 +3991,51 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return false; } + @GuardedBy("mLock") + public AppWidgetProviderInfo getInfoLocked(Context context) { + if (!mInfoParsed) { + // parse + if (!zombie) { + AppWidgetProviderInfo newInfo = null; + if (!TextUtils.isEmpty(infoTag)) { + newInfo = parseAppWidgetProviderInfo( + context, id, info.providerInfo, infoTag); + } + if (newInfo == null) { + newInfo = parseAppWidgetProviderInfo(context, id, info.providerInfo, + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); + } + if (newInfo != null) { + info = newInfo; + } + } + mInfoParsed = true; + } + return info; + } + + /** + * Returns the last updated AppWidgetProviderInfo for this provider. This info may not + * be completely parsed and only contain placeHolder information like + * {@link AppWidgetProviderInfo#providerInfo} + */ + @GuardedBy("mLock") + public AppWidgetProviderInfo getPartialInfoLocked() { + return info; + } + + @GuardedBy("mLock") + public void setPartialInfoLocked(AppWidgetProviderInfo info) { + this.info = info; + mInfoParsed = false; + } + + @GuardedBy("mLock") + public void setInfoLocked(AppWidgetProviderInfo info) { + this.info = info; + mInfoParsed = true; + } + @Override public String toString() { return "Provider{" + id + (zombie ? " Z" : "") + '}'; @@ -4049,6 +4080,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku this.componentName = componentName; } + public UserHandle getProfile() { + return UserHandle.getUserHandleForUid(uid); + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -4114,8 +4149,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku final int N = widgets.size(); for (int i = 0; i < N; i++) { Provider provider = widgets.get(i).provider; - if (provider != null && provider.getUserId() == userId && provider.info != null - && pkg.equals(provider.info.provider.getPackageName())) { + if (provider != null && provider.getUserId() == userId + && pkg.equals(provider.id.componentName.getPackageName())) { return true; } } @@ -4125,7 +4160,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku /** * Adds all pending updates in {@param outUpdates} keys by the update time. */ - public void getPendingUpdatesForId(int appWidgetId, + public void getPendingUpdatesForIdLocked(Context context, int appWidgetId, LongSparseArray outUpdates) { long updateSequenceNo = lastWidgetUpdateSequenceNo; int N = widgets.size(); @@ -4142,7 +4177,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku switch (id) { case ID_PROVIDER_CHANGED: update = PendingHostUpdate.providerChanged( - appWidgetId, widget.provider.info); + appWidgetId, widget.provider.getInfoLocked(context)); break; case ID_VIEWS_UPDATE: update = PendingHostUpdate.updateAppWidget(appWidgetId, @@ -4491,10 +4526,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Provider p = findProviderLocked(componentName, userId); if (p == null) { + AppWidgetProviderInfo info = new AppWidgetProviderInfo(); + info.provider = componentName; + p = new Provider(); p.id = new ProviderId(UNKNOWN_UID, componentName); - p.info = new AppWidgetProviderInfo(); - p.info.provider = componentName; + p.setPartialInfoLocked(info); p.zombie = true; mProviders.add(p); } @@ -4559,7 +4596,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } addWidgetLocked(id); } - if (id.provider != null && id.provider.info != null) { + if (id.provider != null + && id.provider.getPartialInfoLocked() != null) { stashProviderRestoreUpdateLocked(id.provider, restoredId, id.appWidgetId); } else { @@ -4785,7 +4823,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS, oldIds); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, newIds); if (provider != null) { - intent.setComponent(provider.info.provider); + intent.setComponent(provider.id.componentName); sendBroadcastAsUser(intent, userHandle); } if (host != null) {