From 0078e1b777fbd1b8d9e734632185851fee720cc9 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 11 Jan 2017 16:05:27 -0700 Subject: [PATCH] Add support for fallback categories. When an app doesn't define a category, look for a fallback category in a hard-coded list. This change only defines a fallback for a single package, but device-specific overlays can be used to provide more detailed fallback lists. The precidence order is: app manifest > installer hint > fallback Test: builds, boots, fallback categories work Bug: 33815939 Change-Id: I1f5ca76fb7e5743a4500c0a1230a754266f34d9e --- .../content/pm/FallbackCategoryProvider.java | 69 ++++++++++++++++++++++ core/java/android/content/pm/PackageParser.java | 3 + core/res/res/raw/fallback_categories.csv | 3 + core/res/res/values/symbols.xml | 2 + .../android/server/pm/PackageManagerService.java | 5 ++ 5 files changed, 82 insertions(+) create mode 100644 core/java/android/content/pm/FallbackCategoryProvider.java create mode 100644 core/res/res/raw/fallback_categories.csv diff --git a/core/java/android/content/pm/FallbackCategoryProvider.java b/core/java/android/content/pm/FallbackCategoryProvider.java new file mode 100644 index 000000000000..a0a11aa52c38 --- /dev/null +++ b/core/java/android/content/pm/FallbackCategoryProvider.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.pm; + +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.os.SystemProperties; +import android.util.ArrayMap; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * Class that provides fallback values for {@link ApplicationInfo#category}. + * + * @hide + */ +public class FallbackCategoryProvider { + private static final String TAG = "FallbackCategoryProvider"; + + private static final ArrayMap sFallbacks = new ArrayMap<>(); + + public static void loadFallbacks() { + sFallbacks.clear(); + if (SystemProperties.getBoolean("fw.ignore_fb_categories", false)) { + Log.d(TAG, "Ignoring fallback categories"); + return; + } + + final AssetManager assets = new AssetManager(); + assets.addAssetPath("/system/framework/framework-res.apk"); + final Resources res = new Resources(assets, null, null); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader( + res.openRawResource(com.android.internal.R.raw.fallback_categories)))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.charAt(0) == '#') continue; + final String[] split = line.split(","); + if (split.length == 2) { + sFallbacks.put(split[0], Integer.parseInt(split[1])); + } + } + Log.d(TAG, "Found " + sFallbacks.size() + " fallback categories"); + } catch (IOException | NumberFormatException e) { + Log.w(TAG, "Failed to read fallback categories", e); + } + } + + public static int getFallbackCategory(String packageName) { + return sFallbacks.getOrDefault(packageName, ApplicationInfo.CATEGORY_UNDEFINED); + } +} diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 9e1fe79291fa..a48762bd36fa 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -6260,6 +6260,9 @@ public class PackageParser { if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { ai.category = state.categoryHint; } + if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { + ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName); + } } public static ApplicationInfo generateApplicationInfo(Package p, int flags, diff --git a/core/res/res/raw/fallback_categories.csv b/core/res/res/raw/fallback_categories.csv new file mode 100644 index 000000000000..7ed5afa96a24 --- /dev/null +++ b/core/res/res/raw/fallback_categories.csv @@ -0,0 +1,3 @@ +# Default app categories used if neither the package nor installer sets anything +# First column is package name, second column is raw ApplicationInfo.CATEGORY value +com.android.printspooler,7 diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index cd07d88de50d..d46bdcf4f058 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2793,4 +2793,6 @@ + + diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 395ec1f26187..4382057a95a8 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -127,6 +127,7 @@ import android.content.pm.EphemeralApplicationInfo; import android.content.pm.EphemeralRequest; import android.content.pm.EphemeralResolveInfo; import android.content.pm.EphemeralResponse; +import android.content.pm.FallbackCategoryProvider; import android.content.pm.FeatureInfo; import android.content.pm.IOnPermissionsChangeListener; import android.content.pm.IPackageDataObserver; @@ -2822,6 +2823,10 @@ public class PackageManagerService extends IPackageManager.Stub { Runtime.getRuntime().gc(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks"); + FallbackCategoryProvider.loadFallbacks(); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + // The initial scanning above does many calls into installd while // holding the mPackages lock, but we're mostly interested in yelling // once we have a booted system. -- 2.11.0