diff options
336 files changed, 24455 insertions, 9031 deletions
diff --git a/Android.bp b/Android.bp index 6fc233c94310..69f5595fd69f 100644 --- a/Android.bp +++ b/Android.bp @@ -305,7 +305,7 @@ java_defaults { exclude_srcs: [ // See comment on framework-atb-backward-compatibility module below - "core/java/android/content/pm/AndroidTestBaseUpdater.java", + "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java", ], sdk_version: "core_platform", @@ -435,7 +435,7 @@ java_library { name: "framework-atb-backward-compatibility", installable: true, srcs: [ - "core/java/android/content/pm/AndroidTestBaseUpdater.java", + "core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java", ], } diff --git a/apex/jobscheduler/README_js-mainline.md b/apex/jobscheduler/README_js-mainline.md index c1ad666e3e05..ea20e3e29d99 100644 --- a/apex/jobscheduler/README_js-mainline.md +++ b/apex/jobscheduler/README_js-mainline.md @@ -1,23 +1,11 @@ # Making Job Scheduler into a Mainline Module -## TODOs - -See also: -- http://go/moving-js-code-for-mainline -- http://go/jobscheduler-code-dependencies-2019-07 - -- [ ] Move this into `frameworks/apex/jobscheduler/...`. Currently it's in `frameworks/base/apex/...` -because `frameworks/apex/` is not a part of any git projects. (and also working on multiple -projects is a pain.) - ## Current structure - JS service side classes are put in `jobscheduler-service.jar`. It's *not* included in services.jar, and instead it's put in the system server classpath, which currently looks like the following: -`SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/jobscheduler-service.jar:/system/framework/ethernet-service.jar:/system/framework/wifi-service.jar:/system/framework/com.android.location.provider.jar` - - (Note `jobscheduler-service.jar` will be put at the end in http://ag/9128109) +`SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/com.android.location.provider.jar:/system/framework/jobscheduler-service.jar` `SYSTEMSERVERCLASSPATH` is generated from `PRODUCT_SYSTEM_SERVER_JARS`. @@ -29,10 +17,4 @@ as of http://ag/9145619. `framework.jar` merging the two jar files, and this jar file is what's put on the device and loaded by Zygote. - -This is *not* the final design. From a gerrit comment on http://ag/9145619: - -> This CL is just the first step, and the current state isn't not really the final form. For now we just want to have two separate jars, which makes it easier for us to analyze dependencies between them, and I wanted to minimize the change to the rest of the system. So, for example, zygote will still only have "framework.jar" in its classpath, instead of the two jars for now. -> But yes, eventually, we won't even be able to have the monolithic "framework.jar" file because of mainline, so we need to figure out how to build the system without creating it. At that point zygote will have the two separate jar files in its classpath. -> When we reach that point, we should revisit the naming of it, and yes, maybe the simple "framework.jar" is a good option. -> But again, for now, I want to make this change as transparent as possible to the rest of the world. +The current structure is *not* the final design. diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index c2bdb6caffd3..2f5f555817ec 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -1157,22 +1157,14 @@ public final class JobStore { private void removeAll(Predicate<JobStatus> predicate) { for (int jobSetIndex = mJobs.size() - 1; jobSetIndex >= 0; jobSetIndex--) { final ArraySet<JobStatus> jobs = mJobs.valueAt(jobSetIndex); - for (int jobIndex = jobs.size() - 1; jobIndex >= 0; jobIndex--) { - if (predicate.test(jobs.valueAt(jobIndex))) { - jobs.removeAt(jobIndex); - } - } + jobs.removeIf(predicate); if (jobs.size() == 0) { mJobs.removeAt(jobSetIndex); } } for (int jobSetIndex = mJobsPerSourceUid.size() - 1; jobSetIndex >= 0; jobSetIndex--) { final ArraySet<JobStatus> jobs = mJobsPerSourceUid.valueAt(jobSetIndex); - for (int jobIndex = jobs.size() - 1; jobIndex >= 0; jobIndex--) { - if (predicate.test(jobs.valueAt(jobIndex))) { - jobs.removeAt(jobIndex); - } - } + jobs.removeIf(predicate); if (jobs.size() == 0) { mJobsPerSourceUid.removeAt(jobSetIndex); } diff --git a/api/current.txt b/api/current.txt index fc7685d2da97..44cb997a250d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -44291,6 +44291,7 @@ package android.telephony { field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool"; field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool"; + field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool"; field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool"; field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool"; field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int"; diff --git a/api/system-current.txt b/api/system-current.txt index 279d2c89808e..fcf69a7592a4 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -7858,6 +7858,8 @@ package android.telephony { method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes); method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onCallDisconnectCauseChanged(int, int); method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo); + method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber); + method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber); method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState); method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState); method public void onRadioPowerStateChanged(int); diff --git a/api/test-current.txt b/api/test-current.txt index 75d80bd9eeaf..ee631bee5750 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -786,7 +786,7 @@ package android.content.res { public final class AssetManager implements java.lang.AutoCloseable { method @NonNull public String[] getApkPaths(); - method @Nullable public java.util.Map<java.lang.String,java.lang.String> getOverlayableMap(String); + method @Nullable public String getOverlayablesToString(String); } public final class Configuration implements java.lang.Comparable<android.content.res.Configuration> android.os.Parcelable { @@ -2890,6 +2890,11 @@ package android.telephony { method public static void setMinMatchForTest(int); } + public class PhoneStateListener { + field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER = 268435456; // 0x10000000 + field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER = 536870912; // 0x20000000 + } + public class ServiceState implements android.os.Parcelable { method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo); method public void setCdmaSystemAndNetworkId(int, int); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index b71a86b87d49..6249de3d3bac 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -378,7 +378,6 @@ message Atom { PowerProfile power_profile = 10033; ProcStatsPkgProc proc_stats_pkg_proc = 10034; ProcessCpuTime process_cpu_time = 10035; - NativeProcessMemoryState native_process_memory_state = 10036; CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037; OnDevicePowerMeasurement on_device_power_measurement = 10038; DeviceCalculatedPowerUse device_calculated_power_use = 10039; @@ -412,6 +411,8 @@ message Atom { // DO NOT USE field numbers above 100,000 in AOSP. // Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use. // Field numbers 200,000 and above are reserved for future use; do not use them at all. + + reserved 10036; } /** @@ -4019,8 +4020,8 @@ message ProcessMemoryState { optional int64 page_major_fault = 5; // RSS - // Value is read from /proc/PID/status. Or from memory.stat, field - // total_rss if per-app memory cgroups are enabled. + // Value is read from memory.stat, field total_rss if per-app memory + // cgroups are enabled. Otherwise, value from /proc/pid/stat. optional int64 rss_in_bytes = 6; // CACHE @@ -4030,56 +4031,17 @@ message ProcessMemoryState { // SWAP // Value is read from memory.stat, field total_swap if per-app memory - // cgroups are enabled. Otherwise, VmSwap from /proc/PID/status. + // cgroups are enabled. Otherwise, 0. optional int64 swap_in_bytes = 8; - // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0. + // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always -1. optional int64 rss_high_watermark_in_bytes = 9 [deprecated = true]; - // Elapsed real time when the process started. - // Value is read from /proc/PID/stat, field 22. 0 if read from per-app memory cgroups. - optional int64 start_time_nanos = 10; - - // Anonymous page size plus swap size. Values are read from /proc/PID/status. - optional int32 anon_rss_and_swap_in_kilobytes = 11; -} - -/* - * Logs the memory stats for a native process (from procfs). - * - * Pulled from StatsCompanionService for selected native processes. - */ -message NativeProcessMemoryState { - // The uid if available. -1 means not available. - optional int32 uid = 1 [(is_uid) = true]; - - // The process name. - // Value read from /proc/PID/cmdline. - optional string process_name = 2; - - // # of page-faults - optional int64 page_fault = 3; - - // # of major page-faults - optional int64 page_major_fault = 4; - - // RSS - // Value read from /proc/PID/status. - optional int64 rss_in_bytes = 5; - - // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0. - optional int64 rss_high_watermark_in_bytes = 6 [deprecated = true]; - - // Elapsed real time when the process started. - // Value is read from /proc/PID/stat, field 22. - optional int64 start_time_nanos = 7; - - // SWAP - // Value read from /proc/PID/status, field VmSwap. - optional int64 swap_in_bytes = 8; + // Deprecated: use ProcessMemorySnapshot atom instead. Always -1. + optional int64 start_time_nanos = 10 [deprecated = true]; - // Anonymous page size plus swap size. Values are read from /proc/PID/status. - optional int32 anon_rss_and_swap_in_kilobytes = 9; + // Deprecated: use ProcessMemorySnapshot atom instead. Always -1. + optional int32 anon_rss_and_swap_in_kilobytes = 11 [deprecated = true]; } /* diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 7a183a3b1b2e..43e33f59f612 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -145,16 +145,11 @@ std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}}, // process_memory_state {android::util::PROCESS_MEMORY_STATE, - {.additiveFields = {4, 5, 6, 7, 8, 9}, + {.additiveFields = {4, 5, 6, 7, 8}, .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, - // native_process_memory_state - {android::util::NATIVE_PROCESS_MEMORY_STATE, - {.additiveFields = {3, 4, 5, 6, 8}, - .puller = new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}}, // process_memory_high_water_mark {android::util::PROCESS_MEMORY_HIGH_WATER_MARK, - {.additiveFields = {3}, - .puller = + {.puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}}, // process_memory_snapshot {android::util::PROCESS_MEMORY_SNAPSHOT, diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java index e0f7d862e70a..b37ee74b100c 100644 --- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java +++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java @@ -65,6 +65,14 @@ public final class Telecom extends BaseCommand { private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account"; private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer"; private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer"; + /** + * Change the system dialer package name if a package name was specified, + * Example: adb shell telecom set-system-dialer <PACKAGE> + * + * Restore it to the default if if argument is "default" or no argument is passed. + * Example: adb shell telecom set-system-dialer default + */ + private static final String COMMAND_SET_SYSTEM_DIALER = "set-system-dialer"; private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer"; private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers"; private static final String COMMAND_SET_SIM_COUNT = "set-sim-count"; @@ -193,6 +201,9 @@ public final class Telecom extends BaseCommand { case COMMAND_GET_DEFAULT_DIALER: runGetDefaultDialer(); break; + case COMMAND_SET_SYSTEM_DIALER: + runSetSystemDialer(); + break; case COMMAND_GET_SYSTEM_DIALER: runGetSystemDialer(); break; @@ -297,6 +308,12 @@ public final class Telecom extends BaseCommand { System.out.println("Success - " + packageName + " set as override default dialer."); } + private void runSetSystemDialer() throws RemoteException { + final String packageName = nextArg(); + mTelecomService.setSystemDialerPackage(packageName.equals("default") ? null : packageName); + System.out.println("Success - " + packageName + " set as override system dialer."); + } + private void runGetDefaultDialer() throws RemoteException { System.out.println(mTelecomService.getDefaultDialerPackage()); } diff --git a/config/preloaded-classes b/config/preloaded-classes index 8d911443ce06..5698dfe8a586 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -877,7 +877,7 @@ android.content.pm.-$$Lambda$jpya2qgMDDEok2GAoKRDqPM5lIE android.content.pm.ActivityInfo$1 android.content.pm.ActivityInfo$WindowLayout android.content.pm.ActivityInfo -android.content.pm.AndroidHidlUpdater +android.content.pm.parsing.library.AndroidHidlUpdater android.content.pm.ApplicationInfo$1 android.content.pm.ApplicationInfo android.content.pm.BaseParceledListSlice @@ -921,10 +921,10 @@ android.content.pm.LauncherApps$1 android.content.pm.LauncherApps android.content.pm.ModuleInfo$1 android.content.pm.ModuleInfo -android.content.pm.OrgApacheHttpLegacyUpdater -android.content.pm.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater -android.content.pm.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary -android.content.pm.PackageBackwardCompatibility +android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater +android.content.pm.parsing.library.PackageBackwardCompatibility$AndroidTestRunnerSplitUpdater +android.content.pm.parsing.library.PackageBackwardCompatibility$RemoveUnnecessaryAndroidTestBaseLibrary +android.content.pm.parsing.library.PackageBackwardCompatibility android.content.pm.PackageInfo$1 android.content.pm.PackageInfo android.content.pm.PackageInstaller$Session @@ -959,7 +959,7 @@ android.content.pm.PackageParser$SigningDetails$1 android.content.pm.PackageParser$SigningDetails android.content.pm.PackageParser$SplitNameComparator android.content.pm.PackageParser -android.content.pm.PackageSharedLibraryUpdater +android.content.pm.parsing.library.PackageSharedLibraryUpdater android.content.pm.PackageStats$1 android.content.pm.PackageStats android.content.pm.PackageUserState diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java index 08c97eb284e3..19d158dedd06 100644 --- a/core/java/android/app/AppCompatCallbacks.java +++ b/core/java/android/app/AppCompatCallbacks.java @@ -18,7 +18,6 @@ package android.app; import android.compat.Compatibility; import android.os.Process; -import android.util.Log; import android.util.StatsLog; import com.android.internal.compat.ChangeReporter; @@ -31,8 +30,6 @@ import java.util.Arrays; * @hide */ public final class AppCompatCallbacks extends Compatibility.Callbacks { - private static final String TAG = "Compatibility"; - private final long[] mDisabledChanges; private final ChangeReporter mChangeReporter; @@ -48,7 +45,8 @@ public final class AppCompatCallbacks extends Compatibility.Callbacks { private AppCompatCallbacks(long[] disabledChanges) { mDisabledChanges = Arrays.copyOf(disabledChanges, disabledChanges.length); Arrays.sort(mDisabledChanges); - mChangeReporter = new ChangeReporter(); + mChangeReporter = new ChangeReporter( + StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__APP_PROCESS); } protected void reportChange(long changeId) { @@ -67,10 +65,7 @@ public final class AppCompatCallbacks extends Compatibility.Callbacks { private void reportChange(long changeId, int state) { int uid = Process.myUid(); - //TODO(b/138374585): Implement rate limiting for the logs. - Log.d(TAG, ChangeReporter.createLogString(uid, changeId, state)); - mChangeReporter.reportChange(uid, changeId, - state, /* source */StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__APP_PROCESS); + mChangeReporter.reportChange(uid, changeId, state); } } diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index 8765760b216b..b873be3e7042 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -153,4 +153,11 @@ public abstract class DevicePolicyManagerInternal { * Do not call it directly. Use {@link DevicePolicyCache#getInstance()} instead. */ protected abstract DevicePolicyCache getDevicePolicyCache(); + + /** + * @return cached version of device state related to DPM that can be accessed without risking + * deadlocks. + * Do not call it directly. Use {@link DevicePolicyCache#getInstance()} instead. + */ + protected abstract DeviceStateCache getDeviceStateCache(); } diff --git a/core/java/android/app/admin/DeviceStateCache.java b/core/java/android/app/admin/DeviceStateCache.java new file mode 100644 index 000000000000..7619aa2b7473 --- /dev/null +++ b/core/java/android/app/admin/DeviceStateCache.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2019 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.app.admin; + +import com.android.server.LocalServices; + +/** + * Stores a copy of the set of device state maintained by {@link DevicePolicyManager} which + * is not directly related to admin policies. This lives in its own class so that the state + * can be accessed from any place without risking dead locks. + * + * @hide + */ +public abstract class DeviceStateCache { + protected DeviceStateCache() { + } + + /** + * @return the instance. + */ + public static DeviceStateCache getInstance() { + final DevicePolicyManagerInternal dpmi = + LocalServices.getService(DevicePolicyManagerInternal.class); + return (dpmi != null) ? dpmi.getDeviceStateCache() : EmptyDeviceStateCache.INSTANCE; + } + + /** + * See {@link DevicePolicyManager#isDeviceProvisioned} + */ + public abstract boolean isDeviceProvisioned(); + + /** + * Empty implementation. + */ + private static class EmptyDeviceStateCache extends DeviceStateCache { + private static final EmptyDeviceStateCache INSTANCE = new EmptyDeviceStateCache(); + + @Override + public boolean isDeviceProvisioned() { + return false; + } + } +} diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 415c2428405f..29f243f76905 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -1379,7 +1379,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { this.minHeight = minHeight; } - WindowLayout(Parcel source) { + /** @hide */ + public WindowLayout(Parcel source) { width = source.readInt(); widthFraction = source.readFloat(); height = source.readInt(); diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index d6fb28f694fd..aa0002df2c3a 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -373,8 +373,9 @@ public class PackageInfo implements Parcelable { /** * Whether the overlay is static, meaning it cannot be enabled/disabled at runtime. + * @hide */ - boolean mOverlayIsStatic; + public boolean mOverlayIsStatic; /** * The user-visible SDK version (ex. 26) of the framework against which the application claims diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index f28b85ccbedc..746549814c8d 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -28,6 +28,8 @@ import android.content.pm.PackageManager.ApplicationInfoFlags; import android.content.pm.PackageManager.ComponentInfoFlags; import android.content.pm.PackageManager.PackageInfoFlags; import android.content.pm.PackageManager.ResolveInfoFlags; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils; import android.os.Bundle; import android.os.PersistableBundle; import android.util.ArraySet; @@ -315,7 +317,7 @@ public abstract class PackageManagerInternal { * @param installed the new installed state * @return true if the installed state changed as a result */ - public abstract boolean setInstalled(PackageParser.Package pkg, + public abstract boolean setInstalled(AndroidPackage pkg, @UserIdInt int userId, boolean installed); /** @@ -394,7 +396,7 @@ public abstract class PackageManagerInternal { * Returns whether or not the given package represents a legacy system application released * prior to runtime permissions. */ - public abstract boolean isLegacySystemApp(PackageParser.Package pkg); + public abstract boolean isLegacySystemApp(AndroidPackage pkg); /** * Get all overlay packages for a user. @@ -486,13 +488,17 @@ public abstract class PackageManagerInternal { /** * Returns a package object for the given package name. */ - public abstract @Nullable PackageParser.Package getPackage(@NonNull String packageName); + public abstract @Nullable AndroidPackage getPackage(@NonNull String packageName); + + // TODO(b/135203078): PackageSetting can't be referenced directly. Should move to a server side + // internal PM which is aware of PS. + public abstract @Nullable Object getPackageSetting(String packageName); /** * Returns a package for the given UID. If the UID is part of a shared user ID, one * of the packages will be chosen to be returned. */ - public abstract @Nullable PackageParser.Package getPackage(int uid); + public abstract @Nullable AndroidPackage getPackage(int uid); /** * Returns a list without a change observer. @@ -523,17 +529,19 @@ public abstract class PackageManagerInternal { */ public abstract void removePackageListObserver(@NonNull PackageListObserver observer); + // TODO(b/135203078): PackageSetting can't be referenced directly /** * Returns a package object for the disabled system package name. */ - public abstract @Nullable PackageParser.Package getDisabledSystemPackage( - @NonNull String packageName); + public abstract @Nullable Object getDisabledSystemPackage(@NonNull String packageName); /** * Returns the package name for the disabled system package. * * This is equivalent to - * {@link #getDisabledSystemPackage(String)}.{@link PackageParser.Package#packageName} + * {@link #getDisabledSystemPackage(String)} + * .{@link com.android.server.pm.PackageSetting#pkg} + * .{@link AndroidPackage#getPackageName()} */ public abstract @Nullable String getDisabledSystemPackageName(@NonNull String packageName); @@ -567,7 +575,7 @@ public abstract class PackageManagerInternal { * @see #canAccessInstantApps */ public abstract boolean filterAppAccess( - @NonNull PackageParser.Package pkg, int callingUid, int userId); + @NonNull AndroidPackage pkg, int callingUid, int userId); /** * Returns whether or not access to the application should be filtered. @@ -641,7 +649,8 @@ public abstract class PackageManagerInternal { throws IOException; /** Returns {@code true} if the specified component is enabled and matches the given flags. */ - public abstract boolean isEnabledAndMatches(@NonNull ComponentInfo info, int flags, int userId); + public abstract boolean isEnabledAndMatches( + @NonNull ComponentParseUtils.ParsedComponent component, int flags, int userId); /** Returns {@code true} if the given user requires extra badging for icons. */ public abstract boolean userNeedsBadging(int userId); @@ -652,14 +661,14 @@ public abstract class PackageManagerInternal { * * @param actionLocked action to be performed */ - public abstract void forEachPackage(Consumer<PackageParser.Package> actionLocked); + public abstract void forEachPackage(Consumer<AndroidPackage> actionLocked); /** * Perform the given action for each installed package for a user. * Note that packages lock will be held while performin the actions. */ public abstract void forEachInstalledPackage( - @NonNull Consumer<PackageParser.Package> actionLocked, @UserIdInt int userId); + @NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId); /** Returns the list of enabled components */ public abstract ArraySet<String> getEnabledComponents(String packageName, int userId); @@ -793,7 +802,7 @@ public abstract class PackageManagerInternal { * Otherwise, {@code false}. */ public abstract boolean isCallerInstallerOfRecord( - @NonNull PackageParser.Package pkg, int callingUid); + @NonNull AndroidPackage pkg, int callingUid); /** Returns whether or not default runtime permissions are granted for the given user */ public abstract boolean areDefaultRuntimePermissionsGranted(@UserIdInt int userId); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 0b157fa3bb1e..2ded5dcae0d9 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -57,6 +57,12 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageParserCacheHelper.ReadHelper; import android.content.pm.PackageParserCacheHelper.WriteHelper; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ApkParseUtils; +import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.ParsedPackage; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.content.pm.split.DefaultSplitAssetLoader; import android.content.pm.split.SplitAssetDependencyLoader; @@ -67,7 +73,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.FileUtils; @@ -156,21 +161,22 @@ import java.util.concurrent.atomic.AtomicInteger; * @hide */ public class PackageParser { - private static final boolean DEBUG_JAR = false; - private static final boolean DEBUG_PARSER = false; - private static final boolean DEBUG_BACKUP = false; - private static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE; - private static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100; + + public static final boolean DEBUG_JAR = false; + public static final boolean DEBUG_PARSER = false; + public static final boolean DEBUG_BACKUP = false; + public static final boolean LOG_PARSE_TIMINGS = Build.IS_DEBUGGABLE; + public static final int LOG_PARSE_TIMINGS_THRESHOLD_MS = 100; private static final String PROPERTY_CHILD_PACKAGES_ENABLED = "persist.sys.child_packages_enabled"; - private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE && + public static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE && SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false); - private static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; - private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f; - private static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f; + public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; + public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f; + public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f; private static final int DEFAULT_MIN_SDK_VERSION = 1; private static final int DEFAULT_TARGET_SDK_VERSION = 0; @@ -182,37 +188,38 @@ public class PackageParser { public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; /** Path prefix for apps on expanded storage */ - private static final String MNT_EXPAND = "/mnt/expand/"; - - private static final String TAG_MANIFEST = "manifest"; - private static final String TAG_APPLICATION = "application"; - private static final String TAG_PACKAGE_VERIFIER = "package-verifier"; - private static final String TAG_OVERLAY = "overlay"; - private static final String TAG_KEY_SETS = "key-sets"; - private static final String TAG_PERMISSION_GROUP = "permission-group"; - private static final String TAG_PERMISSION = "permission"; - private static final String TAG_PERMISSION_TREE = "permission-tree"; - private static final String TAG_USES_PERMISSION = "uses-permission"; - private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; - private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; - private static final String TAG_USES_CONFIGURATION = "uses-configuration"; - private static final String TAG_USES_FEATURE = "uses-feature"; - private static final String TAG_FEATURE_GROUP = "feature-group"; - private static final String TAG_USES_SDK = "uses-sdk"; - private static final String TAG_SUPPORT_SCREENS = "supports-screens"; - private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; - private static final String TAG_INSTRUMENTATION = "instrumentation"; - private static final String TAG_ORIGINAL_PACKAGE = "original-package"; - private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; - private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; - private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; - private static final String TAG_SUPPORTS_INPUT = "supports-input"; - private static final String TAG_EAT_COMMENT = "eat-comment"; - private static final String TAG_PACKAGE = "package"; - private static final String TAG_RESTRICT_UPDATE = "restrict-update"; - private static final String TAG_USES_SPLIT = "uses-split"; - - private static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect"; + public static final String MNT_EXPAND = "/mnt/expand/"; + + public static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions"; + public static final String TAG_APPLICATION = "application"; + public static final String TAG_COMPATIBLE_SCREENS = "compatible-screens"; + public static final String TAG_EAT_COMMENT = "eat-comment"; + public static final String TAG_FEATURE_GROUP = "feature-group"; + public static final String TAG_INSTRUMENTATION = "instrumentation"; + public static final String TAG_KEY_SETS = "key-sets"; + public static final String TAG_MANIFEST = "manifest"; + public static final String TAG_ORIGINAL_PACKAGE = "original-package"; + public static final String TAG_OVERLAY = "overlay"; + public static final String TAG_PACKAGE = "package"; + public static final String TAG_PACKAGE_VERIFIER = "package-verifier"; + public static final String TAG_PERMISSION = "permission"; + public static final String TAG_PERMISSION_GROUP = "permission-group"; + public static final String TAG_PERMISSION_TREE = "permission-tree"; + public static final String TAG_PROTECTED_BROADCAST = "protected-broadcast"; + public static final String TAG_QUERIES = "queries"; + public static final String TAG_RESTRICT_UPDATE = "restrict-update"; + public static final String TAG_SUPPORT_SCREENS = "supports-screens"; + public static final String TAG_SUPPORTS_INPUT = "supports-input"; + public static final String TAG_USES_CONFIGURATION = "uses-configuration"; + public static final String TAG_USES_FEATURE = "uses-feature"; + public static final String TAG_USES_GL_TEXTURE = "uses-gl-texture"; + public static final String TAG_USES_PERMISSION = "uses-permission"; + public static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23"; + public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m"; + public static final String TAG_USES_SDK = "uses-sdk"; + public static final String TAG_USES_SPLIT = "uses-split"; + + public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect"; /** * Bit mask of all the valid bits that can be set in recreateOnConfigChanges. @@ -222,25 +229,25 @@ public class PackageParser { ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC; // These are the tags supported by child packages - private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>(); + public static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>(); static { CHILD_PACKAGE_TAGS.add(TAG_APPLICATION); - CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION); - CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M); - CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23); - CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION); - CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE); + CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS); + CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT); CHILD_PACKAGE_TAGS.add(TAG_FEATURE_GROUP); - CHILD_PACKAGE_TAGS.add(TAG_USES_SDK); - CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS); CHILD_PACKAGE_TAGS.add(TAG_INSTRUMENTATION); - CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE); - CHILD_PACKAGE_TAGS.add(TAG_COMPATIBLE_SCREENS); + CHILD_PACKAGE_TAGS.add(TAG_SUPPORT_SCREENS); CHILD_PACKAGE_TAGS.add(TAG_SUPPORTS_INPUT); - CHILD_PACKAGE_TAGS.add(TAG_EAT_COMMENT); + CHILD_PACKAGE_TAGS.add(TAG_USES_CONFIGURATION); + CHILD_PACKAGE_TAGS.add(TAG_USES_FEATURE); + CHILD_PACKAGE_TAGS.add(TAG_USES_GL_TEXTURE); + CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION); + CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_23); + CHILD_PACKAGE_TAGS.add(TAG_USES_PERMISSION_SDK_M); + CHILD_PACKAGE_TAGS.add(TAG_USES_SDK); } - private static final boolean LOG_UNSAFE_BROADCASTS = false; + public static final boolean LOG_UNSAFE_BROADCASTS = false; /** * Total number of packages that were read from the cache. We use it only for logging. @@ -248,7 +255,7 @@ public class PackageParser { public static final AtomicInteger sCachedPackageReadCount = new AtomicInteger(); // Set of broadcast actions that are safe for manifest receivers - private static final Set<String> SAFE_BROADCASTS = new ArraySet<>(); + public static final Set<String> SAFE_BROADCASTS = new ArraySet<>(); static { SAFE_BROADCASTS.add(Intent.ACTION_BOOT_COMPLETED); } @@ -295,26 +302,29 @@ public class PackageParser { * @deprecated callers should move to explicitly passing around source path. */ @Deprecated - private String mArchiveSourcePath; + public String mArchiveSourcePath; - private String[] mSeparateProcesses; + public String[] mSeparateProcesses; private boolean mOnlyCoreApps; private DisplayMetrics mMetrics; @UnsupportedAppUsage - private Callback mCallback; + public Callback mCallback; private File mCacheDir; - private static final int SDK_VERSION = Build.VERSION.SDK_INT; - private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; + public static final int SDK_VERSION = Build.VERSION.SDK_INT; + public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; + + public int mParseError = PackageManager.INSTALL_SUCCEEDED; - private int mParseError = PackageManager.INSTALL_SUCCEEDED; + public ThreadLocal<ApkParseUtils.ParseResult> mSharedResult + = ThreadLocal.withInitial(ApkParseUtils.ParseResult::new); - private static boolean sCompatibilityModeEnabled = true; - private static boolean sUseRoundIcon = false; + public static boolean sCompatibilityModeEnabled = true; + public static boolean sUseRoundIcon = false; - private static final int PARSE_DEFAULT_INSTALL_LOCATION = + public static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED; - private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; + public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; static class ParsePackageItemArgs { final Package owner; @@ -536,7 +546,7 @@ public class PackageParser { * the DTD. Otherwise, we try to get as much from the package as we * can without failing. This should normally be set to false, to * support extensions to the DTD in future versions. */ - private static final boolean RIGID_PARSER = false; + public static final boolean RIGID_PARSER = false; private static final String TAG = "PackageParser"; @@ -897,7 +907,7 @@ public class PackageParser { @Retention(RetentionPolicy.SOURCE) public @interface ParseFlags {} - private static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); + public static final Comparator<String> sSplitNameComparator = new SplitNameComparator(); /** * Used to sort a set of APKs based on their split names, always placing the @@ -1043,7 +1053,7 @@ public class PackageParser { * and unique split names. * <p> * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(Package, int)}. + * must be done separately in {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. * * If {@code useCaches} is true, the package parser might return a cached * result from a previous parse of the same {@code packageFile} with the same @@ -1051,21 +1061,54 @@ public class PackageParser { * has changed since the last parse, it's up to callers to do so. * * @see #parsePackageLite(File, int) + * @deprecated use {@link #parseParsedPackage(File, int, boolean)} */ @UnsupportedAppUsage + @Deprecated public Package parsePackage(File packageFile, int flags, boolean useCaches) throws PackageParserException { - Package parsed = useCaches ? getCachedResult(packageFile, flags) : null; + if (packageFile.isDirectory()) { + return parseClusterPackage(packageFile, flags); + } else { + return parseMonolithicPackage(packageFile, flags); + } + } + + /** + * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}. + * @deprecated use {@link #parseParsedPackage(File, int, boolean)} + */ + @UnsupportedAppUsage + @Deprecated + public Package parsePackage(File packageFile, int flags) throws PackageParserException { + return parsePackage(packageFile, flags, false /* useCaches */); + } + + /** + * Updated method which returns {@link ParsedPackage}, the current representation of a + * package parsed from disk. + * + * @see #parsePackage(File, int, boolean) + */ + public ParsedPackage parseParsedPackage(File packageFile, int flags, boolean useCaches) + throws PackageParserException { + ParsedPackage parsed = useCaches ? getCachedResult(packageFile, flags) : null; if (parsed != null) { return parsed; } long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; - if (packageFile.isDirectory()) { - parsed = parseClusterPackage(packageFile, flags); - } else { - parsed = parseMonolithicPackage(packageFile, flags); - } + ApkParseUtils.ParseInput parseInput = mSharedResult.get().reset(); + parsed = ApkParseUtils.parsePackage( + parseInput, + mSeparateProcesses, + mCallback, + mMetrics, + mOnlyCoreApps, + packageFile, + flags + ) + .hideAsParsed(); long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0; cacheResult(packageFile, flags, parsed); @@ -1077,19 +1120,12 @@ public class PackageParser { + "ms, update_cache=" + cacheTime + " ms"); } } - return parsed; - } - /** - * Equivalent to {@link #parsePackage(File, int, boolean)} with {@code useCaches == false}. - */ - @UnsupportedAppUsage - public Package parsePackage(File packageFile, int flags) throws PackageParserException { - return parsePackage(packageFile, flags, false /* useCaches */); + return parsed; } /** - * Returns the cache key for a specificied {@code packageFile} and {@code flags}. + * Returns the cache key for a specified {@code packageFile} and {@code flags}. */ private String getCacheKey(File packageFile, int flags) { StringBuilder sb = new StringBuilder(packageFile.getName()); @@ -1100,13 +1136,13 @@ public class PackageParser { } @VisibleForTesting - protected Package fromCacheEntry(byte[] bytes) { + protected ParsedPackage fromCacheEntry(byte[] bytes) { return fromCacheEntryStatic(bytes); } /** static version of {@link #fromCacheEntry} for unit tests. */ @VisibleForTesting - public static Package fromCacheEntryStatic(byte[] bytes) { + public static ParsedPackage fromCacheEntryStatic(byte[] bytes) { final Parcel p = Parcel.obtain(); p.unmarshall(bytes, 0, bytes.length); p.setDataPosition(0); @@ -1114,7 +1150,8 @@ public class PackageParser { final ReadHelper helper = new ReadHelper(p); helper.startAndInstall(); - PackageParser.Package pkg = new PackageParser.Package(p); + // TODO(b/135203078): Hide PackageImpl constructor? + ParsedPackage pkg = new PackageImpl(p); p.recycle(); @@ -1124,14 +1161,14 @@ public class PackageParser { } @VisibleForTesting - protected byte[] toCacheEntry(Package pkg) { + protected byte[] toCacheEntry(ParsedPackage pkg) { return toCacheEntryStatic(pkg); } /** static version of {@link #toCacheEntry} for unit tests. */ @VisibleForTesting - public static byte[] toCacheEntryStatic(Package pkg) { + public static byte[] toCacheEntryStatic(ParsedPackage pkg) { final Parcel p = Parcel.obtain(); final WriteHelper helper = new WriteHelper(p); @@ -1180,7 +1217,7 @@ public class PackageParser { * Returns the cached parse result for {@code packageFile} for parse flags {@code flags}, * or {@code null} if no cached result exists. */ - private Package getCachedResult(File packageFile, int flags) { + public ParsedPackage getCachedResult(File packageFile, int flags) { if (mCacheDir == null) { return null; } @@ -1195,9 +1232,9 @@ public class PackageParser { } final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath()); - Package p = fromCacheEntry(bytes); + ParsedPackage p = fromCacheEntry(bytes); if (mCallback != null) { - String[] overlayApks = mCallback.getOverlayApks(p.packageName); + String[] overlayApks = mCallback.getOverlayApks(p.getPackageName()); if (overlayApks != null && overlayApks.length > 0) { for (String overlayApk : overlayApks) { // If a static RRO is updated, return null. @@ -1221,7 +1258,7 @@ public class PackageParser { /** * Caches the parse result for {@code packageFile} with flags {@code flags}. */ - private void cacheResult(File packageFile, int flags, Package parsed) { + public void cacheResult(File packageFile, int flags, ParsedPackage parsed) { if (mCacheDir == null) { return; } @@ -1260,7 +1297,8 @@ public class PackageParser { * split names. * <p> * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(Package, int)}. + * must be done separately in + * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. */ private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { final PackageLite lite = parseClusterPackageLite(packageDir, 0); @@ -1324,10 +1362,11 @@ public class PackageParser { * Parse the given APK file, treating it as as a single monolithic package. * <p> * Note that this <em>does not</em> perform signature verification; that - * must be done separately in {@link #collectCertificates(Package, int)}. + * must be done separately in + * {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)}. * * @deprecated external callers should move to - * {@link #parsePackage(File, int)}. Eventually this method will + * {@link #parseParsedPackage(File, int, boolean)}. Eventually this method will * be marked private. */ @Deprecated @@ -1527,8 +1566,11 @@ public class PackageParser { * Collect certificates from all the APKs described in the given package, * populating {@link Package#mSigningDetails}. Also asserts that all APK * contents are signed correctly and consistently. + * + * @deprecated use {@link ApkParseUtils#collectCertificates(AndroidPackage, boolean)} */ @UnsupportedAppUsage + @Deprecated public static void collectCertificates(Package pkg, boolean skipVerify) throws PackageParserException { collectCertificatesInternal(pkg, skipVerify); @@ -1707,7 +1749,7 @@ public class PackageParser { ? null : "must have at least one '.' separator"; } - private static Pair<String, String> parsePackageSplitNames(XmlPullParser parser, + public static Pair<String, String> parsePackageSplitNames(XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException, PackageParserException { @@ -2487,8 +2529,6 @@ public class PackageParser { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; - } else if (tagName.equals("queries")) { - parseQueries(pkg, res, parser, flags, outError); } else { Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() + " at " + mArchiveSourcePath + " " @@ -2958,7 +2998,7 @@ public class PackageParser { return true; } - private static String buildClassName(String pkg, CharSequence clsSeq, + public static String buildClassName(String pkg, CharSequence clsSeq, String[] outError) { if (clsSeq == null || clsSeq.length() <= 0) { outError[0] = "Empty class name in package " + pkg; @@ -3006,7 +3046,7 @@ public class PackageParser { return proc; } - private static String buildProcessName(String pkg, String defProc, + public static String buildProcessName(String pkg, String defProc, CharSequence procSeq, int flags, String[] separateProcesses, String[] outError) { if ((flags&PARSE_IGNORE_PROCESSES) != 0 && !"system".equals(procSeq)) { @@ -3026,7 +3066,7 @@ public class PackageParser { return TextUtils.safeIntern(buildCompoundName(pkg, procSeq, "process", outError)); } - private static String buildTaskAffinityName(String pkg, String defProc, + public static String buildTaskAffinityName(String pkg, String defProc, CharSequence procSeq, String[] outError) { if (procSeq == null) { return defProc; @@ -3588,9 +3628,6 @@ public class PackageParser { owner.mRequiredAccountType = requiredAccountType; } - owner.mForceQueryable = - sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false); - if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_debuggable, false)) { @@ -4052,89 +4089,6 @@ public class PackageParser { return true; } - private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags, - String[] outError) - throws IOException, XmlPullParserException { - - final int outerDepth = parser.getDepth(); - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG - || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - if (parser.getName().equals("intent")) { - QueriesIntentInfo intentInfo = new QueriesIntentInfo(); - if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/, - intentInfo, outError)) { - return false; - } - - Uri data = null; - String dataType = null; - String host = ""; - final int numActions = intentInfo.countActions(); - final int numSchemes = intentInfo.countDataSchemes(); - final int numTypes = intentInfo.countDataTypes(); - final int numHosts = intentInfo.getHosts().length; - if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) { - outError[0] = "intent tags must contain either an action or data."; - return false; - } - if (numActions > 1) { - outError[0] = "intent tag may have at most one action."; - return false; - } - if (numTypes > 1) { - outError[0] = "intent tag may have at most one data type."; - return false; - } - if (numSchemes > 1) { - outError[0] = "intent tag may have at most one data scheme."; - return false; - } - if (numHosts > 1) { - outError[0] = "intent tag may have at most one data host."; - return false; - } - Intent intent = new Intent(); - for (int i = 0, max = intentInfo.countCategories(); i < max; i++) { - intent.addCategory(intentInfo.getCategory(i)); - } - if (numHosts == 1) { - host = intentInfo.getHosts()[0]; - } - if (numSchemes == 1) { - data = new Uri.Builder() - .scheme(intentInfo.getDataScheme(0)) - .authority(host) - .build(); - } - if (numTypes == 1) { - dataType = intentInfo.getDataType(0); - } - intent.setDataAndType(data, dataType); - if (numActions == 1) { - intent.setAction(intentInfo.getAction(0)); - } - owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent); - } else if (parser.getName().equals("package")) { - final TypedArray sa = res.obtainAttributes(parser, - com.android.internal.R.styleable.AndroidManifestQueriesPackage); - final String packageName = - sa.getString(R.styleable.AndroidManifestQueriesPackage_name); - if (TextUtils.isEmpty(packageName)) { - outError[0] = "Package name is missing from package tag."; - return false; - } - owner.mQueriesPackages = - ArrayUtils.add(owner.mQueriesPackages, packageName.intern()); - } - } - return true; - } - /** * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI */ @@ -5846,7 +5800,7 @@ public class PackageParser { return null; } - private static final String ANDROID_RESOURCES + public static final String ANDROID_RESOURCES = "http://schemas.android.com/apk/res/android"; private boolean parseIntent(Resources res, XmlResourceParser parser, boolean allowGlobs, @@ -6541,7 +6495,10 @@ public class PackageParser { /** * Representation of a full package parsed from APK files on disk. A package * consists of a single base APK, and zero or more split APKs. + * + * @deprecated use an {@link AndroidPackage} */ + @Deprecated public final static class Package implements Parcelable { @UnsupportedAppUsage @@ -6649,9 +6606,6 @@ public class PackageParser { // The major version code declared for this package. public int mVersionCodeMajor; - // Whether the package declares that it should be queryable by all normal apps on device. - public boolean mForceQueryable; - // Return long containing mVersionCode and mVersionCodeMajor. public long getLongVersionCode() { return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode); @@ -6757,9 +6711,6 @@ public class PackageParser { /** Whether or not the package is a stub and must be replaced by the full version. */ public boolean isStub; - public ArrayList<String> mQueriesPackages; - public ArrayList<Intent> mQueriesIntents; - @UnsupportedAppUsage public Package(String packageName) { this.packageName = packageName; @@ -7263,9 +7214,6 @@ public class PackageParser { use32bitAbi = (dest.readInt() == 1); restrictUpdateHash = dest.createByteArray(); visibleToInstantApps = dest.readInt() == 1; - mForceQueryable = dest.readBoolean(); - mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR); - mQueriesPackages = dest.createStringArrayList(); } private static void internStringArrayList(List<String> list) { @@ -7281,7 +7229,7 @@ public class PackageParser { * Sets the package owner and the the {@code applicationInfo} for every component * owner by this package. */ - private void fixupOwner(List<? extends Component<?>> list) { + public void fixupOwner(List<? extends Component<?>> list) { if (list != null) { for (Component<?> c : list) { c.owner = this; @@ -7391,12 +7339,8 @@ public class PackageParser { dest.writeInt(use32bitAbi ? 1 : 0); dest.writeByteArray(restrictUpdateHash); dest.writeInt(visibleToInstantApps ? 1 : 0); - dest.writeBoolean(mForceQueryable); - dest.writeTypedList(mQueriesIntents); - dest.writeList(mQueriesPackages); } - /** * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. */ @@ -7468,6 +7412,10 @@ public class PackageParser { }; } + /** + * @deprecated use a {@link ComponentParseUtils.ParsedComponent} + */ + @Deprecated public static abstract class Component<II extends IntentInfo> { @UnsupportedAppUsage public final ArrayList<II> intents; @@ -7648,6 +7596,10 @@ public class PackageParser { } } + /** + * @deprecated use {@link ComponentParseUtils.ParsedPermission} + */ + @Deprecated public final static class Permission extends Component<IntentInfo> implements Parcelable { @UnsupportedAppUsage public final PermissionInfo info; @@ -7722,6 +7674,10 @@ public class PackageParser { }; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedPermissionGroup} + */ + @Deprecated public final static class PermissionGroup extends Component<IntentInfo> implements Parcelable { @UnsupportedAppUsage public final PermissionGroupInfo info; @@ -7821,7 +7777,12 @@ public class PackageParser { return false; } + /** + * @deprecated use {@link PackageInfoUtils#generateApplicationInfo( + * AndroidPackage, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static ApplicationInfo generateApplicationInfo(Package p, int flags, PackageUserState state) { return generateApplicationInfo(p, flags, state, UserHandle.getCallingUserId()); @@ -7878,7 +7839,12 @@ public class PackageParser { ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes; } + /** + * @deprecated use {@link PackageInfoUtils#generateApplicationInfo( + * AndroidPackage, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static ApplicationInfo generateApplicationInfo(Package p, int flags, PackageUserState state, int userId) { if (p == null) return null; @@ -7918,6 +7884,11 @@ public class PackageParser { return ai; } + /** + * @deprecated use {@link PackageInfoUtils#generateApplicationInfo( + * AndroidPackage, int, PackageUserState, int)} + */ + @Deprecated public static ApplicationInfo generateApplicationInfo(ApplicationInfo ai, int flags, PackageUserState state, int userId) { if (ai == null) return null; @@ -7937,7 +7908,12 @@ public class PackageParser { return ai; } + /** + * @deprecated use {@link PackageInfoUtils#generatePermissionInfo( + * ComponentParseUtils.ParsedPermission, int)} + */ @UnsupportedAppUsage + @Deprecated public static final PermissionInfo generatePermissionInfo( Permission p, int flags) { if (p == null) return null; @@ -7949,7 +7925,12 @@ public class PackageParser { return pi; } + /** + * @deprecated use {@link PackageInfoUtils#generatePermissionGroupInfo( + * ComponentParseUtils.ParsedPermissionGroup, int)} + */ @UnsupportedAppUsage + @Deprecated public static final PermissionGroupInfo generatePermissionGroupInfo( PermissionGroup pg, int flags) { if (pg == null) return null; @@ -7961,6 +7942,10 @@ public class PackageParser { return pgi; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedActivity} + */ + @Deprecated public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable { @UnsupportedAppUsage public final ActivityInfo info; @@ -8076,7 +8061,12 @@ public class PackageParser { }; } + /** + * @deprecated use {@link PackageInfoUtils#generateActivityInfo( + * AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static final ActivityInfo generateActivityInfo(Activity a, int flags, PackageUserState state, int userId) { if (a == null) return null; @@ -8094,6 +8084,11 @@ public class PackageParser { return ai; } + /** + * @deprecated use {@link PackageInfoUtils#generateActivityInfo( + * AndroidPackage, ComponentParseUtils.ParsedActivity, int, PackageUserState, int)} + */ + @Deprecated public static final ActivityInfo generateActivityInfo(ActivityInfo ai, int flags, PackageUserState state, int userId) { if (ai == null) return null; @@ -8107,6 +8102,10 @@ public class PackageParser { return ai; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedService} + */ + @Deprecated public final static class Service extends Component<ServiceIntentInfo> implements Parcelable { @UnsupportedAppUsage public final ServiceInfo info; @@ -8168,7 +8167,12 @@ public class PackageParser { }; } + /** + * @deprecated use {@link PackageInfoUtils#generateServiceInfo( + * AndroidPackage, ComponentParseUtils.ParsedService, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static final ServiceInfo generateServiceInfo(Service s, int flags, PackageUserState state, int userId) { if (s == null) return null; @@ -8186,6 +8190,10 @@ public class PackageParser { return si; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedProvider} + */ + @Deprecated public final static class Provider extends Component<ProviderIntentInfo> implements Parcelable { @UnsupportedAppUsage public final ProviderInfo info; @@ -8266,7 +8274,12 @@ public class PackageParser { }; } + /** + * @deprecated use {@link PackageInfoUtils#generateProviderInfo( + * AndroidPackage, ComponentParseUtils.ParsedProvider, int, PackageUserState, int)} + */ @UnsupportedAppUsage + @Deprecated public static final ProviderInfo generateProviderInfo(Provider p, int flags, PackageUserState state, int userId) { if (p == null) return null; @@ -8289,6 +8302,10 @@ public class PackageParser { return pi; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedInstrumentation} + */ + @Deprecated public final static class Instrumentation extends Component<IntentInfo> implements Parcelable { @UnsupportedAppUsage @@ -8349,7 +8366,12 @@ public class PackageParser { }; } + /** + * @deprecated use {@link PackageInfoUtils#generateInstrumentationInfo( + * ComponentParseUtils.ParsedInstrumentation, int)} + */ @UnsupportedAppUsage + @Deprecated public static final InstrumentationInfo generateInstrumentationInfo( Instrumentation i, int flags) { if (i == null) return null; @@ -8361,6 +8383,10 @@ public class PackageParser { return ii; } + /** + * @deprecated use {@link ComponentParseUtils.ParsedIntentInfo} + */ + @Deprecated public static abstract class IntentInfo extends IntentFilter { @UnsupportedAppUsage public boolean hasDefault; @@ -8404,8 +8430,10 @@ public class PackageParser { } } - public static final class QueriesIntentInfo extends IntentInfo {} - + /** + * @deprecated use {@link ComponentParseUtils.ParsedActivityIntentInfo} + */ + @Deprecated public final static class ActivityIntentInfo extends IntentInfo { @UnsupportedAppUsage public Activity activity; @@ -8429,6 +8457,10 @@ public class PackageParser { } } + /** + * @deprecated use {@link ComponentParseUtils.ParsedServiceIntentInfo} + */ + @Deprecated public final static class ServiceIntentInfo extends IntentInfo { @UnsupportedAppUsage public Service service; @@ -8452,6 +8484,10 @@ public class PackageParser { } } + /** + * @deprecated use {@link ComponentParseUtils.ParsedProviderIntentInfo} + */ + @Deprecated public static final class ProviderIntentInfo extends IntentInfo { @UnsupportedAppUsage public Provider provider; diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 249b6919fc28..b271ccdad041 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -28,6 +28,7 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPON import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import android.annotation.UnsupportedAppUsage; +import android.content.pm.parsing.ComponentParseUtils; import android.os.BaseBundle; import android.os.Debug; import android.os.PersistableBundle; @@ -127,6 +128,18 @@ public class PackageUserState { && (!this.hidden || matchUninstalled)); } + public boolean isMatch(ComponentInfo componentInfo, int flags) { + return isMatch(componentInfo.applicationInfo.isSystemApp(), + componentInfo.applicationInfo.enabled, componentInfo.enabled, + componentInfo.directBootAware, componentInfo.name, flags); + } + + public boolean isMatch(boolean isSystem, boolean isPackageEnabled, + ComponentParseUtils.ParsedComponent component, int flags) { + return isMatch(isSystem, isPackageEnabled, component.isEnabled(), + component.isDirectBootAware(), component.getName(), flags); + } + /** * Test if the given component is considered installed, enabled and a match * for the given flags. @@ -135,28 +148,33 @@ public class PackageUserState { * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}. * </p> + * */ - public boolean isMatch(ComponentInfo componentInfo, int flags) { - final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp(); + public boolean isMatch(boolean isSystem, boolean isPackageEnabled, boolean isComponentEnabled, + boolean isComponentDirectBootAware, String componentName, int flags) { final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0; - if (!isAvailable(flags) - && !(isSystemApp && matchUninstalled)) return reportIfDebug(false, flags); - if (!isEnabled(componentInfo, flags)) return reportIfDebug(false, flags); + if (!isAvailable(flags) && !(isSystem && matchUninstalled)) { + return reportIfDebug(false, flags); + } + + if (!isEnabled(isPackageEnabled, isComponentEnabled, componentName, flags)) { + return reportIfDebug(false, flags); + } if ((flags & MATCH_SYSTEM_ONLY) != 0) { - if (!isSystemApp) { + if (!isSystem) { return reportIfDebug(false, flags); } } final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0) - && !componentInfo.directBootAware; + && !isComponentDirectBootAware; final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0) - && componentInfo.directBootAware; + && isComponentDirectBootAware; return reportIfDebug(matchesUnaware || matchesAware, flags); } - private boolean reportIfDebug(boolean result, int flags) { + public boolean reportIfDebug(boolean result, int flags) { if (DEBUG && !result) { Slog.i(LOG_TAG, "No match!; flags: " + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " " @@ -165,10 +183,22 @@ public class PackageUserState { return result; } + public boolean isEnabled(ComponentInfo componentInfo, int flags) { + return isEnabled(componentInfo.applicationInfo.enabled, componentInfo.enabled, + componentInfo.name, flags); + } + + public boolean isEnabled(boolean isPackageEnabled, + ComponentParseUtils.ParsedComponent parsedComponent, int flags) { + return isEnabled(isPackageEnabled, parsedComponent.isEnabled(), parsedComponent.getName(), + flags); + } + /** * Test if the given component is considered enabled. */ - public boolean isEnabled(ComponentInfo componentInfo, int flags) { + public boolean isEnabled(boolean isPackageEnabled, boolean isComponentEnabled, + String componentName, int flags) { if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { return true; } @@ -183,24 +213,26 @@ public class PackageUserState { if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) { return false; } + // fallthrough case COMPONENT_ENABLED_STATE_DEFAULT: - if (!componentInfo.applicationInfo.enabled) { + if (!isPackageEnabled) { return false; } + // fallthrough case COMPONENT_ENABLED_STATE_ENABLED: break; } // Check if component has explicit state before falling through to // the manifest default - if (ArrayUtils.contains(this.enabledComponents, componentInfo.name)) { + if (ArrayUtils.contains(this.enabledComponents, componentName)) { return true; } - if (ArrayUtils.contains(this.disabledComponents, componentInfo.name)) { + if (ArrayUtils.contains(this.disabledComponents, componentName)) { return false; } - return componentInfo.enabled; + return isComponentEnabled; } @Override diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index 3488cc30892c..2863b268e795 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.parsing.AndroidPackage; import android.os.Parcel; import android.os.Parcelable; @@ -38,20 +39,24 @@ import java.util.List; public final class SharedLibraryInfo implements Parcelable { /** @hide */ - public static SharedLibraryInfo createForStatic(PackageParser.Package pkg) { - return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(), - pkg.staticSharedLibName, - pkg.staticSharedLibVersion, + public static SharedLibraryInfo createForStatic(AndroidPackage pkg) { + return new SharedLibraryInfo(null, pkg.getPackageName(), + pkg.makeListAllCodePaths(), + pkg.getStaticSharedLibName(), + pkg.getStaticSharedLibVersion(), TYPE_STATIC, - new VersionedPackage(pkg.manifestPackageName, pkg.getLongVersionCode()), + new VersionedPackage(pkg.getManifestPackageName(), + pkg.getLongVersionCode()), null, null); } /** @hide */ - public static SharedLibraryInfo createForDynamic(PackageParser.Package pkg, String name) { - return new SharedLibraryInfo(null, pkg.packageName, pkg.getAllCodePaths(), name, + public static SharedLibraryInfo createForDynamic(AndroidPackage pkg, String name) { + return new SharedLibraryInfo(null, pkg.getPackageName(), + pkg.makeListAllCodePaths(), name, (long) VERSION_UNDEFINED, - TYPE_DYNAMIC, new VersionedPackage(pkg.packageName, pkg.getLongVersionCode()), + TYPE_DYNAMIC, new VersionedPackage(pkg.getPackageName(), + pkg.getLongVersionCode()), null, null); } diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java index 5d10b8826b00..4cd201fbe538 100644 --- a/core/java/android/content/pm/dex/DexMetadataHelper.java +++ b/core/java/android/content/pm/dex/DexMetadataHelper.java @@ -22,6 +22,7 @@ import static android.content.pm.PackageParser.APK_FILE_EXTENSION; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.parsing.AndroidPackage; import android.util.ArrayMap; import android.util.jar.StrictJarFile; @@ -86,8 +87,8 @@ public class DexMetadataHelper { * * NOTE: involves I/O checks. */ - public static Map<String, String> getPackageDexMetadata(PackageParser.Package pkg) { - return buildPackageApkToDexMetadataMap(pkg.getAllCodePaths()); + public static Map<String, String> getPackageDexMetadata(AndroidPackage pkg) { + return buildPackageApkToDexMetadataMap(pkg.makeListAllCodePaths()); } /** @@ -160,7 +161,7 @@ public class DexMetadataHelper { * * @throws PackageParserException in case of errors. */ - public static void validatePackageDexMetadata(PackageParser.Package pkg) + public static void validatePackageDexMetadata(AndroidPackage pkg) throws PackageParserException { Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values(); for (String dexMetadata : apkToDexMetadataList) { diff --git a/core/java/android/content/pm/parsing/AndroidPackage.aidl b/core/java/android/content/pm/parsing/AndroidPackage.aidl new file mode 100644 index 000000000000..ab3cf7cb8c65 --- /dev/null +++ b/core/java/android/content/pm/parsing/AndroidPackage.aidl @@ -0,0 +1,21 @@ +/* +** +** Copyright 2019, 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.parsing; + +/* @hide */ +parcelable AndroidPackage; diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java new file mode 100644 index 000000000000..bef984df4c10 --- /dev/null +++ b/core/java/android/content/pm/parsing/AndroidPackage.java @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2019 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.parsing; + +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageParser; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArraySet; +import android.util.SparseArray; + +import java.security.PublicKey; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * The last state of a package during parsing/install before it is available in + * {@link com.android.server.pm.PackageManagerService#mPackages}. + * + * It is the responsibility of the caller to understand what data is available at what step of the + * parsing or install process. + * + * TODO(b/135203078): Nullability annotations + * TODO(b/135203078): Remove get/setAppInfo differences + * + * @hide + */ +public interface AndroidPackage extends Parcelable { + + /** + * This will eventually be removed. Avoid calling this at all costs. + */ + @Deprecated + AndroidPackageWrite mutate(); + + boolean canHaveOatDir(); + + boolean cantSaveState(); + + List<String> getAdoptPermissions(); + + List<String> getAllCodePaths(); + + List<String> getAllCodePathsExcludingResourceOnly(); + + String getAppComponentFactory(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getClassLoaderName()} + */ + @Deprecated + String getAppInfoClassLoaderName(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getCodePath()} + */ + @Deprecated + String getAppInfoCodePath(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getName()} + */ + @Deprecated + String getAppInfoName(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getPackageName()} + */ + @Deprecated + String getAppInfoPackageName(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getProcessName()} + */ + @Deprecated + String getAppInfoProcessName(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getCodePath()} + */ + @Deprecated + String getAppInfoResourcePath(); + + Bundle getAppMetaData(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #getVolumeUuid()} + */ + @Deprecated + String getApplicationInfoVolumeUuid(); + + String getBackupAgentName(); + + int getBanner(); + + String getBaseCodePath(); + + int getBaseRevisionCode(); + + int getCategory(); + + String getClassLoaderName(); + + String getClassName(); + + String getCodePath(); + + int getCompatibleWidthLimitDp(); + + int getCompileSdkVersion(); + + String getCompileSdkVersionCodeName(); + + @Nullable + List<ConfigurationInfo> getConfigPreferences(); + + String getCpuAbiOverride(); + + String getCredentialProtectedDataDir(); + + String getDataDir(); + + int getDescriptionRes(); + + String getDeviceProtectedDataDir(); + + List<FeatureGroupInfo> getFeatureGroups(); + + int getFlags(); + + int getFullBackupContent(); + + int getHiddenApiEnforcementPolicy(); + + int getIcon(); + + int getIconRes(); + + List<String> getImplicitPermissions(); + + int getInstallLocation(); + + Map<String, ArraySet<PublicKey>> getKeySetMapping(); + + int getLabelRes(); + + int getLargestWidthLimitDp(); + + long[] getLastPackageUsageTimeInMills(); + + long getLatestForegroundPackageUseTimeInMills(); + + long getLatestPackageUseTimeInMills(); + + List<String> getLibraryNames(); + + int getLogo(); + + long getLongVersionCode(); + + String getManageSpaceActivityName(); + + String getManifestPackageName(); + + float getMaxAspectRatio(); + + Bundle getMetaData(); // TODO(b/135203078): Make all the Bundles immutable + + float getMinAspectRatio(); + + int getMinSdkVersion(); + + String getName(); + + String getNativeLibraryDir(); + + String getNativeLibraryRootDir(); + + int getNetworkSecurityConfigRes(); + + CharSequence getNonLocalizedLabel(); + + @Nullable + List<String> getOriginalPackages(); + + String getOverlayCategory(); + + int getOverlayPriority(); + + String getOverlayTarget(); + + String getOverlayTargetName(); + + // TODO(b/135203078): Does this and getAppInfoPackageName have to be separate methods? + // The refactor makes them the same value with no known consequences, so should be redundant. + String getPackageName(); + + @Nullable + List<ParsedActivity> getActivities(); + + @Nullable + List<ParsedInstrumentation> getInstrumentations(); + + @Nullable + List<ParsedPermissionGroup> getPermissionGroups(); + + @Nullable + List<ParsedPermission> getPermissions(); + + @Nullable + List<ParsedProvider> getProviders(); + + @Nullable + List<ParsedActivity> getReceivers(); + + @Nullable + List<ParsedService> getServices(); + + String getPermission(); + + @Nullable + List<ParsedActivityIntentInfo> getPreferredActivityFilters(); + + int getPreferredOrder(); + + String getPrimaryCpuAbi(); + + int getPrivateFlags(); + + String getProcessName(); + + @Nullable + List<String> getProtectedBroadcasts(); + + String getPublicSourceDir(); + + List<Intent> getQueriesIntents(); + + List<String> getQueriesPackages(); + + String getRealPackage(); + + // TODO(b/135203078): Rename to getRequiredFeatures? Somewhat ambigious whether "Req" is + // required or requested. + @Nullable + List<FeatureInfo> getReqFeatures(); + + List<String> getRequestedPermissions(); + + String getRequiredAccountType(); + + int getRequiresSmallestWidthDp(); + + byte[] getRestrictUpdateHash(); + + String getRestrictedAccountType(); + + int getRoundIconRes(); + + String getScanPublicSourceDir(); + + String getScanSourceDir(); + + String getSeInfo(); + + String getSeInfoUser(); + + String getSecondaryCpuAbi(); + + String getSecondaryNativeLibraryDir(); + + String getSharedUserId(); + + int getSharedUserLabel(); + + PackageParser.SigningDetails getSigningDetails(); + + String[] getSplitClassLoaderNames(); + + @Nullable + String[] getSplitCodePaths(); + + @Nullable + SparseArray<int[]> getSplitDependencies(); + + int[] getSplitFlags(); + + String[] getSplitNames(); + + String[] getSplitPublicSourceDirs(); + + int[] getSplitRevisionCodes(); + + String getStaticSharedLibName(); + + long getStaticSharedLibVersion(); + + // TODO(b/135203078): Return String directly + UUID getStorageUuid(); + + int getTargetSandboxVersion(); + + int getTargetSdkVersion(); + + String getTaskAffinity(); + + int getTheme(); + + int getUiOptions(); + + int getUid(); + + Set<String> getUpgradeKeySets(); + + @Nullable + List<String> getUsesLibraries(); + + @Nullable + String[] getUsesLibraryFiles(); + + List<SharedLibraryInfo> getUsesLibraryInfos(); + + @Nullable + List<String> getUsesOptionalLibraries(); + + @Nullable + List<String> getUsesStaticLibraries(); + + @Nullable + String[][] getUsesStaticLibrariesCertDigests(); + + @Nullable + long[] getUsesStaticLibrariesVersions(); + + int getVersionCode(); + + int getVersionCodeMajor(); + + String getVersionName(); + + String getVolumeUuid(); + + String getZygotePreloadName(); + + boolean hasComponentClassName(String className); + + // App Info + + boolean hasRequestedLegacyExternalStorage(); + + boolean isBaseHardwareAccelerated(); + + boolean isCoreApp(); + + boolean isDefaultToDeviceProtectedStorage(); + + boolean isDirectBootAware(); + + boolean isEmbeddedDexUsed(); + + boolean isEnabled(); + + boolean isEncryptionAware(); + + boolean isExternal(); + + boolean isForceQueryable(); + + boolean isForwardLocked(); + + boolean isHiddenUntilInstalled(); + + boolean isInstantApp(); + + boolean isInternal(); + + boolean isLibrary(); + + // TODO(b/135203078): Should probably be in a utility class + boolean isMatch(int flags); + + boolean isNativeLibraryRootRequiresIsa(); + + boolean isOem(); + + boolean isOverlayIsStatic(); + + boolean isPrivileged(); + + boolean isProduct(); + + boolean isProfileableByShell(); + + boolean isRequiredForAllUsers(); + + boolean isStaticSharedLibrary(); + + boolean isStub(); + + boolean isSystem(); // TODO(b/135203078): Collapse with isSystemApp, should be exactly the same. + + boolean isSystemApp(); + + boolean isSystemExt(); + + boolean isUpdatedSystemApp(); + + boolean isUse32BitAbi(); + + boolean isVendor(); + + boolean isVisibleToInstantApps(); + + List<String> makeListAllCodePaths(); // TODO(b/135203078): Collapse with getAllCodePaths + + boolean requestsIsolatedSplitLoading(); + + ApplicationInfo toAppInfo(); + + Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() { + @Override + public PackageImpl createFromParcel(Parcel source) { + return new PackageImpl(source); + } + + @Override + public PackageImpl[] newArray(int size) { + return new PackageImpl[size]; + } + }; +} diff --git a/core/java/android/content/pm/parsing/AndroidPackageWrite.java b/core/java/android/content/pm/parsing/AndroidPackageWrite.java new file mode 100644 index 000000000000..b7595d2dd710 --- /dev/null +++ b/core/java/android/content/pm/parsing/AndroidPackageWrite.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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.parsing; + +import android.annotation.Nullable; +import android.content.pm.PackageParser; +import android.content.pm.SharedLibraryInfo; + +import java.util.List; + +/** + * Contains remaining mutable fields after package parsing has completed. + * + * Most are state that can probably be tracked outside of the AndroidPackage object. New methods + * should never be added to this interface. + * + * TODO(b/135203078): Remove entirely + * + * @deprecated the eventual goal is that the object returned from parsing represents exactly what + * was parsed from the APK, and so further mutation should be disallowed, + * with any state being stored in another class + * + * @hide + */ +@Deprecated +public interface AndroidPackageWrite extends AndroidPackage { + + AndroidPackageWrite setUsesLibraryFiles(@Nullable String[] usesLibraryFiles); + + // TODO(b/135203078): Remove or use a non-system wide representation of the shared libraries; + // this doesn't represent what was parsed from the APK + AndroidPackageWrite setUsesLibraryInfos(@Nullable List<SharedLibraryInfo> usesLibraryInfos); + + AndroidPackageWrite setHiddenUntilInstalled(boolean hidden); + + AndroidPackageWrite setUpdatedSystemApp(boolean updatedSystemApp); + + AndroidPackageWrite setLastPackageUsageTimeInMills(int reason, long time); + + AndroidPackageWrite setPrimaryCpuAbi(String primaryCpuAbi); + + AndroidPackageWrite setSeInfo(String seInfo); + + AndroidPackageWrite setSigningDetails(PackageParser.SigningDetails signingDetails); +} diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java new file mode 100644 index 000000000000..ac2e373f000d --- /dev/null +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2019 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.parsing; + +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; + +import android.annotation.UnsupportedAppUsage; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.VerifierInfo; +import android.content.res.ApkAssets; +import android.content.res.XmlResourceParser; +import android.os.Trace; +import android.util.ArrayMap; +import android.util.AttributeSet; +import android.util.Pair; +import android.util.Slog; + +import com.android.internal.R; +import com.android.internal.util.ArrayUtils; + +import libcore.io.IoUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.IOException; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** @hide */ +public class ApkLiteParseUtils { + + private static final String TAG = ApkParseUtils.TAG; + + // TODO(b/135203078): Consolidate constants + private static final int DEFAULT_MIN_SDK_VERSION = 1; + private static final int DEFAULT_TARGET_SDK_VERSION = 0; + + private static final int PARSE_DEFAULT_INSTALL_LOCATION = + PackageInfo.INSTALL_LOCATION_UNSPECIFIED; + + /** + * Parse only lightweight details about the package at the given location. + * Automatically detects if the package is a monolithic style (single APK + * file) or cluster style (directory of APKs). + * <p> + * This performs sanity checking on cluster style packages, such as + * requiring identical package name and version codes, a single base APK, + * and unique split names. + * + * @see PackageParser#parsePackage(File, int) + */ + @UnsupportedAppUsage + public static PackageParser.PackageLite parsePackageLite(File packageFile, int flags) + throws PackageParser.PackageParserException { + if (packageFile.isDirectory()) { + return parseClusterPackageLite(packageFile, flags); + } else { + return parseMonolithicPackageLite(packageFile, flags); + } + } + + public static PackageParser.PackageLite parseMonolithicPackageLite(File packageFile, int flags) + throws PackageParser.PackageParserException { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); + final PackageParser.ApkLite baseApk = parseApkLite(packageFile, flags); + final String packagePath = packageFile.getAbsolutePath(); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + return new PackageParser.PackageLite(packagePath, baseApk, null, null, null, null, + null, null); + } + + public static PackageParser.PackageLite parseClusterPackageLite(File packageDir, int flags) + throws PackageParser.PackageParserException { + final File[] files = packageDir.listFiles(); + if (ArrayUtils.isEmpty(files)) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_NOT_APK, "No packages found in split"); + } + + String packageName = null; + int versionCode = 0; + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite"); + final ArrayMap<String, PackageParser.ApkLite> apks = new ArrayMap<>(); + for (File file : files) { + if (PackageParser.isApkFile(file)) { + final PackageParser.ApkLite lite = parseApkLite(file, flags); + + // Assert that all package names and version codes are + // consistent with the first one we encounter. + if (packageName == null) { + packageName = lite.packageName; + versionCode = lite.versionCode; + } else { + if (!packageName.equals(lite.packageName)) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Inconsistent package " + lite.packageName + " in " + file + + "; expected " + packageName); + } + if (versionCode != lite.versionCode) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Inconsistent version " + lite.versionCode + " in " + file + + "; expected " + versionCode); + } + } + + // Assert that each split is defined only oncuses-static-libe + if (apks.put(lite.splitName, lite) != null) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Split name " + lite.splitName + + " defined more than once; most recent was " + file); + } + } + } + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + + final PackageParser.ApkLite baseApk = apks.remove(null); + if (baseApk == null) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Missing base APK in " + packageDir); + } + + // Always apply deterministic ordering based on splitName + final int size = apks.size(); + + String[] splitNames = null; + boolean[] isFeatureSplits = null; + String[] usesSplitNames = null; + String[] configForSplits = null; + String[] splitCodePaths = null; + int[] splitRevisionCodes = null; + if (size > 0) { + splitNames = new String[size]; + isFeatureSplits = new boolean[size]; + usesSplitNames = new String[size]; + configForSplits = new String[size]; + splitCodePaths = new String[size]; + splitRevisionCodes = new int[size]; + + splitNames = apks.keySet().toArray(splitNames); + Arrays.sort(splitNames, PackageParser.sSplitNameComparator); + + for (int i = 0; i < size; i++) { + final PackageParser.ApkLite apk = apks.get(splitNames[i]); + usesSplitNames[i] = apk.usesSplitName; + isFeatureSplits[i] = apk.isFeatureSplit; + configForSplits[i] = apk.configForSplit; + splitCodePaths[i] = apk.codePath; + splitRevisionCodes[i] = apk.revisionCode; + } + } + + final String codePath = packageDir.getAbsolutePath(); + return new PackageParser.PackageLite(codePath, baseApk, splitNames, isFeatureSplits, + usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes); + } + + /** + * Utility method that retrieves lightweight details about a single APK + * file, including package name, split name, and install location. + * + * @param apkFile path to a single APK + * @param flags optional parse flags, such as + * {@link PackageParser#PARSE_COLLECT_CERTIFICATES} + */ + public static PackageParser.ApkLite parseApkLite(File apkFile, int flags) + throws PackageParser.PackageParserException { + return parseApkLiteInner(apkFile, null, null, flags); + } + + /** + * Utility method that retrieves lightweight details about a single APK + * file, including package name, split name, and install location. + * + * @param fd already open file descriptor of an apk file + * @param debugPathName arbitrary text name for this file, for debug output + * @param flags optional parse flags, such as + * {@link PackageParser#PARSE_COLLECT_CERTIFICATES} + */ + public static PackageParser.ApkLite parseApkLite(FileDescriptor fd, String debugPathName, + int flags) throws PackageParser.PackageParserException { + return parseApkLiteInner(null, fd, debugPathName, flags); + } + + private static PackageParser.ApkLite parseApkLiteInner(File apkFile, FileDescriptor fd, + String debugPathName, int flags) throws PackageParser.PackageParserException { + final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath(); + + XmlResourceParser parser = null; + ApkAssets apkAssets = null; + try { + try { + apkAssets = fd != null + ? ApkAssets.loadFromFd(fd, debugPathName, false, false) + : ApkAssets.loadFromPath(apkPath); + } catch (IOException e) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_NOT_APK, + "Failed to parse " + apkPath, e); + } + + parser = apkAssets.openXml(PackageParser.ANDROID_MANIFEST_FILENAME); + + final PackageParser.SigningDetails signingDetails; + if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) { + final boolean skipVerify = (flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0; + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); + try { + signingDetails = + ApkParseUtils.collectCertificates(apkFile.getAbsolutePath(), skipVerify, + false, PackageParser.SigningDetails.UNKNOWN); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } else { + signingDetails = PackageParser.SigningDetails.UNKNOWN; + } + + final AttributeSet attrs = parser; + return parseApkLite(apkPath, parser, attrs, signingDetails); + + } catch (XmlPullParserException | IOException | RuntimeException e) { + Slog.w(TAG, "Failed to parse " + apkPath, e); + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to parse " + apkPath, e); + } finally { + IoUtils.closeQuietly(parser); + if (apkAssets != null) { + try { + apkAssets.close(); + } catch (Throwable ignored) { + } + } + // TODO(b/72056911): Implement AutoCloseable on ApkAssets. + } + } + + private static PackageParser.ApkLite parseApkLite( + String codePath, XmlPullParser parser, AttributeSet attrs, + PackageParser.SigningDetails signingDetails) + throws IOException, XmlPullParserException, PackageParser.PackageParserException { + final Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames( + parser, attrs); + + int installLocation = PARSE_DEFAULT_INSTALL_LOCATION; + int versionCode = 0; + int versionCodeMajor = 0; + int targetSdkVersion = DEFAULT_TARGET_SDK_VERSION; + int minSdkVersion = DEFAULT_MIN_SDK_VERSION; + int revisionCode = 0; + boolean coreApp = false; + boolean debuggable = false; + boolean multiArch = false; + boolean use32bitAbi = false; + boolean extractNativeLibs = true; + boolean isolatedSplits = false; + boolean isFeatureSplit = false; + boolean isSplitRequired = false; + boolean useEmbeddedDex = false; + String configForSplit = null; + String usesSplitName = null; + + for (int i = 0; i < attrs.getAttributeCount(); i++) { + final String attr = attrs.getAttributeName(i); + switch (attr) { + case "installLocation": + installLocation = attrs.getAttributeIntValue(i, + PARSE_DEFAULT_INSTALL_LOCATION); + break; + case "versionCode": + versionCode = attrs.getAttributeIntValue(i, 0); + break; + case "versionCodeMajor": + versionCodeMajor = attrs.getAttributeIntValue(i, 0); + break; + case "revisionCode": + revisionCode = attrs.getAttributeIntValue(i, 0); + break; + case "coreApp": + coreApp = attrs.getAttributeBooleanValue(i, false); + break; + case "isolatedSplits": + isolatedSplits = attrs.getAttributeBooleanValue(i, false); + break; + case "configForSplit": + configForSplit = attrs.getAttributeValue(i); + break; + case "isFeatureSplit": + isFeatureSplit = attrs.getAttributeBooleanValue(i, false); + break; + case "isSplitRequired": + isSplitRequired = attrs.getAttributeBooleanValue(i, false); + break; + } + } + + // Only search the tree when the tag is the direct child of <manifest> tag + int type; + final int searchDepth = parser.getDepth() + 1; + + final List<VerifierInfo> verifiers = new ArrayList<>(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getDepth() != searchDepth) { + continue; + } + + if (PackageParser.TAG_PACKAGE_VERIFIER.equals(parser.getName())) { + final VerifierInfo verifier = parseVerifier(attrs); + if (verifier != null) { + verifiers.add(verifier); + } + } else if (PackageParser.TAG_APPLICATION.equals(parser.getName())) { + for (int i = 0; i < attrs.getAttributeCount(); ++i) { + final String attr = attrs.getAttributeName(i); + switch (attr) { + case "debuggable": + debuggable = attrs.getAttributeBooleanValue(i, false); + break; + case "multiArch": + multiArch = attrs.getAttributeBooleanValue(i, false); + break; + case "use32bitAbi": + use32bitAbi = attrs.getAttributeBooleanValue(i, false); + break; + case "extractNativeLibs": + extractNativeLibs = attrs.getAttributeBooleanValue(i, true); + break; + case "useEmbeddedDex": + useEmbeddedDex = attrs.getAttributeBooleanValue(i, false); + break; + } + } + } else if (PackageParser.TAG_USES_SPLIT.equals(parser.getName())) { + if (usesSplitName != null) { + Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others."); + continue; + } + + usesSplitName = attrs.getAttributeValue(PackageParser.ANDROID_RESOURCES, "name"); + if (usesSplitName == null) { + throw new PackageParser.PackageParserException( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<uses-split> tag requires 'android:name' attribute"); + } + } else if (PackageParser.TAG_USES_SDK.equals(parser.getName())) { + for (int i = 0; i < attrs.getAttributeCount(); ++i) { + final String attr = attrs.getAttributeName(i); + if ("targetSdkVersion".equals(attr)) { + targetSdkVersion = attrs.getAttributeIntValue(i, + DEFAULT_TARGET_SDK_VERSION); + } + if ("minSdkVersion".equals(attr)) { + minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION); + } + } + } + } + + return new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second, + isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode, + versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails, + coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs, + isolatedSplits, minSdkVersion, targetSdkVersion); + } + + public static VerifierInfo parseVerifier(AttributeSet attrs) { + String packageName = null; + String encodedPublicKey = null; + + final int attrCount = attrs.getAttributeCount(); + for (int i = 0; i < attrCount; i++) { + final int attrResId = attrs.getAttributeNameResource(i); + switch (attrResId) { + case R.attr.name: + packageName = attrs.getAttributeValue(i); + break; + + case R.attr.publicKey: + encodedPublicKey = attrs.getAttributeValue(i); + break; + } + } + + if (packageName == null || packageName.length() == 0) { + Slog.i(TAG, "verifier package name was null; skipping"); + return null; + } + + final PublicKey publicKey = PackageParser.parsePublicKey(encodedPublicKey); + if (publicKey == null) { + Slog.i(TAG, "Unable to parse verifier public key for " + packageName); + return null; + } + + return new VerifierInfo(packageName, publicKey); + } +} diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java new file mode 100644 index 000000000000..0f35b27de7e2 --- /dev/null +++ b/core/java/android/content/pm/parsing/ApkParseUtils.java @@ -0,0 +1,3197 @@ +/* + * Copyright (C) 2019 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.parsing; + +import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.content.pm.PackageManager.FEATURE_WATCH; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; +import static android.os.Build.VERSION_CODES.O; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityTaskManager; +import android.app.ActivityThread; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.PackageParser.SigningDetails; +import android.content.pm.Signature; +import android.content.pm.permission.SplitPermissionInfoParcelable; +import android.content.pm.split.DefaultSplitAssetLoader; +import android.content.pm.split.SplitAssetDependencyLoader; +import android.content.pm.split.SplitAssetLoader; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.FileUtils; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.os.Trace; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Pair; +import android.util.Slog; +import android.util.SparseArray; +import android.util.TypedValue; +import android.util.apk.ApkSignatureVerifier; + +import com.android.internal.R; +import com.android.internal.os.ClassLoaderFactory; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.XmlUtils; + +import libcore.io.IoUtils; +import libcore.util.EmptyArray; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +/** @hide */ +public class ApkParseUtils { + + // TODO(b/135203078): Consolidate log tags + static final String TAG = "PackageParsing"; + + /** + * Parse the package at the given location. Automatically detects if the + * package is a monolithic style (single APK file) or cluster style + * (directory of APKs). + * <p> + * This performs sanity checking on cluster style packages, such as + * requiring identical package name and version codes, a single base APK, + * and unique split names. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}. + * + * If {@code useCaches} is true, the package parser might return a cached + * result from a previous parse of the same {@code packageFile} with the same + * {@code flags}. Note that this method does not check whether {@code packageFile} + * has changed since the last parse, it's up to callers to do so. + * + * @see PackageParser#parsePackageLite(File, int) + */ + public static ParsingPackage parsePackage( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + DisplayMetrics displayMetrics, + boolean onlyCoreApps, + File packageFile, + int flags + ) throws PackageParserException { + if (packageFile.isDirectory()) { + return parseClusterPackage(parseInput, separateProcesses, callback, displayMetrics, + onlyCoreApps, packageFile, flags); + } else { + return parseMonolithicPackage(parseInput, separateProcesses, callback, displayMetrics, + onlyCoreApps, packageFile, flags); + } + } + + /** + * Parse all APKs contained in the given directory, treating them as a + * single package. This also performs sanity checking, such as requiring + * identical package name and version codes, a single base APK, and unique + * split names. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(ParsedPackage, boolean)}. + */ + private static ParsingPackage parseClusterPackage( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + DisplayMetrics displayMetrics, + boolean onlyCoreApps, + File packageDir, + int flags + ) throws PackageParserException { + final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir, + 0); + if (onlyCoreApps && !lite.coreApp) { + throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Not a coreApp: " + packageDir); + } + + // Build the split dependency tree. + SparseArray<int[]> splitDependencies = null; + final SplitAssetLoader assetLoader; + if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) { + try { + splitDependencies = SplitAssetDependencyLoader.createDependenciesFromPackage(lite); + assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); + } catch (SplitAssetDependencyLoader.IllegalDependencyException e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getMessage()); + } + } else { + assetLoader = new DefaultSplitAssetLoader(lite, flags); + } + + try { + final AssetManager assets = assetLoader.getBaseAssetManager(); + final File baseApk = new File(lite.baseCodePath); + ParsingPackage parsingPackage = parseBaseApk(parseInput, separateProcesses, callback, + displayMetrics, baseApk, assets, flags); + if (parsingPackage == null) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, + "Failed to parse base APK: " + baseApk); + } + + if (!ArrayUtils.isEmpty(lite.splitNames)) { + parsingPackage.asSplit( + lite.splitNames, + lite.splitCodePaths, + lite.splitRevisionCodes, + splitDependencies + ); + final int num = lite.splitNames.length; + + for (int i = 0; i < num; i++) { + final AssetManager splitAssets = assetLoader.getSplitAssetManager(i); + parseSplitApk(parseInput, displayMetrics, separateProcesses, parsingPackage, i, + splitAssets, flags); + } + } + + return parsingPackage.setCodePath(packageDir.getCanonicalPath()) + .setUse32BitAbi(lite.use32bitAbi); + } catch (IOException e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to get path: " + lite.baseCodePath, e); + } finally { + IoUtils.closeQuietly(assetLoader); + } + } + + /** + * Parse the given APK file, treating it as as a single monolithic package. + * <p> + * Note that this <em>does not</em> perform signature verification; that + * must be done separately in {@link #collectCertificates(AndroidPackage, boolean)}. + */ + public static ParsingPackage parseMonolithicPackage( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + DisplayMetrics displayMetrics, + boolean onlyCoreApps, + File apkFile, + int flags + ) throws PackageParserException { + final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile, + flags); + if (onlyCoreApps) { + if (!lite.coreApp) { + throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Not a coreApp: " + apkFile); + } + } + + final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags); + try { + return parseBaseApk(parseInput, separateProcesses, callback, + displayMetrics, apkFile, assetLoader.getBaseAssetManager(), flags) + .setCodePath(apkFile.getCanonicalPath()) + .setUse32BitAbi(lite.use32bitAbi); + } catch (IOException e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to get path: " + apkFile, e); + } finally { + IoUtils.closeQuietly(assetLoader); + } + } + + private static ParsingPackage parseBaseApk( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + DisplayMetrics displayMetrics, + File apkFile, + AssetManager assets, + int flags + ) throws PackageParserException { + final String apkPath = apkFile.getAbsolutePath(); + + String volumeUuid = null; + if (apkPath.startsWith(PackageParser.MNT_EXPAND)) { + final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length()); + volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end); + } + + if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); + + XmlResourceParser parser = null; + try { + final int cookie = assets.findCookieForPath(apkPath); + if (cookie == 0) { + throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Failed adding asset path: " + apkPath); + } + parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME); + final Resources res = new Resources(assets, displayMetrics, null); + + ParseResult result = parseBaseApk(parseInput, separateProcesses, callback, apkPath, res, + parser, flags); + if (!result.isSuccess()) { + throw new PackageParserException(result.getParseError(), + apkPath + " (at " + parser.getPositionDescription() + "): " + + result.getErrorMessage()); + } + + return result.getResultAndNull() + .setVolumeUuid(volumeUuid) + .setApplicationVolumeUuid(volumeUuid) + .setSigningDetails(SigningDetails.UNKNOWN); + } catch (PackageParserException e) { + throw e; + } catch (Exception e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to read manifest from " + apkPath, e); + } finally { + IoUtils.closeQuietly(parser); + } + } + + private static void parseSplitApk( + ParseInput parseInput, + DisplayMetrics displayMetrics, + String[] separateProcesses, + ParsingPackage parsingPackage, + int splitIndex, + AssetManager assets, + int flags + ) throws PackageParserException { + final String apkPath = parsingPackage.getSplitCodePaths()[splitIndex]; + + if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath); + + final Resources res; + XmlResourceParser parser = null; + try { + // This must always succeed, as the path has been added to the AssetManager before. + final int cookie = assets.findCookieForPath(apkPath); + if (cookie == 0) { + throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, + "Failed adding asset path: " + apkPath); + } + + parser = assets.openXmlResourceParser(cookie, PackageParser.ANDROID_MANIFEST_FILENAME); + res = new Resources(assets, displayMetrics, null); + + final String[] outError = new String[1]; + ParseResult parseResult = parseSplitApk(parseInput, separateProcesses, parsingPackage, + res, parser, flags, splitIndex, outError); + if (!parseResult.isSuccess()) { + throw new PackageParserException(parseResult.getParseError(), + apkPath + " (at " + parser.getPositionDescription() + "): " + + parseResult.getErrorMessage()); + } + } catch (PackageParserException e) { + throw e; + } catch (Exception e) { + throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, + "Failed to read manifest from " + apkPath, e); + } finally { + IoUtils.closeQuietly(parser); + } + } + + /** + * Parse the manifest of a <em>base APK</em>. When adding new features you + * need to consider whether they should be supported by split APKs and child + * packages. + * + * @param apkPath The package apk file path + * @param res The resources from which to resolve values + * @param parser The manifest parser + * @param flags Flags how to parse + * @return Parsed package or null on error. + */ + private static ParseResult parseBaseApk( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + String apkPath, + Resources res, + XmlResourceParser parser, + int flags + ) throws XmlPullParserException, IOException { + final String splitName; + final String pkgName; + + try { + Pair<String, String> packageSplit = PackageParser.parsePackageSplitNames(parser, + parser); + pkgName = packageSplit.first; + splitName = packageSplit.second; + + if (!TextUtils.isEmpty(splitName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, + "Expected base APK, but found split " + splitName + ); + } + } catch (PackageParserException e) { + return parseInput.error(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME); + } + + // TODO: Remove when manifest overlaying removed + if (callback != null) { + String[] overlayPaths = callback.getOverlayPaths(pkgName, apkPath); + if (overlayPaths != null && overlayPaths.length > 0) { + for (String overlayPath : overlayPaths) { + res.getAssets().addOverlayPath(overlayPath); + } + } + } + + TypedArray manifestArray = null; + + try { + manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest); + + boolean isCoreApp = parser.getAttributeBooleanValue(null, "coreApp", false); + + ParsingPackage parsingPackage = PackageImpl.forParsing( + pkgName, + apkPath, + manifestArray, + isCoreApp + ); + + ParseResult result = parseBaseApkTags(parseInput, separateProcesses, callback, + parsingPackage, manifestArray, res, parser, flags); + if (!result.isSuccess()) { + return result; + } + + return parseInput.success(parsingPackage); + } finally { + if (manifestArray != null) { + manifestArray.recycle(); + } + } + } + + /** + * Parse the manifest of a <em>split APK</em>. + * <p> + * Note that split APKs have many more restrictions on what they're capable + * of doing, so many valid features of a base APK have been carefully + * omitted here. + * + * @param parsingPackage builder to fill + * @return false on failure + */ + private static ParseResult parseSplitApk( + ParseInput parseInput, + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + int flags, + int splitIndex, + String[] outError + ) throws XmlPullParserException, IOException, PackageParserException { + AttributeSet attrs = parser; + + // We parsed manifest tag earlier; just skip past it + PackageParser.parsePackageSplitNames(parser, attrs); + + int type; + + boolean foundApp = false; + + int outerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals(PackageParser.TAG_APPLICATION)) { + if (foundApp) { + if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<manifest> has more than one <application>" + ); + } else { + Slog.w(TAG, "<manifest> has more than one <application>"); + XmlUtils.skipCurrentTag(parser); + continue; + } + } + + foundApp = true; + ParseResult parseResult = parseSplitApplication(parseInput, separateProcesses, + parsingPackage, res, + parser, flags, + splitIndex, outError); + if (!parseResult.isSuccess()) { + return parseResult; + } + + } else if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <manifest>: " + parser.getName() + ); + + } else { + Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + } + + if (!foundApp) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY, + "<manifest> does not contain an <application>" + ); + } + + return parseInput.success(parsingPackage); + } + + /** + * Parse the {@code application} XML tree at the current parse location in a + * <em>split APK</em> manifest. + * <p> + * Note that split APKs have many more restrictions on what they're capable + * of doing, so many valid features of a base APK have been carefully + * omitted here. + */ + private static ParseResult parseSplitApplication( + ParseInput parseInput, + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + int flags, + int splitIndex, + String[] outError + ) throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestApplication); + + parsingPackage.setSplitHasCode(splitIndex, sa.getBoolean( + R.styleable.AndroidManifestApplication_hasCode, true)); + + final String classLoaderName = sa.getString( + R.styleable.AndroidManifestApplication_classLoader); + if (classLoaderName == null || ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { + parsingPackage.setSplitClassLoaderName(splitIndex, classLoaderName); + } else { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Invalid class loader name: " + classLoaderName + ); + } + + final int innerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + ComponentParseUtils.ParsedComponent parsedComponent = null; + + String tagName = parser.getName(); + switch (tagName) { + case "activity": + ComponentParseUtils.ParsedActivity activity = + ComponentParseUtils.parseActivity(separateProcesses, + parsingPackage, + res, parser, flags, + outError, + false, + parsingPackage.isBaseHardwareAccelerated()); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addActivity(activity); + parsedComponent = activity; + break; + case "receiver": + activity = ComponentParseUtils.parseActivity( + separateProcesses, parsingPackage, + res, parser, flags, outError, + true, false); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addReceiver(activity); + parsedComponent = activity; + break; + case "service": + ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService( + separateProcesses, + parsingPackage, + res, parser, flags, outError + ); + if (s == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addService(s); + parsedComponent = s; + break; + case "provider": + ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider( + separateProcesses, + parsingPackage, + res, parser, flags, outError); + if (p == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addProvider(p); + parsedComponent = p; + break; + case "activity-alias": + activity = ComponentParseUtils.parseActivityAlias( + parsingPackage, + res, + parser, + outError + ); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addActivity(activity); + parsedComponent = activity; + break; + case "meta-data": + // note: application meta-data is stored off to the side, so it can + // remain null in the primary copy (we like to avoid extra copies because + // it can be large) + Bundle appMetaData = parseMetaData(parsingPackage, res, parser, + parsingPackage.getAppMetaData(), + outError); + if (appMetaData == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.setAppMetaData(appMetaData); + break; + case "uses-static-library": + ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage, + res, parser); + if (!parseResult.isSuccess()) { + return parseResult; + } + + break; + case "uses-library": + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesLibrary_name); + boolean req = sa.getBoolean( + R.styleable.AndroidManifestUsesLibrary_required, true); + + sa.recycle(); + + if (lname != null) { + lname = lname.intern(); + if (req) { + // Upgrade to treat as stronger constraint + parsingPackage.addUsesLibrary(lname) + .removeUsesOptionalLibrary(lname); + } else { + // Ignore if someone already defined as required + if (!ArrayUtils.contains(parsingPackage.getUsesLibraries(), lname)) { + parsingPackage.addUsesOptionalLibrary(lname); + } + } + } + + XmlUtils.skipCurrentTag(parser); + break; + case "uses-package": + // Dependencies for app installers; we don't currently try to + // enforce this. + XmlUtils.skipCurrentTag(parser); + break; + default: + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <application>: " + tagName + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <application>: " + tagName + ); + } + } + + if (parsedComponent != null && parsedComponent.getSplitName() == null) { + // If the loaded component did not specify a split, inherit the split name + // based on the split it is defined in. + // This is used to later load the correct split when starting this + // component. + parsedComponent.setSplitName(parsingPackage.getSplitNames()[splitIndex]); + } + } + + return parseInput.success(parsingPackage); + } + + private static ParseResult parseBaseApkTags( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + ParsingPackage parsingPackage, + TypedArray manifestArray, + Resources res, + XmlResourceParser parser, + int flags + ) throws XmlPullParserException, IOException { + int type; + boolean foundApp = false; + + TypedArray sa = manifestArray; + + ParseResult sharedUserResult = parseSharedUser(parseInput, parsingPackage, sa); + if (!sharedUserResult.isSuccess()) { + return sharedUserResult; + } + + parseManifestAttributes(sa, parsingPackage, flags); + + int outerDepth = parser.getDepth(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + + // All methods return a boolean, even if they can't fail. This can be enforced + // by making this final and not assigned, forcing the switch to assign success + // once in every branch. + final boolean success; + ParseResult parseResult = null; + + // TODO(b/135203078): Either use all booleans or all ParseResults + // TODO(b/135203078): Convert to instance methods to share variables + switch (tagName) { + case PackageParser.TAG_APPLICATION: + if (foundApp) { + if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<manifest> has more than one <application>" + ); + } else { + Slog.w(TAG, "<manifest> has more than one <application>"); + XmlUtils.skipCurrentTag(parser); + success = true; + } + } else { + foundApp = true; + parseResult = parseBaseApplication(parseInput, separateProcesses, + callback, + parsingPackage, res, parser, flags); + success = parseResult.isSuccess(); + } + break; + case PackageParser.TAG_OVERLAY: + parseResult = parseOverlay(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_KEY_SETS: + parseResult = parseKeySets(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_PERMISSION_GROUP: + parseResult = parsePermissionGroup(parseInput, parsingPackage, res, + parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_PERMISSION: + parseResult = parsePermission(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_PERMISSION_TREE: + parseResult = parsePermissionTree(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_USES_PERMISSION: + case PackageParser.TAG_USES_PERMISSION_SDK_M: + case PackageParser.TAG_USES_PERMISSION_SDK_23: + parseResult = parseUsesPermission(parseInput, parsingPackage, res, parser, + callback); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_USES_CONFIGURATION: + success = parseUsesConfiguration(parsingPackage, res, parser); + break; + case PackageParser.TAG_USES_FEATURE: + success = parseUsesFeature(parsingPackage, res, parser); + break; + case PackageParser.TAG_FEATURE_GROUP: + success = parseFeatureGroup(parsingPackage, res, parser); + break; + case PackageParser.TAG_USES_SDK: + parseResult = parseUsesSdk(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_SUPPORT_SCREENS: + success = parseSupportScreens(parsingPackage, res, parser); + break; + case PackageParser.TAG_PROTECTED_BROADCAST: + success = parseProtectedBroadcast(parsingPackage, res, parser); + break; + case PackageParser.TAG_INSTRUMENTATION: + parseResult = parseInstrumentation(parseInput, parsingPackage, res, + parser); + success = parseResult.isSuccess(); + break; + case PackageParser.TAG_ORIGINAL_PACKAGE: + success = parseOriginalPackage(parsingPackage, res, parser); + break; + case PackageParser.TAG_ADOPT_PERMISSIONS: + success = parseAdoptPermissions(parsingPackage, res, parser); + break; + case PackageParser.TAG_USES_GL_TEXTURE: + case PackageParser.TAG_COMPATIBLE_SCREENS: + case PackageParser.TAG_SUPPORTS_INPUT: + case PackageParser.TAG_EAT_COMMENT: + // Just skip this tag + XmlUtils.skipCurrentTag(parser); + success = true; + break; + case PackageParser.TAG_RESTRICT_UPDATE: + success = parseRestrictUpdateHash(flags, parsingPackage, res, parser); + break; + case PackageParser.TAG_QUERIES: + parseResult = parseQueries(parseInput, parsingPackage, res, parser); + success = parseResult.isSuccess(); + break; + default: + parseResult = parseUnknownTag(parseInput, parsingPackage, parser); + success = parseResult.isSuccess(); + break; + } + + if (parseResult != null && !parseResult.isSuccess()) { + return parseResult; + } + + if (!success) { + return parseResult; + } + } + + if (!foundApp && ArrayUtils.size(parsingPackage.getInstrumentations()) == 0) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY, + "<manifest> does not contain an <application> or <instrumentation>" + ); + } + + convertNewPermissions(parsingPackage); + + convertSplitPermissions(parsingPackage); + + // At this point we can check if an application is not supporting densities and hence + // cannot be windowed / resized. Note that an SDK version of 0 is common for + // pre-Doughnut applications. + if (parsingPackage.usesCompatibilityMode()) { + adjustPackageToBeUnresizeableAndUnpipable(parsingPackage); + } + + return parseInput.success(parsingPackage); + } + + private static ParseResult parseUnknownTag( + ParseInput parseInput, + ParsingPackage parsingPackage, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <manifest>: " + parser.getName() + ); + } else { + Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + return parseInput.success(parsingPackage); + } + } + + private static ParseResult parseSharedUser( + ParseInput parseInput, + ParsingPackage parsingPackage, + TypedArray manifestArray + ) { + String str = manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_sharedUserId, 0); + if (TextUtils.isEmpty(str)) { + return parseInput.success(parsingPackage); + } + + String nameError = validateName(str, true, true); + if (nameError != null && !"android".equals(parsingPackage.getPackageName())) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + "<manifest> specifies bad sharedUserId name \"" + str + "\": " + + nameError + ); + } + + int sharedUserLabel = manifestArray.getResourceId( + R.styleable.AndroidManifest_sharedUserLabel, 0); + parsingPackage.setSharedUserId(str.intern()) + .setSharedUserLabel(sharedUserLabel); + + return parseInput.success(parsingPackage); + } + + private static void parseManifestAttributes( + TypedArray manifestArray, + ParsingPackage parsingPackage, + int flags + ) { + int installLocation = manifestArray.getInteger(R.styleable.AndroidManifest_installLocation, + PackageParser.PARSE_DEFAULT_INSTALL_LOCATION); + + final int targetSandboxVersion = manifestArray.getInteger( + R.styleable.AndroidManifest_targetSandboxVersion, + PackageParser.PARSE_DEFAULT_TARGET_SANDBOX); + + parsingPackage.setInstallLocation(installLocation) + .setTargetSandboxVersion(targetSandboxVersion); + + /* Set the global "on SD card" flag */ + parsingPackage.setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0); + + parsingPackage.setIsolatedSplitLoading(manifestArray.getBoolean( + R.styleable.AndroidManifest_isolatedSplits, false)); + } + + private static ParseResult parseKeySets( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // we've encountered the 'key-sets' tag + // all the keys and keysets that we want must be defined here + // so we're going to iterate over the parser and pull out the things we want + int outerDepth = parser.getDepth(); + int currentKeySetDepth = -1; + int type; + String currentKeySet = null; + ArrayMap<String, PublicKey> publicKeys = new ArrayMap<>(); + ArraySet<String> upgradeKeySets = new ArraySet<>(); + ArrayMap<String, ArraySet<String>> definedKeySets = + new ArrayMap<>(); + ArraySet<String> improperKeySets = new ArraySet<>(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG) { + if (parser.getDepth() == currentKeySetDepth) { + currentKeySet = null; + currentKeySetDepth = -1; + } + continue; + } + String tagName = parser.getName(); + if (tagName.equals("key-set")) { + if (currentKeySet != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Improperly nested 'key-set' tag at " + parser.getPositionDescription() + ); + } + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestKeySet); + final String keysetName = sa.getNonResourceString( + R.styleable.AndroidManifestKeySet_name); + definedKeySets.put(keysetName, new ArraySet<>()); + currentKeySet = keysetName; + currentKeySetDepth = parser.getDepth(); + sa.recycle(); + } else if (tagName.equals("public-key")) { + if (currentKeySet == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Improperly nested 'key-set' tag at " + parser.getPositionDescription() + ); + } + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestPublicKey); + final String publicKeyName = sa.getNonResourceString( + R.styleable.AndroidManifestPublicKey_name); + final String encodedKey = sa.getNonResourceString( + R.styleable.AndroidManifestPublicKey_value); + if (encodedKey == null && publicKeys.get(publicKeyName) == null) { + sa.recycle(); + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "'public-key' " + publicKeyName + " must define a public-key value" + + " on first use at " + parser.getPositionDescription() + ); + } else if (encodedKey != null) { + PublicKey currentKey = PackageParser.parsePublicKey(encodedKey); + if (currentKey == null) { + Slog.w(TAG, "No recognized valid key in 'public-key' tag at " + + parser.getPositionDescription() + " key-set " + currentKeySet + + " will not be added to the package's defined key-sets."); + sa.recycle(); + improperKeySets.add(currentKeySet); + XmlUtils.skipCurrentTag(parser); + continue; + } + if (publicKeys.get(publicKeyName) == null + || publicKeys.get(publicKeyName).equals(currentKey)) { + + /* public-key first definition, or matches old definition */ + publicKeys.put(publicKeyName, currentKey); + } else { + sa.recycle(); + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Value of 'public-key' " + publicKeyName + + " conflicts with previously defined value at " + + parser.getPositionDescription() + ); + } + } + definedKeySets.get(currentKeySet).add(publicKeyName); + sa.recycle(); + XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("upgrade-key-set")) { + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUpgradeKeySet); + String name = sa.getNonResourceString( + R.styleable.AndroidManifestUpgradeKeySet_name); + upgradeKeySets.add(name); + sa.recycle(); + XmlUtils.skipCurrentTag(parser); + } else if (PackageParser.RIGID_PARSER) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <key-sets>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription() + ); + } else { + Slog.w(TAG, "Unknown element under <key-sets>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + } + String packageName = parsingPackage.getPackageName(); + Set<String> publicKeyNames = publicKeys.keySet(); + if (publicKeyNames.removeAll(definedKeySets.keySet())) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Package" + packageName + " AndroidManifest.xml " + + "'key-set' and 'public-key' names must be distinct." + ); + } + + for (ArrayMap.Entry<String, ArraySet<String>> e : definedKeySets.entrySet()) { + final String keySetName = e.getKey(); + if (e.getValue().size() == 0) { + Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " + + "'key-set' " + keySetName + " has no valid associated 'public-key'." + + " Not including in package's defined key-sets."); + continue; + } else if (improperKeySets.contains(keySetName)) { + Slog.w(TAG, "Package" + packageName + " AndroidManifest.xml " + + "'key-set' " + keySetName + " contained improper 'public-key'" + + " tags. Not including in package's defined key-sets."); + continue; + } + + for (String s : e.getValue()) { + parsingPackage.addKeySet(keySetName, publicKeys.get(s)); + } + } + if (parsingPackage.getKeySetMapping().keySet().containsAll(upgradeKeySets)) { + parsingPackage.setUpgradeKeySets(upgradeKeySets); + } else { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Package" + packageName + " AndroidManifest.xml " + + "does not define all 'upgrade-key-set's ." + ); + } + + return parseInput.success(parsingPackage); + } + + public static boolean parsePackageItemInfo(String packageName, PackageItemInfo outInfo, + String[] outError, String tag, TypedArray sa, boolean nameRequired, + int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) { + // This case can only happen in unit tests where we sometimes need to create fakes + // of various package parser data structures. + if (sa == null) { + outError[0] = tag + " does not contain any attributes"; + return false; + } + + String name = sa.getNonConfigurationString(nameRes, 0); + if (name == null) { + if (nameRequired) { + outError[0] = tag + " does not specify android:name"; + return false; + } + } else { + String outInfoName = buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { + outError[0] = tag + " invalid android:name"; + return false; + } + outInfo.name = outInfoName; + if (outInfoName == null) { + return false; + } + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; + if (roundIconVal != 0) { + outInfo.icon = roundIconVal; + outInfo.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(iconRes, 0); + if (iconVal != 0) { + outInfo.icon = iconVal; + outInfo.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(logoRes, 0); + if (logoVal != 0) { + outInfo.logo = logoVal; + } + + int bannerVal = sa.getResourceId(bannerRes, 0); + if (bannerVal != 0) { + outInfo.banner = bannerVal; + } + + TypedValue v = sa.peekValue(labelRes); + if (v != null && (outInfo.labelRes = v.resourceId) == 0) { + outInfo.nonLocalizedLabel = v.coerceToString(); + } + + outInfo.packageName = packageName; + + return true; + } + + private static ParseResult parsePackageItemInfo( + ParseInput parseInput, + ParsingPackage parsingPackage, + String tag, + TypedArray sa, + boolean nameRequired, + int nameRes, + int labelRes, + int iconRes, + int roundIconRes, + int logoRes, + int bannerRes + ) { + // This case can only happen in unit tests where we sometimes need to create fakes + // of various package parser data structures. + if (sa == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + tag + " does not contain any attributes" + ); + } + + String name = sa.getNonConfigurationString(nameRes, 0); + if (name == null) { + if (nameRequired) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + tag + " does not specify android:name" + ); + } + } else { + String packageName = parsingPackage.getPackageName(); + String outInfoName = buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + tag + " invalid android:name" + ); + } else if (outInfoName == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Empty class name in package " + packageName + ); + } + + parsingPackage.setName(outInfoName); + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; + if (roundIconVal != 0) { + parsingPackage.setIcon(roundIconVal) + .setNonLocalizedLabel(null); + } else { + int iconVal = sa.getResourceId(iconRes, 0); + if (iconVal != 0) { + parsingPackage.setIcon(iconVal) + .setNonLocalizedLabel(null); + } + } + + int logoVal = sa.getResourceId(logoRes, 0); + if (logoVal != 0) { + parsingPackage.setLogo(logoVal); + } + + int bannerVal = sa.getResourceId(bannerRes, 0); + if (bannerVal != 0) { + parsingPackage.setBanner(bannerVal); + } + + TypedValue v = sa.peekValue(labelRes); + if (v != null) { + parsingPackage.setLabelRes(v.resourceId); + if (v.resourceId == 0) { + parsingPackage.setNonLocalizedLabel(v.coerceToString()); + } + } + + return parseInput.success(parsingPackage); + } + + private static ParseResult parsePermissionGroup( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + + ComponentParseUtils.ParsedPermissionGroup parsedPermissionGroup = + ComponentParseUtils.parsePermissionGroup(parsingPackage, + res, parser, outError); + + if (parsedPermissionGroup == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addPermissionGroup(parsedPermissionGroup); + + return parseInput.success(parsingPackage); + } + + private static ParseResult parsePermission( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + + ComponentParseUtils.ParsedPermission parsedPermission = + ComponentParseUtils.parsePermission(parsingPackage, + res, parser, outError); + + if (parsedPermission == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addPermission(parsedPermission); + + return parseInput.success(parsingPackage); + } + + private static ParseResult parsePermissionTree( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + + ComponentParseUtils.ParsedPermission parsedPermission = + ComponentParseUtils.parsePermissionTree(parsingPackage, + res, parser, outError); + + if (parsedPermission == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addPermission(parsedPermission); + + return parseInput.success(parsingPackage); + } + + private static ParseResult parseUsesPermission( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + PackageParser.Callback callback + ) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesPermission); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String name = sa.getNonResourceString( + R.styleable.AndroidManifestUsesPermission_name); + + int maxSdkVersion = 0; + TypedValue val = sa.peekValue( + R.styleable.AndroidManifestUsesPermission_maxSdkVersion); + if (val != null) { + if (val.type >= TypedValue.TYPE_FIRST_INT && val.type <= TypedValue.TYPE_LAST_INT) { + maxSdkVersion = val.data; + } + } + + final String requiredFeature = sa.getNonConfigurationString( + R.styleable.AndroidManifestUsesPermission_requiredFeature, 0); + + final String requiredNotfeature = sa.getNonConfigurationString( + R.styleable.AndroidManifestUsesPermission_requiredNotFeature, + 0); + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + + // Can only succeed from here on out + ParseResult success = parseInput.success(parsingPackage); + + if (name == null) { + return success; + } + + if ((maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT)) { + return success; + } + + // Only allow requesting this permission if the platform supports the given feature. + if (requiredFeature != null && callback != null && !callback.hasFeature(requiredFeature)) { + return success; + } + + // Only allow requesting this permission if the platform doesn't support the given feature. + if (requiredNotfeature != null && callback != null + && callback.hasFeature(requiredNotfeature)) { + return success; + } + + if (!parsingPackage.getRequestedPermissions().contains(name)) { + parsingPackage.addRequestedPermission(name.intern()); + } else { + Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: " + + name + " in package: " + parsingPackage.getPackageName() + " at: " + + parser.getPositionDescription()); + } + + return success; + } + + private static boolean parseUsesConfiguration( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + ConfigurationInfo cPref = new ConfigurationInfo(); + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesConfiguration); + cPref.reqTouchScreen = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen, + Configuration.TOUCHSCREEN_UNDEFINED); + cPref.reqKeyboardType = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType, + Configuration.KEYBOARD_UNDEFINED); + if (sa.getBoolean( + R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; + } + cPref.reqNavigation = sa.getInt( + R.styleable.AndroidManifestUsesConfiguration_reqNavigation, + Configuration.NAVIGATION_UNDEFINED); + if (sa.getBoolean( + R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav, + false)) { + cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV; + } + sa.recycle(); + parsingPackage.addConfigPreference(cPref); + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static boolean parseUsesFeature( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + FeatureInfo fi = parseFeatureInfo(res, parser); + parsingPackage.addReqFeature(fi); + + if (fi.name == null) { + ConfigurationInfo cPref = new ConfigurationInfo(); + cPref.reqGlEsVersion = fi.reqGlEsVersion; + parsingPackage.addConfigPreference(cPref); + } + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static FeatureInfo parseFeatureInfo(Resources res, AttributeSet attrs) { + FeatureInfo fi = new FeatureInfo(); + TypedArray sa = res.obtainAttributes(attrs, + R.styleable.AndroidManifestUsesFeature); + // Note: don't allow this value to be a reference to a resource + // that may change. + fi.name = sa.getNonResourceString(R.styleable.AndroidManifestUsesFeature_name); + fi.version = sa.getInt(R.styleable.AndroidManifestUsesFeature_version, 0); + if (fi.name == null) { + fi.reqGlEsVersion = sa.getInt(R.styleable.AndroidManifestUsesFeature_glEsVersion, + FeatureInfo.GL_ES_VERSION_UNDEFINED); + } + if (sa.getBoolean(R.styleable.AndroidManifestUsesFeature_required, true)) { + fi.flags |= FeatureInfo.FLAG_REQUIRED; + } + sa.recycle(); + return fi; + } + + private static boolean parseFeatureGroup( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + FeatureGroupInfo group = new FeatureGroupInfo(); + ArrayList<FeatureInfo> features = null; + final int innerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final String innerTagName = parser.getName(); + if (innerTagName.equals("uses-feature")) { + FeatureInfo featureInfo = parseFeatureInfo(res, parser); + // FeatureGroups are stricter and mandate that + // any <uses-feature> declared are mandatory. + featureInfo.flags |= FeatureInfo.FLAG_REQUIRED; + features = ArrayUtils.add(features, featureInfo); + } else { + Slog.w(TAG, + "Unknown element under <feature-group>: " + innerTagName + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } + XmlUtils.skipCurrentTag(parser); + } + + if (features != null) { + group.features = new FeatureInfo[features.size()]; + group.features = features.toArray(group.features); + } + + parsingPackage.addFeatureGroup(group); + return true; + } + + private static ParseResult parseUsesSdk( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + if (PackageParser.SDK_VERSION > 0) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesSdk); + + int minVers = 1; + String minCode = null; + int targetVers = 0; + String targetCode = null; + + TypedValue val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_minSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + minCode = val.string.toString(); + } else { + // If it's not a string, it's an integer. + minVers = val.data; + } + } + + val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_targetSdkVersion); + if (val != null) { + if (val.type == TypedValue.TYPE_STRING && val.string != null) { + targetCode = val.string.toString(); + if (minCode == null) { + minCode = targetCode; + } + } else { + // If it's not a string, it's an integer. + targetVers = val.data; + } + } else { + targetVers = minVers; + targetCode = minCode; + } + + sa.recycle(); + + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, + minCode, + PackageParser.SDK_VERSION, PackageParser.SDK_CODENAMES, outError); + if (minSdkVersion < 0) { + return parseInput.error( + PackageManager.INSTALL_FAILED_OLDER_SDK + ); + } + + final int targetSdkVersion = PackageParser.computeTargetSdkVersion( + targetVers, + targetCode, PackageParser.SDK_CODENAMES, outError); + if (targetSdkVersion < 0) { + return parseInput.error( + PackageManager.INSTALL_FAILED_OLDER_SDK + ); + } + + parsingPackage.setMinSdkVersion(minSdkVersion) + .setTargetSdkVersion(targetSdkVersion); + } + + XmlUtils.skipCurrentTag(parser); + return parseInput.success(parsingPackage); + } + + private static boolean parseRestrictUpdateHash( + int flags, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + if ((flags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestRestrictUpdate); + final String hash = sa.getNonConfigurationString( + R.styleable.AndroidManifestRestrictUpdate_hash, + 0); + sa.recycle(); + + if (hash != null) { + final int hashLength = hash.length(); + final byte[] hashBytes = new byte[hashLength / 2]; + for (int i = 0; i < hashLength; i += 2) { + hashBytes[i / 2] = (byte) ((Character.digit(hash.charAt(i), 16) + << 4) + + Character.digit(hash.charAt(i + 1), 16)); + } + parsingPackage.setRestrictUpdateHash(hashBytes); + } else { + parsingPackage.setRestrictUpdateHash(null); + } + } + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static ParseResult parseQueries( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + + final int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + if (parser.getName().equals("intent")) { + String[] outError = new String[1]; + ComponentParseUtils.ParsedQueriesIntentInfo intentInfo = + ComponentParseUtils.parsedParsedQueriesIntentInfo( + parsingPackage, res, parser, outError + ); + if (intentInfo == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + Uri data = null; + String dataType = null; + String host = ""; + final int numActions = intentInfo.countActions(); + final int numSchemes = intentInfo.countDataSchemes(); + final int numTypes = intentInfo.countDataTypes(); + final int numHosts = intentInfo.getHosts().length; + if ((numSchemes == 0 && numTypes == 0 && numActions == 0)) { + outError[0] = "intent tags must contain either an action or data."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + if (numActions > 1) { + outError[0] = "intent tag may have at most one action."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + if (numTypes > 1) { + outError[0] = "intent tag may have at most one data type."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + if (numSchemes > 1) { + outError[0] = "intent tag may have at most one data scheme."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + if (numHosts > 1) { + outError[0] = "intent tag may have at most one data host."; + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + Intent intent = new Intent(); + for (int i = 0, max = intentInfo.countCategories(); i < max; i++) { + intent.addCategory(intentInfo.getCategory(i)); + } + if (numHosts == 1) { + host = intentInfo.getHosts()[0]; + } + if (numSchemes == 1) { + data = new Uri.Builder() + .scheme(intentInfo.getDataScheme(0)) + .authority(host) + .build(); + } + if (numTypes == 1) { + dataType = intentInfo.getDataType(0); + } + intent.setDataAndType(data, dataType); + if (numActions == 1) { + intent.setAction(intentInfo.getAction(0)); + } + parsingPackage.addQueriesIntent(intent); + } else if (parser.getName().equals("package")) { + final TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestQueriesPackage); + final String packageName = + sa.getString(R.styleable.AndroidManifestQueriesPackage_name); + if (TextUtils.isEmpty(packageName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Package name is missing from package tag." + ); + } + parsingPackage.addQueriesPackage(packageName.intern()); + } + } + return parseInput.success(parsingPackage); + } + + /** + * Parse the {@code application} XML tree at the current parse location in a + * <em>base APK</em> manifest. + * <p> + * When adding new features, carefully consider if they should also be + * supported by split APKs. + * + * @hide + */ + public static ParseResult parseBaseApplication( + ParseInput parseInput, + String[] separateProcesses, + PackageParser.Callback callback, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + int flags + ) throws XmlPullParserException, IOException { + final String pkgName = parsingPackage.getPackageName(); + + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + TypedArray sa = null; + + try { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestApplication); + + + parsingPackage + .setIconRes( + sa.getResourceId(R.styleable.AndroidManifestApplication_icon, 0)) + .setRoundIconRes( + sa.getResourceId(R.styleable.AndroidManifestApplication_roundIcon, 0)); + + ParseResult result = parsePackageItemInfo( + parseInput, + parsingPackage, + "<application>", + sa, false /*nameRequired*/, + R.styleable.AndroidManifestApplication_name, + R.styleable.AndroidManifestApplication_label, + R.styleable.AndroidManifestApplication_icon, + R.styleable.AndroidManifestApplication_roundIcon, + R.styleable.AndroidManifestApplication_logo, + R.styleable.AndroidManifestApplication_banner + ); + if (!result.isSuccess()) { + return result; + } + + String name = parsingPackage.getName(); + if (name != null) { + parsingPackage.setClassName(name); + } + + String manageSpaceActivity = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_manageSpaceActivity, + Configuration.NATIVE_CONFIG_VERSION); + if (manageSpaceActivity != null) { + String manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity); + + if (manageSpaceActivityName == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Empty class name in package " + pkgName + ); + } + + parsingPackage.setManageSpaceActivityName(manageSpaceActivityName); + } + + boolean allowBackup = sa.getBoolean( + R.styleable.AndroidManifestApplication_allowBackup, true); + parsingPackage.setAllowBackup(allowBackup); + + if (allowBackup) { + // backupAgent, killAfterRestore, fullBackupContent, backupInForeground, + // and restoreAnyVersion are only relevant if backup is possible for the + // given application. + String backupAgent = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_backupAgent, + Configuration.NATIVE_CONFIG_VERSION); + if (backupAgent != null) { + String backupAgentName = buildClassName(pkgName, backupAgent); + if (backupAgentName == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Empty class name in package " + pkgName + ); + } + + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "android:backupAgent = " + backupAgentName + + " from " + pkgName + "+" + backupAgent); + } + + parsingPackage.setBackupAgentName(backupAgentName); + + parsingPackage.setKillAfterRestore(sa.getBoolean( + R.styleable.AndroidManifestApplication_killAfterRestore, true)); + + parsingPackage.setRestoreAnyVersion(sa.getBoolean( + R.styleable.AndroidManifestApplication_restoreAnyVersion, false)); + + parsingPackage.setFullBackupOnly(sa.getBoolean( + R.styleable.AndroidManifestApplication_fullBackupOnly, false)); + + parsingPackage.setBackupInForeground(sa.getBoolean( + R.styleable.AndroidManifestApplication_backupInForeground, + false)); + } + + TypedValue v = sa.peekValue( + R.styleable.AndroidManifestApplication_fullBackupContent); + int fullBackupContent = 0; + + if (v != null) { + fullBackupContent = v.resourceId; + + if (v.resourceId == 0) { + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "fullBackupContent specified as boolean=" + + (v.data == 0 ? "false" : "true")); + } + // "false" => -1, "true" => 0 + fullBackupContent = v.data == 0 ? -1 : 0; + } + + parsingPackage.setFullBackupContent(fullBackupContent); + } + if (PackageParser.DEBUG_BACKUP) { + Slog.v(TAG, "fullBackupContent=" + fullBackupContent + " for " + pkgName); + } + } + + parsingPackage + .setTheme( + sa.getResourceId(R.styleable.AndroidManifestApplication_theme, 0)) + .setDescriptionRes( + sa.getResourceId(R.styleable.AndroidManifestApplication_description, + 0)); + + if (sa.getBoolean( + R.styleable.AndroidManifestApplication_persistent, + false)) { + // Check if persistence is based on a feature being present + final String requiredFeature = sa.getNonResourceString(R.styleable + .AndroidManifestApplication_persistentWhenFeatureAvailable); + parsingPackage.setPersistent(requiredFeature == null + || callback.hasFeature(requiredFeature)); + } + + boolean requiredForAllUsers = sa.getBoolean( + R.styleable.AndroidManifestApplication_requiredForAllUsers, + false); + parsingPackage.setRequiredForAllUsers(requiredForAllUsers); + + String restrictedAccountType = sa.getString(R.styleable + .AndroidManifestApplication_restrictedAccountType); + if (restrictedAccountType != null && restrictedAccountType.length() > 0) { + parsingPackage.setRestrictedAccountType(restrictedAccountType); + } + + String requiredAccountType = sa.getString(R.styleable + .AndroidManifestApplication_requiredAccountType); + if (requiredAccountType != null && requiredAccountType.length() > 0) { + parsingPackage.setRequiredAccountType(requiredAccountType); + } + + parsingPackage.setForceQueryable( + sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false) + ); + + boolean debuggable = sa.getBoolean( + R.styleable.AndroidManifestApplication_debuggable, + false + ); + + parsingPackage.setDebuggable(debuggable); + + if (debuggable) { + // Debuggable implies profileable + parsingPackage.setProfileableByShell(true); + } + + parsingPackage.setVmSafeMode(sa.getBoolean( + R.styleable.AndroidManifestApplication_vmSafeMode, false)); + + boolean baseHardwareAccelerated = sa.getBoolean( + R.styleable.AndroidManifestApplication_hardwareAccelerated, + parsingPackage.getTargetSdkVersion() + >= Build.VERSION_CODES.ICE_CREAM_SANDWICH); + parsingPackage.setBaseHardwareAccelerated(baseHardwareAccelerated); + + parsingPackage.setHasCode(sa.getBoolean( + R.styleable.AndroidManifestApplication_hasCode, true)); + + parsingPackage.setAllowTaskReparenting(sa.getBoolean( + R.styleable.AndroidManifestApplication_allowTaskReparenting, false)); + + parsingPackage.setAllowClearUserData(sa.getBoolean( + R.styleable.AndroidManifestApplication_allowClearUserData, true)); + + parsingPackage.setTestOnly(sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_testOnly, + false)); + + parsingPackage.setLargeHeap(sa.getBoolean( + R.styleable.AndroidManifestApplication_largeHeap, false)); + + parsingPackage.setUsesCleartextTraffic(sa.getBoolean( + R.styleable.AndroidManifestApplication_usesCleartextTraffic, + parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.P)); + + parsingPackage.setSupportsRtl(sa.getBoolean( + R.styleable.AndroidManifestApplication_supportsRtl, + false /* default is no RTL support*/)); + + parsingPackage.setMultiArch(sa.getBoolean( + R.styleable.AndroidManifestApplication_multiArch, false)); + + parsingPackage.setExtractNativeLibs(sa.getBoolean( + R.styleable.AndroidManifestApplication_extractNativeLibs, true)); + + parsingPackage.setUseEmbeddedDex(sa.getBoolean( + R.styleable.AndroidManifestApplication_useEmbeddedDex, false)); + + parsingPackage.setDefaultToDeviceProtectedStorage(sa.getBoolean( + R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, + false)); + + parsingPackage.setDirectBootAware(sa.getBoolean( + R.styleable.AndroidManifestApplication_directBootAware, false)); + + if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) { + parsingPackage.setActivitiesResizeModeResizeable(sa.getBoolean( + R.styleable.AndroidManifestApplication_resizeableActivity, true)); + } else { + parsingPackage.setActivitiesResizeModeResizeableViaSdkVersion( + parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.N); + } + + parsingPackage.setAllowClearUserDataOnFailedRestore(sa.getBoolean( + R.styleable.AndroidManifestApplication_allowClearUserDataOnFailedRestore, + true)); + + + parsingPackage.setAllowAudioPlaybackCapture(sa.getBoolean( + R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, + parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q)); + + parsingPackage.setRequestLegacyExternalStorage(sa.getBoolean( + R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, + parsingPackage.getTargetSdkVersion() < Build.VERSION_CODES.Q)); + + parsingPackage + .setMaxAspectRatio( + sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0)) + .setMinAspectRatio( + sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0)) + .setNetworkSecurityConfigRes(sa.getResourceId( + R.styleable.AndroidManifestApplication_networkSecurityConfig, 0)) + .setCategory(sa.getInt(R.styleable.AndroidManifestApplication_appCategory, + ApplicationInfo.CATEGORY_UNDEFINED)); + + String str; + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_permission, 0); + parsingPackage.setPermission((str != null && str.length() > 0) ? str.intern() : null); + + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_taskAffinity, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + str = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_taskAffinity); + } + String packageName = parsingPackage.getPackageName(); + String taskAffinity = PackageParser.buildTaskAffinityName(packageName, + packageName, + str, outError); + + if (outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.setTaskAffinity(taskAffinity); + String factory = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_appComponentFactory); + if (factory != null) { + String appComponentFactory = buildClassName(packageName, factory); + if (appComponentFactory == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Empty class name in package " + pkgName + ); + } + + parsingPackage.setAppComponentFactory(appComponentFactory); + } + + parsingPackage.setUsesNonSdkApi(sa.getBoolean( + R.styleable.AndroidManifestApplication_usesNonSdkApi, false)); + + parsingPackage.setHasFragileUserData(sa.getBoolean( + R.styleable.AndroidManifestApplication_hasFragileUserData, false)); + + CharSequence pname; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString( + R.styleable.AndroidManifestApplication_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString( + R.styleable.AndroidManifestApplication_process); + } + String processName = PackageParser.buildProcessName(packageName, null, pname, flags, + separateProcesses, outError); + + if (outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage + .setProcessName(processName) + .setEnabled( + sa.getBoolean(R.styleable.AndroidManifestApplication_enabled, + true)); + + parsingPackage.setIsGame(sa.getBoolean( + R.styleable.AndroidManifestApplication_isGame, false)); + + boolean cantSaveState = sa.getBoolean( + R.styleable.AndroidManifestApplication_cantSaveState, false); + parsingPackage.setCantSaveState(cantSaveState); + if (cantSaveState) { + // A heavy-weight application can not be in a custom process. + // We can do direct compare because we intern all strings. + if (processName != null && !processName.equals(packageName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "cantSaveState applications can not use custom processes" + ); + } + } + + String classLoaderName = sa.getString( + R.styleable.AndroidManifestApplication_classLoader); + parsingPackage + .setUiOptions(sa.getInt(R.styleable.AndroidManifestApplication_uiOptions, 0)) + .setClassLoaderName(classLoaderName) + .setZygotePreloadName( + sa.getString(R.styleable.AndroidManifestApplication_zygotePreloadName)); + + if (classLoaderName != null + && !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Invalid class loader name: " + classLoaderName + ); + } + } finally { + if (sa != null) { + sa.recycle(); + } + } + + final int innerDepth = parser.getDepth(); + int type; + boolean hasActivityOrder = false; + boolean hasReceiverOrder = false; + boolean hasServiceOrder = false; + + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + switch (tagName) { + case "activity": + ComponentParseUtils.ParsedActivity activity = + ComponentParseUtils.parseActivity(separateProcesses, + parsingPackage, + res, parser, flags, + outError, false, + parsingPackage.isBaseHardwareAccelerated()); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + hasActivityOrder |= (activity.order != 0); + parsingPackage.addActivity(activity); + break; + case "receiver": + activity = ComponentParseUtils.parseActivity(separateProcesses, + parsingPackage, + res, parser, + flags, outError, + true, false); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + hasReceiverOrder |= (activity.order != 0); + parsingPackage.addReceiver(activity); + break; + case "service": + ComponentParseUtils.ParsedService s = ComponentParseUtils.parseService( + separateProcesses, + parsingPackage, + res, parser, flags, + outError); + if (s == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + hasServiceOrder |= (s.order != 0); + parsingPackage.addService(s); + break; + case "provider": + ComponentParseUtils.ParsedProvider p = ComponentParseUtils.parseProvider( + separateProcesses, + parsingPackage, + res, parser, flags, + outError + ); + if (p == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addProvider(p); + break; + case "activity-alias": + activity = ComponentParseUtils.parseActivityAlias( + parsingPackage, + res, + parser, + outError + ); + if (activity == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + hasActivityOrder |= (activity.order != 0); + parsingPackage.addActivity(activity); + break; + case "meta-data": + // note: application meta-data is stored off to the side, so it can + // remain null in the primary copy (we like to avoid extra copies because + // it can be large) + Bundle appMetaData = parseMetaData(parsingPackage, res, parser, + parsingPackage.getAppMetaData(), + outError); + if (appMetaData == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.setAppMetaData(appMetaData); + break; + case "static-library": + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestStaticLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestStaticLibrary_name); + final int version = sa.getInt( + R.styleable.AndroidManifestStaticLibrary_version, -1); + final int versionMajor = sa.getInt( + R.styleable.AndroidManifestStaticLibrary_versionMajor, + 0); + + sa.recycle(); + + // Since the app canot run without a static lib - fail if malformed + if (lname == null || version < 0) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad static-library declaration name: " + lname + + " version: " + version + ); + } + + if (parsingPackage.getSharedUserId() != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID, + "sharedUserId not allowed in static shared library" + ); + } + + if (parsingPackage.getStaticSharedLibName() != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Multiple static-shared libs for package " + pkgName + ); + } + + parsingPackage.setStaticSharedLibName(lname.intern()); + if (version >= 0) { + parsingPackage.setStaticSharedLibVersion( + PackageInfo.composeLongVersionCode(versionMajor, version)); + } else { + parsingPackage.setStaticSharedLibVersion(version); + } + parsingPackage.setStaticSharedLibrary(true); + + XmlUtils.skipCurrentTag(parser); + + break; + case "library": + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + lname = sa.getNonResourceString( + R.styleable.AndroidManifestLibrary_name); + + sa.recycle(); + + if (lname != null) { + lname = lname.intern(); + if (!ArrayUtils.contains(parsingPackage.getLibraryNames(), lname)) { + parsingPackage.addLibraryName(lname); + } + } + + XmlUtils.skipCurrentTag(parser); + + break; + case "uses-static-library": + ParseResult parseResult = parseUsesStaticLibrary(parseInput, parsingPackage, + res, parser); + if (!parseResult.isSuccess()) { + return parseResult; + } + break; + case "uses-library": + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesLibrary); + + // Note: don't allow this value to be a reference to a resource + // that may change. + lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesLibrary_name); + boolean req = sa.getBoolean( + R.styleable.AndroidManifestUsesLibrary_required, + true); + + sa.recycle(); + + if (lname != null) { + lname = lname.intern(); + if (req) { + parsingPackage.addUsesLibrary(lname); + } else { + parsingPackage.addUsesOptionalLibrary(lname); + } + } + + XmlUtils.skipCurrentTag(parser); + + break; + case "uses-package": + // Dependencies for app installers; we don't currently try to + // enforce this. + XmlUtils.skipCurrentTag(parser); + break; + case "profileable": + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestProfileable); + if (sa.getBoolean( + R.styleable.AndroidManifestProfileable_shell, false)) { + parsingPackage.setProfileableByShell(true); + } + XmlUtils.skipCurrentTag(parser); + + default: + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <application>: " + tagName + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad element under <application>: " + tagName + ); + } + } + } + + if (TextUtils.isEmpty(parsingPackage.getStaticSharedLibName())) { + // Add a hidden app detail activity to normal apps which forwards user to App Details + // page. + ComponentParseUtils.ParsedActivity a = generateAppDetailsHiddenActivity( + parsingPackage, + outError + ); + // Ignore errors here + parsingPackage.addActivity(a); + } + + if (hasActivityOrder) { + parsingPackage.sortActivities(); + } + if (hasReceiverOrder) { + parsingPackage.sortReceivers(); + } + if (hasServiceOrder) { + parsingPackage.sortServices(); + } + // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after + // every activity info has had a chance to set it from its attributes. + setMaxAspectRatio(parsingPackage); + setMinAspectRatio(parsingPackage, callback); + + parsingPackage.setHasDomainUrls(hasDomainURLs(parsingPackage)); + + return parseInput.success(parsingPackage); + } + + private static ParseResult parseUsesStaticLibrary( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestUsesStaticLibrary); + + // Note: don't allow this value to be a reference to a resource that may change. + String lname = sa.getNonResourceString( + R.styleable.AndroidManifestUsesLibrary_name); + final int version = sa.getInt( + R.styleable.AndroidManifestUsesStaticLibrary_version, -1); + String certSha256Digest = sa.getNonResourceString(com.android.internal.R.styleable + .AndroidManifestUsesStaticLibrary_certDigest); + sa.recycle(); + + // Since an APK providing a static shared lib can only provide the lib - fail if malformed + if (lname == null || version < 0 || certSha256Digest == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Bad uses-static-library declaration name: " + lname + " version: " + + version + " certDigest" + certSha256Digest + ); + } + + // Can depend only on one version of the same library + List<String> usesStaticLibraries = parsingPackage.getUsesStaticLibraries(); + if (usesStaticLibraries != null && usesStaticLibraries.contains(lname)) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Depending on multiple versions of static library " + lname + ); + } + + lname = lname.intern(); + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + + // Fot apps targeting O-MR1 we require explicit enumeration of all certs. + String[] additionalCertSha256Digests = EmptyArray.STRING; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.O_MR1) { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + additionalCertSha256Digests = parseAdditionalCertificates(res, parser, outError); + if (additionalCertSha256Digests == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + } else { + XmlUtils.skipCurrentTag(parser); + } + + final String[] certSha256Digests = new String[additionalCertSha256Digests.length + 1]; + certSha256Digests[0] = certSha256Digest; + System.arraycopy(additionalCertSha256Digests, 0, certSha256Digests, + 1, additionalCertSha256Digests.length); + + parsingPackage.addUsesStaticLibrary(lname) + .addUsesStaticLibraryVersion(version) + .addUsesStaticLibraryCertDigests(certSha256Digests); + + return parseInput.success(parsingPackage); + } + + private static String[] parseAdditionalCertificates( + Resources resources, + XmlResourceParser parser, + String[] outError + ) throws XmlPullParserException, IOException { + String[] certSha256Digests = EmptyArray.STRING; + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + final String nodeName = parser.getName(); + if (nodeName.equals("additional-certificate")) { + final TypedArray sa = resources.obtainAttributes(parser, com.android.internal. + R.styleable.AndroidManifestAdditionalCertificate); + String certSha256Digest = sa.getNonResourceString(com.android.internal. + R.styleable.AndroidManifestAdditionalCertificate_certDigest); + sa.recycle(); + + if (TextUtils.isEmpty(certSha256Digest)) { + outError[0] = "Bad additional-certificate declaration with empty" + + " certDigest:" + certSha256Digest; + XmlUtils.skipCurrentTag(parser); + sa.recycle(); + return null; + } + + // We allow ":" delimiters in the SHA declaration as this is the format + // emitted by the certtool making it easy for developers to copy/paste. + certSha256Digest = certSha256Digest.replace(":", "").toLowerCase(); + certSha256Digests = ArrayUtils.appendElement(String.class, + certSha256Digests, certSha256Digest); + } else { + XmlUtils.skipCurrentTag(parser); + } + } + + return certSha256Digests; + } + + /** + * Generate activity object that forwards user to App Details page automatically. + * This activity should be invisible to user and user should not know or see it. + * + * @hide + */ + @NonNull + private static ComponentParseUtils.ParsedActivity generateAppDetailsHiddenActivity( + ParsingPackage parsingPackage, + String[] outError + ) { + String packageName = parsingPackage.getPackageName(); + String processName = parsingPackage.getProcessName(); + boolean hardwareAccelerated = parsingPackage.isBaseHardwareAccelerated(); + int uiOptions = parsingPackage.getUiOptions(); + + // Build custom App Details activity info instead of parsing it from xml + ComponentParseUtils.ParsedActivity activity = new ComponentParseUtils.ParsedActivity(); + activity.setPackageName(packageName); + + activity.theme = android.R.style.Theme_NoDisplay; + activity.exported = true; + activity.className = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME; + activity.setProcessName(processName, processName); + activity.uiOptions = uiOptions; + activity.taskAffinity = PackageParser.buildTaskAffinityName(packageName, + packageName, + ":app_details", outError); + activity.enabled = true; + activity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + activity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NONE; + activity.maxRecents = ActivityTaskManager.getDefaultAppRecentsLimitStatic(); + activity.configChanges = PackageParser.getActivityConfigChanges(0, 0); + activity.softInputMode = 0; + activity.persistableMode = ActivityInfo.PERSIST_NEVER; + activity.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED; + activity.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; + activity.lockTaskLaunchMode = 0; + activity.directBootAware = false; + activity.rotationAnimation = ROTATION_ANIMATION_UNSPECIFIED; + activity.colorMode = ActivityInfo.COLOR_MODE_DEFAULT; + if (hardwareAccelerated) { + activity.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; + } + + return activity; + } + + /** + * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI + */ + private static boolean hasDomainURLs( + ParsingPackage parsingPackage) { + final List<ComponentParseUtils.ParsedActivity> activities = parsingPackage.getActivities(); + final int countActivities = activities.size(); + for (int n = 0; n < countActivities; n++) { + ComponentParseUtils.ParsedActivity activity = activities.get(n); + List<ComponentParseUtils.ParsedActivityIntentInfo> filters = activity.intents; + if (filters == null) continue; + final int countFilters = filters.size(); + for (int m = 0; m < countFilters; m++) { + ComponentParseUtils.ParsedActivityIntentInfo aii = filters.get(m); + if (!aii.hasAction(Intent.ACTION_VIEW)) continue; + if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue; + if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) || + aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { + return true; + } + } + } + return false; + } + + /** + * Sets the max aspect ratio of every child activity that doesn't already have an aspect + * ratio set. + */ + private static void setMaxAspectRatio( + ParsingPackage parsingPackage) { + // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. + // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. + float maxAspectRatio = parsingPackage.getTargetSdkVersion() < O + ? PackageParser.DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; + + float packageMaxAspectRatio = parsingPackage.getMaxAspectRatio(); + if (packageMaxAspectRatio != 0) { + // Use the application max aspect ration as default if set. + maxAspectRatio = packageMaxAspectRatio; + } else { + Bundle appMetaData = parsingPackage.getAppMetaData(); + if (appMetaData != null && appMetaData.containsKey( + PackageParser.METADATA_MAX_ASPECT_RATIO)) { + maxAspectRatio = appMetaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, + maxAspectRatio); + } + } + + if (parsingPackage.getActivities() != null) { + for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) { + // If the max aspect ratio for the activity has already been set, skip. + if (activity.hasMaxAspectRatio()) { + continue; + } + + // By default we prefer to use a values defined on the activity directly than values + // defined on the application. We do not check the styled attributes on the activity + // as it would have already been set when we processed the activity. We wait to + // process the meta data here since this method is called at the end of processing + // the application and all meta data is guaranteed. + final float activityAspectRatio = activity.metaData != null + ? activity.metaData.getFloat(PackageParser.METADATA_MAX_ASPECT_RATIO, + maxAspectRatio) + : maxAspectRatio; + + activity.setMaxAspectRatio(activity.resizeMode, activityAspectRatio); + } + } + } + + /** + * Sets the min aspect ratio of every child activity that doesn't already have an aspect + * ratio set. + */ + private static void setMinAspectRatio( + ParsingPackage parsingPackage, + PackageParser.Callback callback + ) { + final float minAspectRatio; + float packageMinAspectRatio = parsingPackage.getMinAspectRatio(); + if (packageMinAspectRatio != 0) { + // Use the application max aspect ration as default if set. + minAspectRatio = packageMinAspectRatio; + } else { + // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater. + // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD, + // except for watches which always supported 1:1. + minAspectRatio = parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.Q + ? 0 + : (callback != null && callback.hasFeature(FEATURE_WATCH)) + ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH + : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO; + } + + if (parsingPackage.getActivities() != null) { + for (ComponentParseUtils.ParsedActivity activity : parsingPackage.getActivities()) { + if (activity.hasMinAspectRatio()) { + continue; + } + activity.setMinAspectRatio(activity.resizeMode, minAspectRatio); + } + } + } + + private static ParseResult parseOverlay( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + + TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay); + String target = sa.getString( + R.styleable.AndroidManifestResourceOverlay_targetPackage); + String targetName = sa.getString( + R.styleable.AndroidManifestResourceOverlay_targetName); + String category = sa.getString( + R.styleable.AndroidManifestResourceOverlay_category); + int priority = sa.getInt(R.styleable.AndroidManifestResourceOverlay_priority, + 0); + boolean isStatic = sa.getBoolean( + R.styleable.AndroidManifestResourceOverlay_isStatic, false); + + if (target == null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<overlay> does not specify a target package" + ); + } + + if (priority < 0 || priority > 9999) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "<overlay> priority must be between 0 and 9999" + ); + } + + // check to see if overlay should be excluded based on system property condition + String propName = sa.getString( + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName); + String propValue = sa.getString( + R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue); + if (!checkOverlayRequiredSystemProperty(propName, propValue)) { + Slog.i(TAG, "Skipping target and overlay pair " + target + " and " + + parsingPackage.getBaseCodePath() + + ": overlay ignored due to required system property: " + + propName + " with value: " + propValue); + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Skipping target and overlay pair " + target + " and " + + parsingPackage.getBaseCodePath() + + ": overlay ignored due to required system property: " + + propName + " with value: " + propValue + ); + } + + parsingPackage + .setIsOverlay(true) + .setOverlayTarget(target) + .setOverlayTargetName(targetName) + .setOverlayCategory(category) + .setOverlayPriority(priority) + .setOverlayIsStatic(isStatic); + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + return parseInput.success(parsingPackage); + } + + private static boolean parseProtectedBroadcast( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestProtectedBroadcast); + + // Note: don't allow this value to be a reference to a resource + // that may change. + String name = sa.getNonResourceString(R.styleable.AndroidManifestProtectedBroadcast_name); + + sa.recycle(); + + if (name != null) { + parsingPackage.addProtectedBroadcast(name); + } + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static boolean parseSupportScreens( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestSupportsScreens); + + int requiresSmallestWidthDp = sa.getInteger( + R.styleable.AndroidManifestSupportsScreens_requiresSmallestWidthDp, + 0); + int compatibleWidthLimitDp = sa.getInteger( + R.styleable.AndroidManifestSupportsScreens_compatibleWidthLimitDp, + 0); + int largestWidthLimitDp = sa.getInteger( + R.styleable.AndroidManifestSupportsScreens_largestWidthLimitDp, + 0); + + // This is a trick to get a boolean and still able to detect + // if a value was actually set. + parsingPackage + .setSupportsSmallScreens( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_smallScreens, 1)) + .setSupportsNormalScreens( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_normalScreens, 1)) + .setSupportsLargeScreens( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_largeScreens, 1)) + .setSupportsXLargeScreens( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_xlargeScreens, 1)) + .setResizeable( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_resizeable, 1)) + .setAnyDensity( + sa.getInteger(R.styleable.AndroidManifestSupportsScreens_anyDensity, 1)) + .setRequiresSmallestWidthDp(requiresSmallestWidthDp) + .setCompatibleWidthLimitDp(compatibleWidthLimitDp) + .setLargestWidthLimitDp(largestWidthLimitDp); + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static ParseResult parseInstrumentation( + ParseInput parseInput, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws XmlPullParserException, IOException { + // TODO(b/135203078): Remove, replace with ParseResult + String[] outError = new String[1]; + + ComponentParseUtils.ParsedInstrumentation parsedInstrumentation = + ComponentParseUtils.parseInstrumentation(parsingPackage, + res, parser, outError); + + if (parsedInstrumentation == null || outError[0] != null) { + return parseInput.error( + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + outError[0] + ); + } + + parsingPackage.addInstrumentation(parsedInstrumentation); + + return parseInput.success(parsingPackage); + } + + private static boolean parseOriginalPackage( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestOriginalPackage); + + String orig = sa.getNonConfigurationString( + R.styleable.AndroidManifestOriginalPackage_name, + 0); + if (!parsingPackage.getPackageName().equals(orig)) { + if (parsingPackage.getOriginalPackages() == null) { + parsingPackage.setRealPackage(parsingPackage.getPackageName()); + } + parsingPackage.addOriginalPackage(orig); + } + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static boolean parseAdoptPermissions( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser + ) throws IOException, XmlPullParserException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestOriginalPackage); + + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestOriginalPackage_name, + 0); + + sa.recycle(); + + if (name != null) { + parsingPackage.addAdoptPermission(name); + } + + XmlUtils.skipCurrentTag(parser); + return true; + } + + private static void convertNewPermissions( + ParsingPackage packageToParse) { + final int NP = PackageParser.NEW_PERMISSIONS.length; + StringBuilder newPermsMsg = null; + for (int ip = 0; ip < NP; ip++) { + final PackageParser.NewPermissionInfo npi + = PackageParser.NEW_PERMISSIONS[ip]; + if (packageToParse.getTargetSdkVersion() >= npi.sdkVersion) { + break; + } + if (!packageToParse.getRequestedPermissions().contains(npi.name)) { + if (newPermsMsg == null) { + newPermsMsg = new StringBuilder(128); + newPermsMsg.append(packageToParse.getPackageName()); + newPermsMsg.append(": compat added "); + } else { + newPermsMsg.append(' '); + } + newPermsMsg.append(npi.name); + packageToParse.addRequestedPermission(npi.name); + packageToParse.addImplicitPermission(npi.name); + } + } + if (newPermsMsg != null) { + Slog.i(TAG, newPermsMsg.toString()); + } + } + + private static void convertSplitPermissions(ParsingPackage packageToParse) { + List<SplitPermissionInfoParcelable> splitPermissions; + + try { + splitPermissions = ActivityThread.getPermissionManager().getSplitPermissions(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + final int listSize = splitPermissions.size(); + for (int is = 0; is < listSize; is++) { + final SplitPermissionInfoParcelable spi = splitPermissions.get(is); + List<String> requestedPermissions = packageToParse.getRequestedPermissions(); + if (packageToParse.getTargetSdkVersion() >= spi.getTargetSdk() + || !requestedPermissions.contains(spi.getSplitPermission())) { + continue; + } + final List<String> newPerms = spi.getNewPermissions(); + for (int in = 0; in < newPerms.size(); in++) { + final String perm = newPerms.get(in); + if (!requestedPermissions.contains(perm)) { + packageToParse.addRequestedPermission(perm); + packageToParse.addImplicitPermission(perm); + } + } + } + } + + private static boolean checkOverlayRequiredSystemProperty(String propName, String propValue) { + if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) { + if (!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue)) { + // malformed condition - incomplete + Slog.w(TAG, "Disabling overlay - incomplete property :'" + propName + + "=" + propValue + "' - require both requiredSystemPropertyName" + + " AND requiredSystemPropertyValue to be specified."); + return false; + } + // no valid condition set - so no exclusion criteria, overlay will be included. + return true; + } + + // check property value - make sure it is both set and equal to expected value + final String currValue = SystemProperties.get(propName); + return (currValue != null && currValue.equals(propValue)); + } + + /** + * This is a pre-density application which will get scaled - instead of being pixel perfect. + * This type of application is not resizable. + * + * @param parsingPackage The package which needs to be marked as unresizable. + */ + private static void adjustPackageToBeUnresizeableAndUnpipable( + ParsingPackage parsingPackage) { + if (parsingPackage.getActivities() != null) { + for (ComponentParseUtils.ParsedActivity a : parsingPackage.getActivities()) { + a.resizeMode = RESIZE_MODE_UNRESIZEABLE; + a.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE; + } + } + } + + private static String validateName(String name, boolean requireSeparator, + boolean requireFilename) { + final int N = name.length(); + boolean hasSep = false; + boolean front = true; + for (int i = 0; i < N; i++) { + final char c = name.charAt(i); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + front = false; + continue; + } + if (!front) { + if ((c >= '0' && c <= '9') || c == '_') { + continue; + } + } + if (c == '.') { + hasSep = true; + front = true; + continue; + } + return "bad character '" + c + "'"; + } + if (requireFilename && !FileUtils.isValidExtFilename(name)) { + return "Invalid filename"; + } + return hasSep || !requireSeparator + ? null : "must have at least one '.' separator"; + } + + public static Bundle parseMetaData( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, Bundle data, String[] outError) + throws XmlPullParserException, IOException { + + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestMetaData); + + if (data == null) { + data = new Bundle(); + } + + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestMetaData_name, 0); + if (name == null) { + outError[0] = "<meta-data> requires an android:name attribute"; + sa.recycle(); + return null; + } + + name = name.intern(); + + TypedValue v = sa.peekValue( + R.styleable.AndroidManifestMetaData_resource); + if (v != null && v.resourceId != 0) { + //Slog.i(TAG, "Meta data ref " + name + ": " + v); + data.putInt(name, v.resourceId); + } else { + v = sa.peekValue( + R.styleable.AndroidManifestMetaData_value); + //Slog.i(TAG, "Meta data " + name + ": " + v); + if (v != null) { + if (v.type == TypedValue.TYPE_STRING) { + CharSequence cs = v.coerceToString(); + data.putString(name, cs != null ? cs.toString() : null); + } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { + data.putBoolean(name, v.data != 0); + } else if (v.type >= TypedValue.TYPE_FIRST_INT + && v.type <= TypedValue.TYPE_LAST_INT) { + data.putInt(name, v.data); + } else if (v.type == TypedValue.TYPE_FLOAT) { + data.putFloat(name, v.getFloat()); + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, + "<meta-data> only supports string, integer, float, color, " + + "boolean, and resource reference types: " + + parser.getName() + " at " + + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + outError[0] = + "<meta-data> only supports string, integer, float, color, " + + "boolean, and resource reference types"; + data = null; + } + } + } else { + outError[0] = "<meta-data> requires an android:value or android:resource attribute"; + data = null; + } + } + + sa.recycle(); + + XmlUtils.skipCurrentTag(parser); + + return data; + } + + /** + * Collect certificates from all the APKs described in the given package, + * populating {@link AndroidPackageWrite#setSigningDetails(SigningDetails)}. Also asserts that + * all APK contents are signed correctly and consistently. + */ + public static void collectCertificates(AndroidPackage pkg, boolean skipVerify) + throws PackageParserException { + pkg.mutate().setSigningDetails(SigningDetails.UNKNOWN); + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); + try { + pkg.mutate().setSigningDetails(collectCertificates( + pkg.getBaseCodePath(), + skipVerify, + pkg.isStaticSharedLibrary(), + pkg.getSigningDetails() + )); + + String[] splitCodePaths = pkg.getSplitCodePaths(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + pkg.mutate().setSigningDetails(collectCertificates( + splitCodePaths[i], + skipVerify, + pkg.isStaticSharedLibrary(), + pkg.getSigningDetails() + )); + } + } + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + public static SigningDetails collectCertificates( + String baseCodePath, + boolean skipVerify, + boolean isStaticSharedLibrary, + @NonNull SigningDetails existingSigningDetails + ) throws PackageParserException { + int minSignatureScheme = SigningDetails.SignatureSchemeVersion.JAR; + if (isStaticSharedLibrary) { + // must use v2 signing scheme + minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2; + } + SigningDetails verified; + if (skipVerify) { + // systemDir APKs are already trusted, save time by not verifying + verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification( + baseCodePath, minSignatureScheme); + } else { + verified = ApkSignatureVerifier.verify(baseCodePath, minSignatureScheme); + } + + // Verify that entries are signed consistently with the first pkg + // we encountered. Note that for splits, certificates may have + // already been populated during an earlier parse of a base APK. + if (existingSigningDetails == SigningDetails.UNKNOWN) { + return verified; + } else { + if (!Signature.areExactMatch(existingSigningDetails.signatures, verified.signatures)) { + throw new PackageParserException( + INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, + baseCodePath + " has mismatched certificates"); + } + + return existingSigningDetails; + } + } + + @Nullable + public static String buildClassName(String pkg, CharSequence clsSeq) { + if (clsSeq == null || clsSeq.length() <= 0) { + return null; + } + String cls = clsSeq.toString(); + char c = cls.charAt(0); + if (c == '.') { + return pkg + cls; + } + if (cls.indexOf('.') < 0) { + StringBuilder b = new StringBuilder(pkg); + b.append('.'); + b.append(cls); + return b.toString(); + } + return cls; + } + + public interface ParseInput { + ParseResult success(ParsingPackage result); + + ParseResult error(int parseError); + + ParseResult error(int parseError, String errorMessage); + } + + public static class ParseResult implements ParseInput { + + private static final boolean DEBUG_FILL_STACK_TRACE = false; + + private ParsingPackage result; + + private int parseError; + private String errorMessage; + + public ParseInput reset() { + this.result = null; + this.parseError = PackageManager.INSTALL_SUCCEEDED; + this.errorMessage = null; + return this; + } + + @Override + public ParseResult success(ParsingPackage result) { + if (parseError != PackageManager.INSTALL_SUCCEEDED || errorMessage != null) { + throw new IllegalStateException("Cannot set to success after set to error"); + } + this.result = result; + return this; + } + + @Override + public ParseResult error(int parseError) { + return error(parseError, null); + } + + @Override + public ParseResult error(int parseError, String errorMessage) { + this.parseError = parseError; + this.errorMessage = errorMessage; + + if (DEBUG_FILL_STACK_TRACE) { + this.errorMessage += Arrays.toString(new Exception().getStackTrace()); + } + + return this; + } + + public ParsingPackage getResultAndNull() { + ParsingPackage result = this.result; + this.result = null; + return result; + } + + public boolean isSuccess() { + return parseError == PackageManager.INSTALL_SUCCEEDED; + } + + public int getParseError() { + return parseError; + } + + public String getErrorMessage() { + return errorMessage; + } + } +} diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java new file mode 100644 index 000000000000..adf2a4f85780 --- /dev/null +++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java @@ -0,0 +1,3289 @@ +/* + * Copyright (C) 2019 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.parsing; + +import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; +import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED; + +import android.annotation.CallSuper; +import android.annotation.UnsupportedAppUsage; +import android.app.ActivityTaskManager; +import android.content.ComponentName; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PathPermission; +import android.content.pm.PermissionInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.PatternMatcher; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.util.SparseArray; +import android.util.TypedValue; +import android.view.Gravity; + +import com.android.internal.R; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +/** + * TODO(b/135203078): Move the inner classes out to separate files. + * TODO(b/135203078): Expose inner classes as immutable through interface methods. + * + * @hide + */ +public class ComponentParseUtils { + + private static final String TAG = ApkParseUtils.TAG; + + // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base? + public static class ParsedIntentInfo extends IntentFilter { + + /** + * <p> + * Implementation note: The serialized form for the intent list also contains the name + * of the concrete class that's stored in the list, and assumes that every element of the + * list is of the same type. This is very similar to the original parcelable mechanism. + * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable + * and is public API. It also declares Parcelable related methods as final which means + * we can't extend them. The approach of using composition instead of inheritance leads to + * a large set of cascading changes in the PackageManagerService, which seem undesirable. + * + * <p> + * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up + * to make sure their owner fields are consistent. See {@code fixupOwner}. + */ + public static void writeIntentsList(List<? extends ParsedIntentInfo> list, Parcel out, + int flags) { + if (list == null) { + out.writeInt(-1); + return; + } + + final int size = list.size(); + out.writeInt(size); + + // Don't bother writing the component name if the list is empty. + if (size > 0) { + ParsedIntentInfo info = list.get(0); + out.writeString(info.getClass().getName()); + + for (int i = 0; i < size; i++) { + list.get(i).writeIntentInfoToParcel(out, flags); + } + } + } + + public static <T extends ParsedIntentInfo> ArrayList<T> createIntentsList(Parcel in) { + int size = in.readInt(); + if (size == -1) { + return null; + } + + if (size == 0) { + return new ArrayList<>(0); + } + + String className = in.readString(); + final ArrayList<T> intentsList; + try { + final Class<T> cls = (Class<T>) Class.forName(className); + final Constructor<T> cons = cls.getConstructor(Parcel.class); + + intentsList = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + intentsList.add(cons.newInstance(in)); + } + } catch (ReflectiveOperationException ree) { + throw new AssertionError("Unable to construct intent list for: " + + className, ree); + } + + return intentsList; + } + + protected String packageName; + protected final String className; + + public boolean hasDefault; + public int labelRes; + public CharSequence nonLocalizedLabel; + public int icon; + + protected List<String> rawDataTypes; + + public void addRawDataType(String dataType) throws MalformedMimeTypeException { + if (rawDataTypes == null) { + rawDataTypes = new ArrayList<>(); + } + + rawDataTypes.add(dataType); + addDataType(dataType); + } + + public ParsedIntentInfo(String packageName, String className) { + this.packageName = packageName; + this.className = className; + } + + public ParsedIntentInfo(Parcel in) { + super(in); + packageName = in.readString(); + className = in.readString(); + hasDefault = (in.readInt() == 1); + labelRes = in.readInt(); + nonLocalizedLabel = in.readCharSequence(); + icon = in.readInt(); + } + + public void writeIntentInfoToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(packageName); + dest.writeString(className); + dest.writeInt(hasDefault ? 1 : 0); + dest.writeInt(labelRes); + dest.writeCharSequence(nonLocalizedLabel); + dest.writeInt(icon); + } + + public String getPackageName() { + return packageName; + } + + public String getClassName() { + return className; + } + } + + public static class ParsedActivityIntentInfo extends ParsedIntentInfo { + + public ParsedActivityIntentInfo(String packageName, String className) { + super(packageName, className); + } + + public ParsedActivityIntentInfo(Parcel in) { + super(in); + } + + public static final Creator<ParsedActivityIntentInfo> CREATOR = + new Creator<ParsedActivityIntentInfo>() { + @Override + public ParsedActivityIntentInfo createFromParcel(Parcel source) { + return new ParsedActivityIntentInfo(source); + } + + @Override + public ParsedActivityIntentInfo[] newArray(int size) { + return new ParsedActivityIntentInfo[size]; + } + }; + } + + public static class ParsedServiceIntentInfo extends ParsedIntentInfo { + + public ParsedServiceIntentInfo(String packageName, String className) { + super(packageName, className); + } + + public ParsedServiceIntentInfo(Parcel in) { + super(in); + } + + public static final Creator<ParsedServiceIntentInfo> CREATOR = + new Creator<ParsedServiceIntentInfo>() { + @Override + public ParsedServiceIntentInfo createFromParcel(Parcel source) { + return new ParsedServiceIntentInfo(source); + } + + @Override + public ParsedServiceIntentInfo[] newArray(int size) { + return new ParsedServiceIntentInfo[size]; + } + }; + } + + public static class ParsedProviderIntentInfo extends ParsedIntentInfo { + + public ParsedProviderIntentInfo(String packageName, String className) { + super(packageName, className); + } + + public ParsedProviderIntentInfo(Parcel in) { + super(in); + } + + public static final Creator<ParsedProviderIntentInfo> CREATOR = + new Creator<ParsedProviderIntentInfo>() { + @Override + public ParsedProviderIntentInfo createFromParcel(Parcel source) { + return new ParsedProviderIntentInfo(source); + } + + @Override + public ParsedProviderIntentInfo[] newArray(int size) { + return new ParsedProviderIntentInfo[size]; + } + }; + } + + public static class ParsedQueriesIntentInfo extends ParsedIntentInfo { + + public ParsedQueriesIntentInfo(String packageName, String className) { + super(packageName, className); + } + + public ParsedQueriesIntentInfo(Parcel in) { + super(in); + } + + public static final Creator<ParsedQueriesIntentInfo> CREATOR = + new Creator<ParsedQueriesIntentInfo>() { + @Override + public ParsedQueriesIntentInfo createFromParcel(Parcel source) { + return new ParsedQueriesIntentInfo(source); + } + + @Override + public ParsedQueriesIntentInfo[] newArray(int size) { + return new ParsedQueriesIntentInfo[size]; + } + }; + } + + public static class ParsedComponent<IntentInfoType extends ParsedIntentInfo> implements + Parcelable { + + // TODO(b/135203078): Replace with "name", as not all usages are an actual class + public String className; + public int icon; + public int labelRes; + public CharSequence nonLocalizedLabel; + public int logo; + public int banner; + + public int descriptionRes; + + // TODO(b/135203078): Make subclass that contains these fields only for the necessary + // subtypes + protected boolean enabled = true; + protected boolean directBootAware; + public int flags; + + private String packageName; + private String splitName; + + // TODO(b/135203078): Make nullable + public List<IntentInfoType> intents = new ArrayList<>(); + + private transient ComponentName componentName; + + protected Bundle metaData; + + public void setSplitName(String splitName) { + this.splitName = splitName; + } + + public String getSplitName() { + return splitName; + } + + @CallSuper + public void setPackageName(String packageName) { + this.packageName = packageName; + this.componentName = null; + } + + void setPackageNameInternal(String packageName) { + this.packageName = packageName; + this.componentName = null; + } + + public String getPackageName() { + return packageName; + } + + public final boolean isDirectBootAware() { + return directBootAware; + } + + public final boolean isEnabled() { + return enabled; + } + + public final String getName() { + return className; + } + + public final Bundle getMetaData() { + return metaData; + } + + @UnsupportedAppUsage + public ComponentName getComponentName() { + if (componentName != null) { + return componentName; + } + if (className != null) { + componentName = new ComponentName(getPackageName(), + className); + } + return componentName; + } + + public void setFrom(ParsedComponent other) { + this.metaData = other.metaData; + this.className = other.className; + this.icon = other.icon; + this.labelRes = other.labelRes; + this.nonLocalizedLabel = other.nonLocalizedLabel; + this.logo = other.logo; + this.banner = other.banner; + + this.descriptionRes = other.descriptionRes; + + this.enabled = other.enabled; + this.directBootAware = other.directBootAware; + this.flags = other.flags; + + this.setPackageName(other.packageName); + this.setSplitName(other.getSplitName()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.className); + dest.writeInt(this.icon); + dest.writeInt(this.labelRes); + dest.writeCharSequence(this.nonLocalizedLabel); + dest.writeInt(this.logo); + dest.writeInt(this.banner); + dest.writeInt(this.descriptionRes); + dest.writeBoolean(this.enabled); + dest.writeBoolean(this.directBootAware); + dest.writeInt(this.flags); + dest.writeString(this.packageName); + dest.writeString(this.splitName); + ParsedIntentInfo.writeIntentsList(this.intents, dest, flags); + dest.writeBundle(this.metaData); + } + + public ParsedComponent() { + } + + protected ParsedComponent(Parcel in) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.className = in.readString(); + this.icon = in.readInt(); + this.labelRes = in.readInt(); + this.nonLocalizedLabel = in.readCharSequence(); + this.logo = in.readInt(); + this.banner = in.readInt(); + this.descriptionRes = in.readInt(); + this.enabled = in.readByte() != 0; + this.directBootAware = in.readByte() != 0; + this.flags = in.readInt(); + this.packageName = in.readString(); + this.splitName = in.readString(); + this.intents = ParsedIntentInfo.createIntentsList(in); + this.metaData = in.readBundle(boot); + } + } + + // TODO(b/135203078): Document this. Maybe split out ParsedComponent to be actual components + // that can have their own processes, rather than something like permission which cannot. + public static class ParsedMainComponent<IntentInfoType extends ParsedIntentInfo> extends + ParsedComponent<IntentInfoType> { + + private String processName; + private String permission; + + public void setProcessName(String appProcessName, String processName) { + // TODO(b/135203078): Is this even necessary anymore? + this.processName = TextUtils.safeIntern( + processName == null ? appProcessName : processName); + } + + public String getProcessName() { + return processName; + } + + public void setPermission(String permission) { + this.permission = TextUtils.safeIntern(permission); + } + + public String getPermission() { + return permission; + } + + @Override + public void setFrom(ParsedComponent other) { + super.setFrom(other); + if (other instanceof ParsedMainComponent) { + ParsedMainComponent otherMainComponent = (ParsedMainComponent) other; + this.setProcessName(otherMainComponent.getProcessName(), + otherMainComponent.getProcessName()); + this.setPermission(otherMainComponent.getPermission()); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.processName); + dest.writeString(this.permission); + } + + public ParsedMainComponent() { + } + + protected ParsedMainComponent(Parcel in) { + super(in); + this.processName = TextUtils.safeIntern(in.readString()); + this.permission = TextUtils.safeIntern(in.readString()); + } + + public static final Creator<ParsedMainComponent> CREATOR = + new Creator<ParsedMainComponent>() { + @Override + public ParsedMainComponent createFromParcel(Parcel source) { + return new ParsedMainComponent(source); + } + + @Override + public ParsedMainComponent[] newArray(int size) { + return new ParsedMainComponent[size]; + } + }; + } + + public static class ParsedActivity extends ParsedMainComponent<ParsedActivityIntentInfo> + implements Parcelable { + + public boolean exported; + public int theme; + public int uiOptions; + + public String targetActivity; + + public String parentActivityName; + public String taskAffinity; + public int privateFlags; + + public int launchMode; + public int documentLaunchMode; + public int maxRecents; + public int configChanges; + public int softInputMode; + public int persistableMode; + public int lockTaskLaunchMode; + + public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; + public int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + + public float maxAspectRatio; + public boolean hasMaxAspectRatio; + + public float minAspectRatio; + public boolean hasMinAspectRatio; + + public String requestedVrComponent; + public int rotationAnimation = -1; + public int colorMode; + public int order; + + public ActivityInfo.WindowLayout windowLayout; + + @Override + public void setPackageName(String packageName) { + super.setPackageName(packageName); + for (ParsedIntentInfo intent : this.intents) { + intent.packageName = packageName; + } + } + + public boolean hasMaxAspectRatio() { + return hasMaxAspectRatio; + } + + public boolean hasMinAspectRatio() { + return hasMinAspectRatio; + } + + public void setMaxAspectRatio(int resizeMode, float maxAspectRatio) { + if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE + || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { + // Resizeable activities can be put in any aspect ratio. + return; + } + + if (maxAspectRatio < 1.0f && maxAspectRatio != 0) { + // Ignore any value lesser than 1.0. + return; + } + + this.maxAspectRatio = maxAspectRatio; + hasMaxAspectRatio = true; + } + + public void setMinAspectRatio(int resizeMode, float minAspectRatio) { + if (resizeMode == RESIZE_MODE_RESIZEABLE + || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { + // Resizeable activities can be put in any aspect ratio. + return; + } + + if (minAspectRatio < 1.0f && minAspectRatio != 0) { + // Ignore any value lesser than 1.0. + return; + } + + this.minAspectRatio = minAspectRatio; + hasMinAspectRatio = true; + } + + public void addIntent(ParsedActivityIntentInfo intent) { + this.intents.add(intent); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeBoolean(this.exported); + dest.writeInt(this.theme); + dest.writeInt(this.uiOptions); + dest.writeString(this.targetActivity); + dest.writeString(this.parentActivityName); + dest.writeString(this.taskAffinity); + dest.writeInt(this.privateFlags); + dest.writeInt(this.launchMode); + dest.writeInt(this.documentLaunchMode); + dest.writeInt(this.maxRecents); + dest.writeInt(this.configChanges); + dest.writeInt(this.softInputMode); + dest.writeInt(this.persistableMode); + dest.writeInt(this.lockTaskLaunchMode); + dest.writeInt(this.screenOrientation); + dest.writeInt(this.resizeMode); + dest.writeFloat(this.maxAspectRatio); + dest.writeBoolean(this.hasMaxAspectRatio); + dest.writeFloat(this.minAspectRatio); + dest.writeBoolean(this.hasMinAspectRatio); + dest.writeString(this.requestedVrComponent); + dest.writeInt(this.rotationAnimation); + dest.writeInt(this.colorMode); + dest.writeInt(this.order); + dest.writeBundle(this.metaData); + + if (windowLayout != null) { + dest.writeInt(1); + dest.writeInt(windowLayout.width); + dest.writeFloat(windowLayout.widthFraction); + dest.writeInt(windowLayout.height); + dest.writeFloat(windowLayout.heightFraction); + dest.writeInt(windowLayout.gravity); + dest.writeInt(windowLayout.minWidth); + dest.writeInt(windowLayout.minHeight); + } else { + dest.writeInt(0); + } + } + + public ParsedActivity() { + } + + protected ParsedActivity(Parcel in) { + super(in); + this.exported = in.readByte() != 0; + this.theme = in.readInt(); + this.uiOptions = in.readInt(); + this.targetActivity = in.readString(); + this.parentActivityName = in.readString(); + this.taskAffinity = in.readString(); + this.privateFlags = in.readInt(); + this.launchMode = in.readInt(); + this.documentLaunchMode = in.readInt(); + this.maxRecents = in.readInt(); + this.configChanges = in.readInt(); + this.softInputMode = in.readInt(); + this.persistableMode = in.readInt(); + this.lockTaskLaunchMode = in.readInt(); + this.screenOrientation = in.readInt(); + this.resizeMode = in.readInt(); + this.maxAspectRatio = in.readFloat(); + this.hasMaxAspectRatio = in.readByte() != 0; + this.minAspectRatio = in.readFloat(); + this.hasMinAspectRatio = in.readByte() != 0; + this.requestedVrComponent = in.readString(); + this.rotationAnimation = in.readInt(); + this.colorMode = in.readInt(); + this.order = in.readInt(); + this.metaData = in.readBundle(); + if (in.readInt() == 1) { + windowLayout = new ActivityInfo.WindowLayout(in); + } + } + + public static final Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() { + @Override + public ParsedActivity createFromParcel(Parcel source) { + return new ParsedActivity(source); + } + + @Override + public ParsedActivity[] newArray(int size) { + return new ParsedActivity[size]; + } + }; + } + + public static class ParsedService extends ParsedMainComponent<ParsedServiceIntentInfo> { + + public boolean exported; + public int flags; + public int foregroundServiceType; + public int order; + + @Override + public void setPackageName(String packageName) { + super.setPackageName(packageName); + for (ParsedIntentInfo intent : this.intents) { + intent.packageName = packageName; + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeBoolean(this.exported); + dest.writeBundle(this.metaData); + dest.writeInt(this.flags); + dest.writeInt(this.foregroundServiceType); + dest.writeInt(this.order); + } + + public ParsedService() { + } + + protected ParsedService(Parcel in) { + super(in); + this.exported = in.readByte() != 0; + this.metaData = in.readBundle(); + this.flags = in.readInt(); + this.foregroundServiceType = in.readInt(); + this.order = in.readInt(); + } + + public static final Creator<ParsedService> CREATOR = new Creator<ParsedService>() { + @Override + public ParsedService createFromParcel(Parcel source) { + return new ParsedService(source); + } + + @Override + public ParsedService[] newArray(int size) { + return new ParsedService[size]; + } + }; + } + + public static class ParsedProvider extends ParsedMainComponent<ParsedProviderIntentInfo> { + + protected boolean exported; + protected int flags; + protected int order; + private String authority; + protected boolean isSyncable; + private String readPermission; + private String writePermission; + protected boolean grantUriPermissions; + protected boolean forceUriPermissions; + protected boolean multiProcess; + protected int initOrder; + protected PatternMatcher[] uriPermissionPatterns; + protected PathPermission[] pathPermissions; + + protected void setFrom(ParsedProvider other) { + super.setFrom(other); + this.exported = other.exported; + + this.intents.clear(); + if (other.intents != null) { + this.intents.addAll(other.intents); + } + + this.flags = other.flags; + this.order = other.order; + this.setAuthority(other.getAuthority()); + this.isSyncable = other.isSyncable; + this.setReadPermission(other.getReadPermission()); + this.setWritePermission(other.getWritePermission()); + this.grantUriPermissions = other.grantUriPermissions; + this.forceUriPermissions = other.forceUriPermissions; + this.multiProcess = other.multiProcess; + this.initOrder = other.initOrder; + this.uriPermissionPatterns = other.uriPermissionPatterns; + this.pathPermissions = other.pathPermissions; + } + + @Override + public void setPackageName(String packageName) { + super.setPackageName(packageName); + for (ParsedIntentInfo intent : this.intents) { + intent.packageName = packageName; + } + } + + public boolean isExported() { + return exported; + } + + public List<ParsedProviderIntentInfo> getIntents() { + return intents; + } + + public int getFlags() { + return flags; + } + + public int getOrder() { + return order; + } + + public void setAuthority(String authority) { + this.authority = TextUtils.safeIntern(authority); + } + + public String getAuthority() { + return authority; + } + + public boolean isSyncable() { + return isSyncable; + } + + public void setReadPermission(String readPermission) { + this.readPermission = TextUtils.safeIntern(readPermission); + } + + public String getReadPermission() { + return readPermission; + } + + public void setWritePermission(String writePermission) { + this.writePermission = TextUtils.safeIntern(writePermission); + } + + public String getWritePermission() { + return writePermission; + } + + public boolean isGrantUriPermissions() { + return grantUriPermissions; + } + + public boolean isForceUriPermissions() { + return forceUriPermissions; + } + + public boolean isMultiProcess() { + return multiProcess; + } + + public int getInitOrder() { + return initOrder; + } + + public PatternMatcher[] getUriPermissionPatterns() { + return uriPermissionPatterns; + } + + public PathPermission[] getPathPermissions() { + return pathPermissions; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeBoolean(this.exported); + dest.writeInt(this.flags); + dest.writeInt(this.order); + dest.writeString(this.authority); + dest.writeBoolean(this.isSyncable); + dest.writeString(this.readPermission); + dest.writeString(this.writePermission); + dest.writeBoolean(this.grantUriPermissions); + dest.writeBoolean(this.forceUriPermissions); + dest.writeBoolean(this.multiProcess); + dest.writeInt(this.initOrder); + dest.writeTypedArray(this.uriPermissionPatterns, flags); + dest.writeTypedArray(this.pathPermissions, flags); + } + + public ParsedProvider() { + } + + protected ParsedProvider(Parcel in) { + super(in); + this.exported = in.readByte() != 0; + this.flags = in.readInt(); + this.order = in.readInt(); + this.authority = TextUtils.safeIntern(in.readString()); + this.isSyncable = in.readByte() != 0; + this.readPermission = TextUtils.safeIntern(in.readString()); + this.writePermission = TextUtils.safeIntern(in.readString()); + this.grantUriPermissions = in.readByte() != 0; + this.forceUriPermissions = in.readByte() != 0; + this.multiProcess = in.readByte() != 0; + this.initOrder = in.readInt(); + this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR); + this.pathPermissions = in.createTypedArray(PathPermission.CREATOR); + } + + public static final Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() { + @Override + public ParsedProvider createFromParcel(Parcel source) { + return new ParsedProvider(source); + } + + @Override + public ParsedProvider[] newArray(int size) { + return new ParsedProvider[size]; + } + }; + } + + public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> { + + public String backgroundPermission; + private String group; + public int requestRes; + public int protectionLevel; + public boolean tree; + + public ParsedPermissionGroup parsedPermissionGroup; + + public void setName(String className) { + this.className = className; + } + + public void setGroup(String group) { + this.group = TextUtils.safeIntern(group); + } + + public String getGroup() { + return group; + } + + public boolean isRuntime() { + return protectionLevel == PermissionInfo.PROTECTION_DANGEROUS; + } + + public boolean isAppOp() { + return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; + } + + @PermissionInfo.Protection + public int getProtection() { + return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; + } + + public int getProtectionFlags() { + return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE; + } + + public int calculateFootprint() { + int size = getName().length(); + if (nonLocalizedLabel != null) { + size += nonLocalizedLabel.length(); + } + return size; + } + + public ParsedPermission() { + } + + public ParsedPermission(ParsedPermission other) { + // TODO(b/135203078): Better way to copy this? Maybe refactor to the point where copy + // isn't needed. + this.className = other.className; + this.icon = other.icon; + this.labelRes = other.labelRes; + this.nonLocalizedLabel = other.nonLocalizedLabel; + this.logo = other.logo; + this.banner = other.banner; + this.descriptionRes = other.descriptionRes; + this.enabled = other.enabled; + this.directBootAware = other.directBootAware; + this.flags = other.flags; + this.setSplitName(other.getSplitName()); + this.setPackageName(other.getPackageName()); + + this.intents.addAll(other.intents); + + if (other.metaData != null) { + this.metaData = new Bundle(); + this.metaData.putAll(other.metaData); + } + + this.backgroundPermission = other.backgroundPermission; + this.setGroup(other.group); + this.requestRes = other.requestRes; + this.protectionLevel = other.protectionLevel; + this.tree = other.tree; + + this.parsedPermissionGroup = other.parsedPermissionGroup; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.backgroundPermission); + dest.writeString(this.group); + dest.writeInt(this.requestRes); + dest.writeInt(this.protectionLevel); + dest.writeBoolean(this.tree); + dest.writeParcelable(this.parsedPermissionGroup, flags); + } + + protected ParsedPermission(Parcel in) { + super(in); + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.backgroundPermission = in.readString(); + this.group = TextUtils.safeIntern(in.readString()); + this.requestRes = in.readInt(); + this.protectionLevel = in.readInt(); + this.tree = in.readBoolean(); + this.parsedPermissionGroup = in.readParcelable(boot); + } + + public static final Creator<ParsedPermission> CREATOR = new Creator<ParsedPermission>() { + @Override + public ParsedPermission createFromParcel(Parcel source) { + return new ParsedPermission(source); + } + + @Override + public ParsedPermission[] newArray(int size) { + return new ParsedPermission[size]; + } + }; + } + + public static class ParsedPermissionGroup extends ParsedComponent<ParsedIntentInfo> { + + public int requestDetailResourceId; + public int backgroundRequestResourceId; + public int backgroundRequestDetailResourceId; + + public int requestRes; + public int priority; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.requestDetailResourceId); + dest.writeInt(this.backgroundRequestResourceId); + dest.writeInt(this.backgroundRequestDetailResourceId); + dest.writeInt(this.requestRes); + dest.writeInt(this.priority); + } + + public ParsedPermissionGroup() { + } + + protected ParsedPermissionGroup(Parcel in) { + super(in); + this.requestDetailResourceId = in.readInt(); + this.backgroundRequestResourceId = in.readInt(); + this.backgroundRequestDetailResourceId = in.readInt(); + this.requestRes = in.readInt(); + this.priority = in.readInt(); + } + + public static final Creator<ParsedPermissionGroup> CREATOR = + new Creator<ParsedPermissionGroup>() { + @Override + public ParsedPermissionGroup createFromParcel(Parcel source) { + return new ParsedPermissionGroup(source); + } + + @Override + public ParsedPermissionGroup[] newArray(int size) { + return new ParsedPermissionGroup[size]; + } + }; + } + + public static class ParsedInstrumentation extends ParsedComponent<ParsedIntentInfo> { + + private String targetPackage; + private String targetProcesses; + public boolean handleProfiling; + public boolean functionalTest; + + public String sourceDir; + public String publicSourceDir; + public String[] splitNames; + public String[] splitSourceDirs; + public String[] splitPublicSourceDirs; + public SparseArray<int[]> splitDependencies; + public String dataDir; + public String deviceProtectedDataDir; + public String credentialProtectedDataDir; + public String primaryCpuAbi; + public String secondaryCpuAbi; + public String nativeLibraryDir; + public String secondaryNativeLibraryDir; + + public ParsedInstrumentation() { + } + + public void setTargetPackage(String targetPackage) { + this.targetPackage = TextUtils.safeIntern(targetPackage); + } + + public String getTargetPackage() { + return targetPackage; + } + + public void setTargetProcesses(String targetProcesses) { + this.targetProcesses = TextUtils.safeIntern(targetProcesses); + } + + public String getTargetProcesses() { + return targetProcesses; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeString(this.targetPackage); + dest.writeString(this.targetProcesses); + dest.writeBoolean(this.handleProfiling); + dest.writeBoolean(this.functionalTest); + dest.writeString(this.sourceDir); + dest.writeString(this.publicSourceDir); + dest.writeStringArray(this.splitNames); + dest.writeStringArray(this.splitSourceDirs); + dest.writeStringArray(this.splitPublicSourceDirs); + dest.writeSparseArray(this.splitDependencies); + dest.writeString(this.dataDir); + dest.writeString(this.deviceProtectedDataDir); + dest.writeString(this.credentialProtectedDataDir); + dest.writeString(this.primaryCpuAbi); + dest.writeString(this.secondaryCpuAbi); + dest.writeString(this.nativeLibraryDir); + dest.writeString(this.secondaryNativeLibraryDir); + } + + protected ParsedInstrumentation(Parcel in) { + super(in); + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.targetPackage = TextUtils.safeIntern(in.readString()); + this.targetProcesses = TextUtils.safeIntern(in.readString()); + this.handleProfiling = in.readByte() != 0; + this.functionalTest = in.readByte() != 0; + this.sourceDir = in.readString(); + this.publicSourceDir = in.readString(); + this.splitNames = in.createStringArray(); + this.splitSourceDirs = in.createStringArray(); + this.splitPublicSourceDirs = in.createStringArray(); + this.splitDependencies = in.readSparseArray(boot); + this.dataDir = in.readString(); + this.deviceProtectedDataDir = in.readString(); + this.credentialProtectedDataDir = in.readString(); + this.primaryCpuAbi = in.readString(); + this.secondaryCpuAbi = in.readString(); + this.nativeLibraryDir = in.readString(); + this.secondaryNativeLibraryDir = in.readString(); + } + + public static final Creator<ParsedInstrumentation> CREATOR = + new Creator<ParsedInstrumentation>() { + @Override + public ParsedInstrumentation createFromParcel(Parcel source) { + return new ParsedInstrumentation(source); + } + + @Override + public ParsedInstrumentation[] newArray(int size) { + return new ParsedInstrumentation[size]; + } + }; + } + + public static ParsedActivity parseActivity( + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, int flags, String[] outError, + boolean receiver, boolean hardwareAccelerated) + throws XmlPullParserException, IOException { + + TypedArray sa = null; + boolean visibleToEphemeral; + boolean setExported; + + int targetSdkVersion = parsingPackage.getTargetSdkVersion(); + String packageName = parsingPackage.getPackageName(); + String packageProcessName = parsingPackage.getProcessName(); + ParsedActivity result = new ParsedActivity(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity); + + String tag = receiver ? "<receiver>" : "<activity>"; + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_name, 0); + if (name == null) { + outError[0] = tag + " does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = tag + " invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestActivity_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivity_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivity_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivity_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivity_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + CharSequence pname; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString(R.styleable.AndroidManifestActivity_process); + } + + result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, + packageProcessName, pname, + flags, separateProcesses, outError)); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestActivity_description, 0); + + result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivity_enabled, true); + + setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported); + if (setExported) { + result.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported, + false); + } + + result.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0); + + result.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions, + parsingPackage.getUiOptions()); + + String parentName = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivity_parentActivityName, + Configuration.NATIVE_CONFIG_VERSION); + if (parentName != null) { + String parentClassName = ApkParseUtils.buildClassName(packageName, parentName); + if (parentClassName == null) { + Log.e(TAG, + "Activity " + result.className + + " specified invalid parentActivityName " + + parentName); + } else { + result.parentActivityName = parentClassName; + } + } + + String str; + str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0); + if (str == null) { + result.setPermission(parsingPackage.getPermission()); + } else { + result.setPermission(str); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivity_taskAffinity, + Configuration.NATIVE_CONFIG_VERSION); + result.taskAffinity = PackageParser.buildTaskAffinityName( + packageName, + parsingPackage.getTaskAffinity(), str, outError); + + result.setSplitName( + sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0)); + + result.flags = 0; + if (sa.getBoolean( + R.styleable.AndroidManifestActivity_multiprocess, false)) { + result.flags |= ActivityInfo.FLAG_MULTIPROCESS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) { + result.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) { + result.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) { + result.flags |= ActivityInfo.FLAG_NO_HISTORY; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) { + result.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) { + result.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) { + result.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting, + (parsingPackage.getFlags() & ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING) + != 0)) { + result.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs, + false)) { + result.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false) + || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) { + result.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) { + result.flags |= ActivityInfo.FLAG_IMMERSIVE; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) { + result.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY; + } + + boolean directBootAware; + + if (!receiver) { + if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated, + hardwareAccelerated)) { + result.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED; + } + + result.launchMode = sa.getInt( + R.styleable.AndroidManifestActivity_launchMode, + ActivityInfo.LAUNCH_MULTIPLE); + result.documentLaunchMode = sa.getInt( + R.styleable.AndroidManifestActivity_documentLaunchMode, + ActivityInfo.DOCUMENT_LAUNCH_NONE); + result.maxRecents = sa.getInt( + R.styleable.AndroidManifestActivity_maxRecents, + ActivityTaskManager.getDefaultAppRecentsLimitStatic()); + result.configChanges = PackageParser.getActivityConfigChanges( + sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0), + sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0)); + result.softInputMode = sa.getInt( + R.styleable.AndroidManifestActivity_windowSoftInputMode, 0); + + result.persistableMode = sa.getInteger( + R.styleable.AndroidManifestActivity_persistableMode, + ActivityInfo.PERSIST_ROOT_ONLY); + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) { + result.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents, + false)) { + result.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity, + false)) { + result.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) { + result.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING; + } + + int screenOrientation = sa.getInt( + R.styleable.AndroidManifestActivity_screenOrientation, + SCREEN_ORIENTATION_UNSPECIFIED); + result.screenOrientation = screenOrientation; + + int resizeMode = getActivityResizeMode(parsingPackage, sa, screenOrientation); + result.resizeMode = resizeMode; + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, + false)) { + result.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) { + result.flags |= FLAG_ALWAYS_FOCUSABLE; + } + + if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio) + && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio) + == TypedValue.TYPE_FLOAT) { + result.setMaxAspectRatio(resizeMode, + sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio, + 0 /*default*/)); + } + + if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio) + && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio) + == TypedValue.TYPE_FLOAT) { + result.setMinAspectRatio(resizeMode, + sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio, + 0 /*default*/)); + } + + result.lockTaskLaunchMode = + sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0); + + directBootAware = sa.getBoolean( + R.styleable.AndroidManifestActivity_directBootAware, + false); + + result.requestedVrComponent = + sa.getString(R.styleable.AndroidManifestActivity_enableVrMode); + + result.rotationAnimation = + sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation, + ROTATION_ANIMATION_UNSPECIFIED); + + result.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, + ActivityInfo.COLOR_MODE_DEFAULT); + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) { + result.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) { + result.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked, + false)) { + result.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED; + } + } else { + result.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + result.configChanges = 0; + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) { + result.flags |= ActivityInfo.FLAG_SINGLE_USER; + } + directBootAware = sa.getBoolean( + R.styleable.AndroidManifestActivity_directBootAware, + false); + } + + result.directBootAware = directBootAware; + + if (directBootAware) { + parsingPackage.setPartiallyDirectBootAware(true); + } + + // can't make this final; we may set it later via meta-data + visibleToEphemeral = sa.getBoolean( + R.styleable.AndroidManifestActivity_visibleToInstantApps, false); + if (visibleToEphemeral) { + result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + parsingPackage.setVisibleToInstantApps(true); + } + } finally { + if (sa != null) { + sa.recycle(); + } + } + + + if (receiver && (parsingPackage.getPrivateFlags() + & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { + // A heavy-weight application can not have receives in its main process + if (result.getProcessName().equals(packageName)) { + outError[0] = "Heavy-weight applications can not have receivers in main process"; + return null; + } + } + + if (outError[0] != null) { + return null; + } + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getName().equals("intent-filter")) { + ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName, + result.className); + if (!parseIntentInfo(intentInfo, parsingPackage, res, parser, + true /*allowGlobs*/, + true /*allowAutoVerify*/, outError)) { + return null; + } + if (intentInfo.countActions() == 0) { + Slog.w(TAG, "No actions in intent filter at " + + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + result.order = Math.max(intentInfo.getOrder(), result.order); + result.addIntent(intentInfo); + } + // adjust activity flags when we implicitly expose it via a browsable filter + final int visibility = visibleToEphemeral + ? IntentFilter.VISIBILITY_EXPLICIT + : !receiver && isImplicitlyExposedIntent(intentInfo) + ? IntentFilter.VISIBILITY_IMPLICIT + : IntentFilter.VISIBILITY_NONE; + intentInfo.setVisibilityToInstantApp(visibility); + if (intentInfo.isVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + if (intentInfo.isImplicitlyVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; + } + if (PackageParser.LOG_UNSAFE_BROADCASTS && receiver + && (targetSdkVersion >= Build.VERSION_CODES.O)) { + for (int i = 0; i < intentInfo.countActions(); i++) { + final String action = intentInfo.getAction(i); + if (action == null || !action.startsWith("android.")) continue; + if (!PackageParser.SAFE_BROADCASTS.contains(action)) { + Slog.w(TAG, "Broadcast " + action + " may never be delivered to " + + packageName + " as requested at: " + + parser.getPositionDescription()); + } + } + } + } else if (!receiver && parser.getName().equals("preferred")) { + ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName, + result.className); + if (!parseIntentInfo(intentInfo, parsingPackage, res, parser, + false /*allowGlobs*/, + false /*allowAutoVerify*/, outError)) { + return null; + } + // adjust activity flags when we implicitly expose it via a browsable filter + final int visibility = visibleToEphemeral + ? IntentFilter.VISIBILITY_EXPLICIT + : !receiver && isImplicitlyExposedIntent(intentInfo) + ? IntentFilter.VISIBILITY_IMPLICIT + : IntentFilter.VISIBILITY_NONE; + intentInfo.setVisibilityToInstantApp(visibility); + if (intentInfo.isVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + if (intentInfo.isImplicitlyVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; + } + + if (intentInfo.countActions() == 0) { + Slog.w(TAG, "No actions in preferred at " + + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + parsingPackage.addPreferredActivityFilter(intentInfo); + } + } else if (parser.getName().equals("meta-data")) { + if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + result.metaData, + outError)) == null) { + return null; + } + } else if (!receiver && parser.getName().equals("layout")) { + result.windowLayout = parseLayout(res, parser); + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Problem in package " + parsingPackage.getBaseCodePath() + ":"); + if (receiver) { + Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + Slog.w(TAG, "Unknown element under <activity>: " + parser.getName() + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } + XmlUtils.skipCurrentTag(parser); + continue; + } else { + if (receiver) { + outError[0] = "Bad element under <receiver>: " + parser.getName(); + } else { + outError[0] = "Bad element under <activity>: " + parser.getName(); + } + return null; + } + } + } + + if (!setExported) { + result.exported = result.intents.size() > 0; + } + + return result; + } + + public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) { + return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE) + || intentInfo.hasAction(Intent.ACTION_SEND) + || intentInfo.hasAction(Intent.ACTION_SENDTO) + || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE); + } + + public static int getActivityResizeMode( + ParsingPackage parsingPackage, + TypedArray sa, + int screenOrientation + ) { + int privateFlags = parsingPackage.getPrivateFlags(); + final boolean appExplicitDefault = (privateFlags + & (ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE + | ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0; + + if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity) + || appExplicitDefault) { + // Activity or app explicitly set if it is resizeable or not; + final boolean appResizeable = (privateFlags + & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0; + if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, + appResizeable)) { + return ActivityInfo.RESIZE_MODE_RESIZEABLE; + } else { + return ActivityInfo.RESIZE_MODE_UNRESIZEABLE; + } + } + + if ((privateFlags + & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) + != 0) { + // The activity or app didn't explicitly set the resizing option, however we want to + // make it resize due to the sdk version it is targeting. + return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; + } + + // resize preference isn't set and target sdk version doesn't support resizing apps by + // default. For the app to be resizeable if it isn't fixed orientation or immersive. + if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; + } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; + } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; + } else { + return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; + } + } + + public static ParsedService parseService( + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, int flags, String[] outError + ) throws XmlPullParserException, IOException { + TypedArray sa = null; + boolean visibleToEphemeral; + boolean setExported; + + String packageName = parsingPackage.getPackageName(); + String packageProcessName = parsingPackage.getProcessName(); + ParsedService result = new ParsedService(); + + try { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestService); + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestService_name, 0); + if (name == null) { + outError[0] = "<service> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<service> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestService_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestService_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestService_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestService_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestService_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + CharSequence pname; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString(R.styleable.AndroidManifestService_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString(R.styleable.AndroidManifestService_process); + } + + result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, + packageProcessName, pname, + flags, separateProcesses, outError)); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestService_description, 0); + + result.enabled = sa.getBoolean(R.styleable.AndroidManifestService_enabled, true); + + setExported = sa.hasValue( + R.styleable.AndroidManifestService_exported); + if (setExported) { + result.exported = sa.getBoolean( + R.styleable.AndroidManifestService_exported, false); + } + + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestService_permission, 0); + if (str == null) { + result.setPermission(parsingPackage.getPermission()); + } else { + result.setPermission(str); + } + + result.setSplitName( + sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0)); + + result.foregroundServiceType = sa.getInt( + R.styleable.AndroidManifestService_foregroundServiceType, + ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE); + + result.flags = 0; + if (sa.getBoolean( + R.styleable.AndroidManifestService_stopWithTask, + false)) { + result.flags |= ServiceInfo.FLAG_STOP_WITH_TASK; + } + if (sa.getBoolean( + R.styleable.AndroidManifestService_isolatedProcess, + false)) { + result.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS; + } + if (sa.getBoolean( + R.styleable.AndroidManifestService_externalService, + false)) { + result.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE; + } + if (sa.getBoolean( + R.styleable.AndroidManifestService_useAppZygote, + false)) { + result.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE; + } + if (sa.getBoolean( + R.styleable.AndroidManifestService_singleUser, + false)) { + result.flags |= ServiceInfo.FLAG_SINGLE_USER; + } + + result.directBootAware = sa.getBoolean( + R.styleable.AndroidManifestService_directBootAware, + false); + if (result.directBootAware) { + parsingPackage.setPartiallyDirectBootAware(true); + } + + visibleToEphemeral = sa.getBoolean( + R.styleable.AndroidManifestService_visibleToInstantApps, false); + if (visibleToEphemeral) { + result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; + parsingPackage.setVisibleToInstantApps(true); + } + } finally { + if (sa != null) { + sa.recycle(); + } + } + + if (parsingPackage.cantSaveState()) { + // A heavy-weight application can not have services in its main process + // We can do direct compare because we intern all strings. + if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) { + outError[0] = "Heavy-weight applications can not have services in main process"; + return null; + } + } + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getName().equals("intent-filter")) { + ParsedServiceIntentInfo intent = new ParsedServiceIntentInfo(packageName, + result.className); + if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, + false /*allowAutoVerify*/, + outError)) { + return null; + } + if (visibleToEphemeral) { + intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); + result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + result.order = Math.max(intent.getOrder(), result.order); + result.intents.add(intent); + } else if (parser.getName().equals("meta-data")) { + if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + result.metaData, + outError)) == null) { + return null; + } + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <service>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "Bad element under <service>: " + parser.getName(); + return null; + } + } + } + + if (!setExported) { + result.exported = result.intents.size() > 0; + } + + return result; + } + + public static ParsedProvider parseProvider( + String[] separateProcesses, + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, int flags, String[] outError) + throws XmlPullParserException, IOException { + TypedArray sa = null; + String cpname; + boolean visibleToEphemeral; + + int targetSdkVersion = parsingPackage.getTargetSdkVersion(); + String packageName = parsingPackage.getPackageName(); + String packageProcessName = parsingPackage.getProcessName(); + ParsedProvider result = new ParsedProvider(); + + try { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestProvider); + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_name, 0); + if (name == null) { + outError[0] = "<provider> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<provider> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestProvider_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestProvider_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestProvider_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestProvider_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestProvider_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + CharSequence pname; + if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { + pname = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_process, + Configuration.NATIVE_CONFIG_VERSION); + } else { + // Some older apps have been seen to use a resource reference + // here that on older builds was ignored (with a warning). We + // need to continue to do this for them so they don't break. + pname = sa.getNonResourceString(R.styleable.AndroidManifestProvider_process); + } + + result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName, + packageProcessName, pname, + flags, separateProcesses, outError)); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestProvider_description, 0); + + result.enabled = sa.getBoolean(R.styleable.AndroidManifestProvider_enabled, true); + + boolean providerExportedDefault = false; + + if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { + // For compatibility, applications targeting API level 16 or lower + // should have their content providers exported by default, unless they + // specify otherwise. + providerExportedDefault = true; + } + + result.exported = sa.getBoolean( + R.styleable.AndroidManifestProvider_exported, + providerExportedDefault); + + cpname = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_authorities, 0); + + result.isSyncable = sa.getBoolean( + R.styleable.AndroidManifestProvider_syncable, + false); + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_permission, 0); + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_readPermission, 0); + if (str == null) { + str = permission; + } + if (str == null) { + result.setReadPermission(parsingPackage.getPermission()); + } else { + result.setReadPermission(str); + } + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestProvider_writePermission, 0); + if (str == null) { + str = permission; + } + if (str == null) { + result.setWritePermission(parsingPackage.getPermission()); + } else { + result.setWritePermission(str); + } + + result.grantUriPermissions = sa.getBoolean( + R.styleable.AndroidManifestProvider_grantUriPermissions, + false); + + result.forceUriPermissions = sa.getBoolean( + R.styleable.AndroidManifestProvider_forceUriPermissions, + false); + + result.multiProcess = sa.getBoolean( + R.styleable.AndroidManifestProvider_multiprocess, + false); + + result.initOrder = sa.getInt( + R.styleable.AndroidManifestProvider_initOrder, + 0); + + result.setSplitName( + sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0)); + + result.flags = 0; + + if (sa.getBoolean( + R.styleable.AndroidManifestProvider_singleUser, + false)) { + result.flags |= ProviderInfo.FLAG_SINGLE_USER; + } + + result.directBootAware = sa.getBoolean( + R.styleable.AndroidManifestProvider_directBootAware, + false); + if (result.directBootAware) { + parsingPackage.setPartiallyDirectBootAware(true); + } + + visibleToEphemeral = + sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false); + if (visibleToEphemeral) { + result.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; + parsingPackage.setVisibleToInstantApps(true); + } + } finally { + if (sa != null) { + sa.recycle(); + } + } + + if ((parsingPackage.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) + != 0) { + // A heavy-weight application can not have providers in its main process + if (result.getProcessName().equals(packageName)) { + outError[0] = "Heavy-weight applications can not have providers in main process"; + return null; + } + } + + if (cpname == null) { + outError[0] = "<provider> does not include authorities attribute"; + return null; + } + if (cpname.length() <= 0) { + outError[0] = "<provider> has empty authorities attribute"; + return null; + } + result.setAuthority(cpname); + + if (!parseProviderTags(parsingPackage, res, parser, visibleToEphemeral, result, outError)) { + return null; + } + + return result; + } + + public static ParsedQueriesIntentInfo parsedParsedQueriesIntentInfo( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + ParsedQueriesIntentInfo intentInfo = new ParsedQueriesIntentInfo( + parsingPackage.getPackageName(), + null + ); + if (!parseIntentInfo( + intentInfo, + parsingPackage, + res, + parser, + true /*allowGlobs*/, + true /*allowAutoVerify*/, + outError + )) { + return null; + } + return intentInfo; + } + + private static boolean parseProviderTags( + ParsingPackage parsingPackage, + Resources res, XmlResourceParser parser, + boolean visibleToEphemeral, ParsedProvider outInfo, String[] outError) + throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getName().equals("intent-filter")) { + ParsedProviderIntentInfo intent = new ParsedProviderIntentInfo( + parsingPackage.getPackageName(), outInfo.className); + if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, + false /*allowAutoVerify*/, + outError)) { + return false; + } + if (visibleToEphemeral) { + intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); + outInfo.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + outInfo.order = Math.max(intent.getOrder(), outInfo.order); + outInfo.intents.add(intent); + + } else if (parser.getName().equals("meta-data")) { + Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + outInfo.metaData, outError); + if (metaData == null) { + return false; + } else { + outInfo.metaData = metaData; + } + + } else if (parser.getName().equals("grant-uri-permission")) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestGrantUriPermission); + + PatternMatcher pa = null; + + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_path, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0); + if (str != null) { + pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + sa.recycle(); + + if (pa != null) { + if (outInfo.uriPermissionPatterns == null) { + outInfo.uriPermissionPatterns = new PatternMatcher[1]; + outInfo.uriPermissionPatterns[0] = pa; + } else { + final int N = outInfo.uriPermissionPatterns.length; + PatternMatcher[] newp = new PatternMatcher[N + 1]; + System.arraycopy(outInfo.uriPermissionPatterns, 0, newp, 0, N); + newp[N] = pa; + outInfo.uriPermissionPatterns = newp; + } + outInfo.grantUriPermissions = true; + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <path-permission>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; + return false; + } + } + XmlUtils.skipCurrentTag(parser); + + } else if (parser.getName().equals("path-permission")) { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestPathPermission); + + PathPermission pa = null; + + String permission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_permission, 0); + String readPermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_readPermission, 0); + if (readPermission == null) { + readPermission = permission; + } + String writePermission = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_writePermission, 0); + if (writePermission == null) { + writePermission = permission; + } + + boolean havePerm = false; + if (readPermission != null) { + readPermission = readPermission.intern(); + havePerm = true; + } + if (writePermission != null) { + writePermission = writePermission.intern(); + havePerm = true; + } + + if (!havePerm) { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "No readPermission or writePermssion for <path-permission>"; + return false; + } + } + + String path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_path, 0); + if (path != null) { + pa = new PathPermission(path, + PatternMatcher.PATTERN_LITERAL, readPermission, writePermission); + } + + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathPrefix, 0); + if (path != null) { + pa = new PathPermission(path, + PatternMatcher.PATTERN_PREFIX, readPermission, writePermission); + } + + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathPattern, 0); + if (path != null) { + pa = new PathPermission(path, + PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission); + } + + path = sa.getNonConfigurationString( + R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0); + if (path != null) { + pa = new PathPermission(path, + PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission); + } + + sa.recycle(); + + if (pa != null) { + if (outInfo.pathPermissions == null) { + outInfo.pathPermissions = new PathPermission[1]; + outInfo.pathPermissions[0] = pa; + } else { + final int N = outInfo.pathPermissions.length; + PathPermission[] newp = new PathPermission[N + 1]; + System.arraycopy(outInfo.pathPermissions, 0, newp, 0, N); + newp[N] = pa; + outInfo.pathPermissions = newp; + } + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>"; + return false; + } + XmlUtils.skipCurrentTag(parser); + + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <provider>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "Bad element under <provider>: " + parser.getName(); + return false; + } + } + } + return true; + } + + public static ParsedActivity parseActivityAlias( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError) + throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestActivityAlias); + + String targetActivity = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivityAlias_targetActivity, + Configuration.NATIVE_CONFIG_VERSION); + if (targetActivity == null) { + outError[0] = "<activity-alias> does not specify android:targetActivity"; + sa.recycle(); + return null; + } + + String packageName = parsingPackage.getPackageName(); + targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity); + if (targetActivity == null) { + outError[0] = "Empty class name in package " + packageName; + sa.recycle(); + return null; + } + + ParsedActivity target = null; + + List<ParsedActivity> activities = parsingPackage.getActivities(); + final int NA = activities.size(); + for (int i = 0; i < NA; i++) { + ParsedActivity t = activities.get(i); + if (targetActivity.equals(t.className)) { + target = t; + break; + } + } + + if (target == null) { + outError[0] = "<activity-alias> target activity " + targetActivity + + " not found in manifest with activities = " + parsingPackage.getActivities() + + ", parsedActivities = " + activities; + sa.recycle(); + return null; + } + + ParsedActivity result = new ParsedActivity(); + result.setPackageNameInternal(target.getPackageName()); + result.targetActivity = targetActivity; + result.configChanges = target.configChanges; + result.flags = target.flags; + result.privateFlags = target.privateFlags; + result.icon = target.icon; + result.logo = target.logo; + result.banner = target.banner; + result.labelRes = target.labelRes; + result.nonLocalizedLabel = target.nonLocalizedLabel; + result.launchMode = target.launchMode; + result.lockTaskLaunchMode = target.lockTaskLaunchMode; + result.descriptionRes = target.descriptionRes; + result.screenOrientation = target.screenOrientation; + result.taskAffinity = target.taskAffinity; + result.theme = target.theme; + result.softInputMode = target.softInputMode; + result.uiOptions = target.uiOptions; + result.parentActivityName = target.parentActivityName; + result.maxRecents = target.maxRecents; + result.windowLayout = target.windowLayout; + result.resizeMode = target.resizeMode; + result.maxAspectRatio = target.maxAspectRatio; + result.hasMaxAspectRatio = target.hasMaxAspectRatio; + result.minAspectRatio = target.minAspectRatio; + result.hasMinAspectRatio = target.hasMinAspectRatio; + result.requestedVrComponent = target.requestedVrComponent; + result.directBootAware = target.directBootAware; + + result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName()); + + // Not all attributes from the target ParsedActivity are copied to the alias. + // Careful when adding an attribute and determine whether or not it should be copied. +// result.enabled = target.enabled; +// result.exported = target.exported; +// result.permission = target.permission; +// result.splitName = target.splitName; +// result.documentLaunchMode = target.documentLaunchMode; +// result.persistableMode = target.persistableMode; +// result.rotationAnimation = target.rotationAnimation; +// result.colorMode = target.colorMode; +// result.intents.addAll(target.intents); +// result.order = target.order; +// result.metaData = target.metaData; + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivityAlias_name, + 0); + if (name == null) { + outError[0] = "<activity-alias> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<activity-alias> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestActivityAlias_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivityAlias_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestActivityAlias_description, 0); + + result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivityAlias_enabled, true); + + final boolean setExported = sa.hasValue( + R.styleable.AndroidManifestActivityAlias_exported); + if (setExported) { + result.exported = sa.getBoolean( + R.styleable.AndroidManifestActivityAlias_exported, false); + } + + String str; + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivityAlias_permission, 0); + if (str != null) { + result.setPermission(str); + } + + String parentName = sa.getNonConfigurationString( + R.styleable.AndroidManifestActivityAlias_parentActivityName, + Configuration.NATIVE_CONFIG_VERSION); + if (parentName != null) { + String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(), + parentName); + if (parentClassName == null) { + Log.e(TAG, "Activity alias " + result.className + + " specified invalid parentActivityName " + parentName); + outError[0] = null; + } else { + result.parentActivityName = parentClassName; + } + } + + // TODO add visibleToInstantApps attribute to activity alias + final boolean visibleToEphemeral = + ((result.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0); + + sa.recycle(); + + if (outError[0] != null) { + return null; + } + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals("intent-filter")) { + ParsedActivityIntentInfo intent = new ParsedActivityIntentInfo(packageName, + result.className); + if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/, + true /*allowAutoVerify*/, outError)) { + return null; + } + if (intent.countActions() == 0) { + Slog.w(TAG, "No actions in intent filter at " + + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + } else { + result.order = Math.max(intent.getOrder(), result.order); + result.addIntent(intent); + } + // adjust activity flags when we implicitly expose it via a browsable filter + final int visibility = visibleToEphemeral + ? IntentFilter.VISIBILITY_EXPLICIT + : isImplicitlyExposedIntent(intent) + ? IntentFilter.VISIBILITY_IMPLICIT + : IntentFilter.VISIBILITY_NONE; + intent.setVisibilityToInstantApp(visibility); + if (intent.isVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP; + } + if (intent.isImplicitlyVisibleToInstantApp()) { + result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP; + } + } else if (tagName.equals("meta-data")) { + if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + result.metaData, + outError)) == null) { + return null; + } + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <activity-alias>: " + tagName + + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "Bad element under <activity-alias>: " + tagName; + return null; + } + } + } + + if (!setExported) { + result.exported = result.intents.size() > 0; + } + + return result; + } + + public static ParsedPermission parsePermission( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + TypedArray sa = null; + String packageName = parsingPackage.getPackageName(); + ParsedPermission result = new ParsedPermission(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission); + + String name = sa.getNonConfigurationString(R.styleable.AndroidManifestPermission_name, + 0); + if (name == null) { + outError[0] = "<permission> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<permission> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestPermission_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermission_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermission_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermission_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermission_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestPermission_description, 0); + + if (sa.hasValue( + R.styleable.AndroidManifestPermission_backgroundPermission)) { + if ("android".equals(packageName)) { + result.backgroundPermission = sa.getNonResourceString( + R.styleable + .AndroidManifestPermission_backgroundPermission); + } else { + Slog.w(TAG, packageName + " defines a background permission. Only the " + + "'android' package can do that."); + } + } + + // Note: don't allow this value to be a reference to a resource + // that may change. + result.setGroup(sa.getNonResourceString( + R.styleable.AndroidManifestPermission_permissionGroup)); + + result.requestRes = sa.getResourceId( + R.styleable.AndroidManifestPermission_request, 0); + + result.protectionLevel = sa.getInt( + R.styleable.AndroidManifestPermission_protectionLevel, + PermissionInfo.PROTECTION_NORMAL); + + result.flags = sa.getInt( + R.styleable.AndroidManifestPermission_permissionFlags, 0); + + // For now only platform runtime permissions can be restricted + if (!result.isRuntime() || !"android".equals(result.getPackageName())) { + result.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED; + result.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED; + } else { + // The platform does not get to specify conflicting permissions + if ((result.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0 + && (result.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) { + throw new IllegalStateException("Permission cannot be both soft and hard" + + " restricted: " + result.getName()); + } + } + + } finally { + if (sa != null) { + sa.recycle(); + } + } + + if (result.protectionLevel == -1) { + outError[0] = "<permission> does not specify protectionLevel"; + return null; + } + + result.protectionLevel = PermissionInfo.fixProtectionLevel(result.protectionLevel); + + if (result.getProtectionFlags() != 0) { + if ((result.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0 + && (result.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) + == 0 + && (result.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) != + PermissionInfo.PROTECTION_SIGNATURE) { + outError[0] = "<permission> protectionLevel specifies a non-instant flag but is " + + "not based on signature type"; + return null; + } + } + + boolean success = parseAllMetaData(parsingPackage, res, parser, + "<permission>", result, outError); + if (!success || outError[0] != null) { + return null; + } + + return result; + } + + public static ParsedPermission parsePermissionTree( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + TypedArray sa = null; + String packageName = parsingPackage.getPackageName(); + ParsedPermission result = new ParsedPermission(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree); + + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestPermissionTree_name, 0); + if (name == null) { + outError[0] = "<permission-tree> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<permission-tree> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestPermissionTree_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionTree_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + } finally { + if (sa != null) { + sa.recycle(); + } + } + + int index = result.getName().indexOf('.'); + if (index > 0) { + index = result.getName().indexOf('.', index + 1); + } + if (index < 0) { + outError[0] = + "<permission-tree> name has less than three segments: " + result.getName(); + return null; + } + + result.descriptionRes = 0; + result.requestRes = 0; + result.protectionLevel = PermissionInfo.PROTECTION_NORMAL; + result.tree = true; + + boolean success = parseAllMetaData(parsingPackage, res, parser, + "<permission-tree>", result, outError); + if (!success || outError[0] != null) { + return null; + } + + return result; + } + + public static ParsedPermissionGroup parsePermissionGroup( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + TypedArray sa = null; + String packageName = parsingPackage.getPackageName(); + ParsedPermissionGroup result = new ParsedPermissionGroup(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup); + + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestPermissionGroup_name, 0); + if (name == null) { + outError[0] = "<permission> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<permission> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionGroup_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + result.descriptionRes = sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_description, 0); + + result.requestDetailResourceId = sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_requestDetail, 0); + result.backgroundRequestResourceId = sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_backgroundRequest, + 0); + result.backgroundRequestDetailResourceId = sa.getResourceId( + R.styleable + .AndroidManifestPermissionGroup_backgroundRequestDetail, 0); + + result.requestRes = sa.getResourceId( + R.styleable.AndroidManifestPermissionGroup_request, 0); + result.flags = sa.getInt( + R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags, + 0); + result.priority = sa.getInt( + R.styleable.AndroidManifestPermissionGroup_priority, 0); + + } finally { + if (sa != null) { + sa.recycle(); + } + } + + boolean success = parseAllMetaData(parsingPackage, res, parser, + "<permission-group>", result, outError); + if (!success || outError[0] != null) { + return null; + } + + return result; + } + + public static ParsedInstrumentation parseInstrumentation( + ParsingPackage parsingPackage, + Resources res, + XmlResourceParser parser, + String[] outError + ) throws IOException, XmlPullParserException { + TypedArray sa = null; + String packageName = parsingPackage.getPackageName(); + ParsedInstrumentation result = new ParsedInstrumentation(); + + try { + sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation); + + // TODO(b/135203078): Re-share all of the configuration for this. ParseComponentArgs was + // un-used for this, but can be adjusted and re-added to share all the initial result + // parsing for icon/logo/name/etc in all of these parse methods. + String name = sa.getNonConfigurationString( + R.styleable.AndroidManifestInstrumentation_name, 0); + if (name == null) { + outError[0] = "<instrumentation> does not specify android:name"; + return null; + } else { + String className = ApkParseUtils.buildClassName(packageName, name); + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) { + outError[0] = "<instrumentation> invalid android:name"; + return null; + } else if (className == null) { + outError[0] = "Empty class name in package " + packageName; + return null; + } + + result.className = className; + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestInstrumentation_roundIcon, 0) : 0; + if (roundIconVal != 0) { + result.icon = roundIconVal; + result.nonLocalizedLabel = null; + } else { + int iconVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_icon, 0); + if (iconVal != 0) { + result.icon = iconVal; + result.nonLocalizedLabel = null; + } + } + + int logoVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_logo, 0); + if (logoVal != 0) { + result.logo = logoVal; + } + + int bannerVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_banner, 0); + if (bannerVal != 0) { + result.banner = bannerVal; + } + + TypedValue v = sa.peekValue(R.styleable.AndroidManifestInstrumentation_label); + if (v != null && (result.labelRes = v.resourceId) == 0) { + result.nonLocalizedLabel = v.coerceToString(); + } + + result.setPackageNameInternal(packageName); + + String str; + // Note: don't allow this value to be a reference to a resource + // that may change. + str = sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage); + result.setTargetPackage(str); + + str = sa.getNonResourceString( + R.styleable.AndroidManifestInstrumentation_targetProcesses); + result.setTargetProcesses(str); + result.handleProfiling = sa.getBoolean( + R.styleable.AndroidManifestInstrumentation_handleProfiling, false); + result.functionalTest = sa.getBoolean( + R.styleable.AndroidManifestInstrumentation_functionalTest, false); + + } finally { + if (sa != null) { + sa.recycle(); + } + } + + boolean success = parseAllMetaData(parsingPackage, res, parser, + "<instrumentation>", result, outError); + if (!success || outError[0] != null) { + return null; + } + + return result; + } + + public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) { + TypedArray sw = res.obtainAttributes(attrs, + R.styleable.AndroidManifestLayout); + int width = -1; + float widthFraction = -1f; + int height = -1; + float heightFraction = -1f; + final int widthType = sw.getType( + R.styleable.AndroidManifestLayout_defaultWidth); + if (widthType == TypedValue.TYPE_FRACTION) { + widthFraction = sw.getFraction( + R.styleable.AndroidManifestLayout_defaultWidth, + 1, 1, -1); + } else if (widthType == TypedValue.TYPE_DIMENSION) { + width = sw.getDimensionPixelSize( + R.styleable.AndroidManifestLayout_defaultWidth, + -1); + } + final int heightType = sw.getType( + R.styleable.AndroidManifestLayout_defaultHeight); + if (heightType == TypedValue.TYPE_FRACTION) { + heightFraction = sw.getFraction( + R.styleable.AndroidManifestLayout_defaultHeight, + 1, 1, -1); + } else if (heightType == TypedValue.TYPE_DIMENSION) { + height = sw.getDimensionPixelSize( + R.styleable.AndroidManifestLayout_defaultHeight, + -1); + } + int gravity = sw.getInt( + R.styleable.AndroidManifestLayout_gravity, + Gravity.CENTER); + int minWidth = sw.getDimensionPixelSize( + R.styleable.AndroidManifestLayout_minWidth, + -1); + int minHeight = sw.getDimensionPixelSize( + R.styleable.AndroidManifestLayout_minHeight, + -1); + sw.recycle(); + return new ActivityInfo.WindowLayout(width, widthFraction, + height, heightFraction, gravity, minWidth, minHeight); + } + + public static boolean parseIntentInfo( + ParsedIntentInfo intentInfo, + ParsingPackage parsingPackage, + Resources res, XmlResourceParser parser, boolean allowGlobs, + boolean allowAutoVerify, String[] outError + ) throws XmlPullParserException, IOException { + TypedArray sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestIntentFilter); + + int priority = sa.getInt( + R.styleable.AndroidManifestIntentFilter_priority, 0); + intentInfo.setPriority(priority); + + int order = sa.getInt( + R.styleable.AndroidManifestIntentFilter_order, 0); + intentInfo.setOrder(order); + + TypedValue v = sa.peekValue( + R.styleable.AndroidManifestIntentFilter_label); + if (v != null && (intentInfo.labelRes = v.resourceId) == 0) { + intentInfo.nonLocalizedLabel = v.coerceToString(); + } + + int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId( + R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0; + if (roundIconVal != 0) { + intentInfo.icon = roundIconVal; + } else { + intentInfo.icon = sa.getResourceId( + R.styleable.AndroidManifestIntentFilter_icon, 0); + } + + if (allowAutoVerify) { + intentInfo.setAutoVerify(sa.getBoolean( + R.styleable.AndroidManifestIntentFilter_autoVerify, + false)); + } + + sa.recycle(); + + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + String nodeName = parser.getName(); + if (nodeName.equals("action")) { + String value = parser.getAttributeValue( + PackageParser.ANDROID_RESOURCES, "name"); + if (TextUtils.isEmpty(value)) { + outError[0] = "No value supplied for <android:name>"; + return false; + } + XmlUtils.skipCurrentTag(parser); + + intentInfo.addAction(value); + } else if (nodeName.equals("category")) { + String value = parser.getAttributeValue( + PackageParser.ANDROID_RESOURCES, "name"); + if (TextUtils.isEmpty(value)) { + outError[0] = "No value supplied for <android:name>"; + return false; + } + XmlUtils.skipCurrentTag(parser); + + intentInfo.addCategory(value); + + } else if (nodeName.equals("data")) { + sa = res.obtainAttributes(parser, + R.styleable.AndroidManifestData); + + String str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_mimeType, 0); + if (str != null) { + try { + intentInfo.addRawDataType(str); + } catch (IntentFilter.MalformedMimeTypeException e) { + outError[0] = e.toString(); + sa.recycle(); + return false; + } + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_scheme, 0); + if (str != null) { + intentInfo.addDataScheme(str); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_ssp, 0); + if (str != null) { + intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspPrefix, 0); + if (str != null) { + intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_sspPattern, 0); + if (str != null) { + if (!allowGlobs) { + outError[0] = "sspPattern not allowed here; ssp must be literal"; + return false; + } + intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + String host = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_host, 0); + String port = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_port, 0); + if (host != null) { + intentInfo.addDataAuthority(host, port); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_path, 0); + if (str != null) { + intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathPrefix, 0); + if (str != null) { + intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathPattern, 0); + if (str != null) { + if (!allowGlobs) { + outError[0] = "pathPattern not allowed here; path must be literal"; + return false; + } + intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB); + } + + str = sa.getNonConfigurationString( + R.styleable.AndroidManifestData_pathAdvancedPattern, 0); + if (str != null) { + if (!allowGlobs) { + outError[0] = "pathAdvancedPattern not allowed here; path must be literal"; + return false; + } + intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB); + } + + sa.recycle(); + XmlUtils.skipCurrentTag(parser); + } else if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under <intent-filter>: " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + } else { + outError[0] = "Bad element under <intent-filter>: " + parser.getName(); + return false; + } + } + + intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT); + + if (PackageParser.DEBUG_PARSER) { + final StringBuilder cats = new StringBuilder("Intent d="); + cats.append(intentInfo.hasDefault); + cats.append(", cat="); + + final Iterator<String> it = intentInfo.categoriesIterator(); + if (it != null) { + while (it.hasNext()) { + cats.append(' '); + cats.append(it.next()); + } + } + Slog.d(TAG, cats.toString()); + } + + return true; + } + + private static boolean parseAllMetaData( + ParsingPackage parsingPackage, + Resources res, XmlResourceParser parser, String tag, + ParsedComponent outInfo, + String[] outError + ) throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + + if (parser.getName().equals("meta-data")) { + if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser, + outInfo.metaData, outError)) == null) { + return false; + } + } else { + if (!PackageParser.RIGID_PARSER) { + Slog.w(TAG, "Unknown element under " + tag + ": " + + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } else { + outError[0] = "Bad element under " + tag + ": " + parser.getName(); + } + } + } + + return true; + } + + public static boolean isImplicitlyExposedIntent(IntentFilter intent) { + return intent.hasCategory(Intent.CATEGORY_BROWSABLE) + || intent.hasAction(Intent.ACTION_SEND) + || intent.hasAction(Intent.ACTION_SENDTO) + || intent.hasAction(Intent.ACTION_SEND_MULTIPLE); + } +} diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java new file mode 100644 index 000000000000..363cf80a0a1d --- /dev/null +++ b/core/java/android/content/pm/parsing/PackageImpl.java @@ -0,0 +1,3213 @@ +/* + * Copyright (C) 2019 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.parsing; + +import static android.os.Build.VERSION_CODES.DONUT; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.ProviderInfo; +import android.content.pm.ServiceInfo; +import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.res.TypedArray; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Parcel; +import android.os.UserHandle; +import android.os.storage.StorageManager; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.SparseArray; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.server.SystemConfig; + +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * The backing data for a package that was parsed from disk. + * + * TODO(b/135203078): Convert Lists used as sets into Sets, to better express intended use case + * TODO(b/135203078): Field nullability annotations + * TODO(b/135203078): Convert = 1 fields into Booleans + * TODO(b/135203078): Make all lists nullable and Collections.unmodifiable immutable when returned. + * Prefer add/set methods if adding is necessary. + * TODO(b/135203078): Consider comments to disable auto-format and single-line, single-space all the + * get/set methods to make this class far more compact. Maybe even separate some logic into parent + * classes, assuming there is no overhead. + * TODO(b/135203078): Copy documentation from PackageParser#Package for the relevant fields included + * here. Should clarify and clean up any differences. Also consider renames if it helps make + * things clearer. + * TODO(b/135203078): Intern all possibl e String values? Initial refactor just mirrored old + * behavior. + * + * @hide + */ +public final class PackageImpl implements ParsingPackage, ParsedPackage, AndroidPackage, + AndroidPackageWrite { + + private static final String TAG = "PackageImpl"; + + // Resource boolean are -1, so 1 means we don't know the value. + private int supportsSmallScreens = 1; + private int supportsNormalScreens = 1; + private int supportsLargeScreens = 1; + private int supportsXLargeScreens = 1; + private int resizeable = 1; + private int anyDensity = 1; + + private long[] lastPackageUsageTimeInMills = + new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT]; + + private int versionCode; + private int versionCodeMajor; + private int baseRevisionCode; + private String versionName; + + private boolean coreApp; + private int compileSdkVersion; + private String compileSdkVersionCodename; + + private String packageName; + private String realPackage; + private String manifestPackageName; + private String baseCodePath; + + private boolean requiredForAllUsers; + private String restrictedAccountType; + private String requiredAccountType; + + private boolean baseHardwareAccelerated; + + private String overlayTarget; + private String overlayTargetName; + private String overlayCategory; + private int overlayPriority; + private boolean overlayIsStatic; + + private String staticSharedLibName; + private long staticSharedLibVersion; + private ArrayList<String> libraryNames; + private ArrayList<String> usesLibraries; + private ArrayList<String> usesOptionalLibraries; + + private ArrayList<String> usesStaticLibraries; + private long[] usesStaticLibrariesVersions; + private String[][] usesStaticLibrariesCertDigests; + + private String sharedUserId; + + private int sharedUserLabel; + private ArrayList<ConfigurationInfo> configPreferences; + private ArrayList<FeatureInfo> reqFeatures; + private ArrayList<FeatureGroupInfo> featureGroups; + + private byte[] restrictUpdateHash; + + private ArrayList<String> originalPackages; + private ArrayList<String> adoptPermissions; + + private ArrayList<String> requestedPermissions; + private ArrayList<String> implicitPermissions; + + private ArraySet<String> upgradeKeySets; + private Map<String, ArraySet<PublicKey>> keySetMapping; + + private ArrayList<String> protectedBroadcasts; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedActivity> activities; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedActivity> receivers; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedService> services; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedProvider> providers; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedPermission> permissions; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedPermissionGroup> permissionGroups; + + @Nullable + private ArrayList<ComponentParseUtils.ParsedInstrumentation> instrumentations; + + private ArrayList<ParsedActivityIntentInfo> preferredActivityFilters; + + private Bundle appMetaData; + + private String volumeUuid; + private String applicationVolumeUuid; + private PackageParser.SigningDetails signingDetails; + + private String codePath; + + private boolean use32BitAbi; + private boolean visibleToInstantApps; + + private String cpuAbiOverride; + + private boolean isStub; + + // TODO(b/135203078): Remove, should be unused + private int preferredOrder; + + private boolean forceQueryable; + + @Nullable + private ArrayList<Intent> queriesIntents; + + @Nullable + private ArrayList<String> queriesPackages; + + private String[] splitClassLoaderNames; + private String[] splitCodePaths; + private SparseArray<int[]> splitDependencies; + private int[] splitFlags; + private String[] splitNames; + private int[] splitRevisionCodes; + + // TODO(b/135203078): Audit applicationInfo.something usages, which may be different from + // package.something usages. There were differing cases of package.field = versus + // package.appInfo.field =. This class assumes some obvious ones, like packageName, + // were collapsible, but kept the following separate. + + private String applicationInfoBaseResourcePath; + private String applicationInfoCodePath; + private String applicationInfoResourcePath; + private String[] applicationInfoSplitResourcePaths; + + private String appComponentFactory; + private String backupAgentName; + private int banner; + private int category; + private String classLoaderName; + private String className; + private int compatibleWidthLimitDp; + private String credentialProtectedDataDir; + private String dataDir; + private int descriptionRes; + private String deviceProtectedDataDir; + private boolean enabled; + private int flags; + private int fullBackupContent; + private boolean hiddenUntilInstalled; + private int icon; + private int iconRes; + private int installLocation = PackageParser.PARSE_DEFAULT_INSTALL_LOCATION; + private int labelRes; + private int largestWidthLimitDp; + private int logo; + private String manageSpaceActivityName; + private float maxAspectRatio; + private float minAspectRatio; + private int minSdkVersion; + private String name; + private String nativeLibraryDir; + private String nativeLibraryRootDir; + private boolean nativeLibraryRootRequiresIsa; + private int networkSecurityConfigRes; + private CharSequence nonLocalizedLabel; + private String permission; + private String primaryCpuAbi; + private int privateFlags; + private String processName; + private int requiresSmallestWidthDp; + private int roundIconRes; + private String secondaryCpuAbi; + private String secondaryNativeLibraryDir; + private String seInfo; + private String seInfoUser; + private int targetSandboxVersion; + private int targetSdkVersion; + private String taskAffinity; + private int theme; + private int uid = -1; + private int uiOptions; + private String[] usesLibraryFiles; + private List<SharedLibraryInfo> usesLibraryInfos; + private String zygotePreloadName; + + @VisibleForTesting + public PackageImpl( + String packageName, + String baseCodePath, + TypedArray manifestArray, + boolean isCoreApp + ) { + this.packageName = TextUtils.safeIntern(packageName); + this.manifestPackageName = this.packageName; + this.baseCodePath = baseCodePath; + + this.versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0); + this.versionCodeMajor = manifestArray.getInteger( + R.styleable.AndroidManifest_versionCodeMajor, 0); + this.baseRevisionCode = manifestArray.getInteger(R.styleable.AndroidManifest_revisionCode, + 0); + setVersionName(manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_versionName, 0)); + this.coreApp = isCoreApp; + + this.compileSdkVersion = manifestArray.getInteger( + R.styleable.AndroidManifest_compileSdkVersion, 0); + setCompileSdkVersionCodename(manifestArray.getNonConfigurationString( + R.styleable.AndroidManifest_compileSdkVersionCodename, 0)); + } + + private PackageImpl(String packageName) { + this.packageName = TextUtils.safeIntern(packageName); + this.manifestPackageName = this.packageName; + } + + @VisibleForTesting + public static ParsingPackage forParsing(String packageName) { + return new PackageImpl(packageName); + } + + @VisibleForTesting + public static ParsingPackage forParsing( + String packageName, + String baseCodePath, + TypedArray manifestArray, + boolean isCoreApp) { + return new PackageImpl(packageName, baseCodePath, manifestArray, isCoreApp); + } + + /** + * Mock an unavailable {@link AndroidPackage} to use when removing a package from the system. + * This can occur if the package was installed on a storage device that has since been removed. + * Since the infrastructure uses {@link AndroidPackage}, but for this case only cares about + * volumeUuid, just fake it rather than having separate method paths. + */ + public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) { + return new PackageImpl(packageName) + .setVolumeUuid(volumeUuid) + .hideAsParsed() + .hideAsFinal(); + } + + @Override + public ParsedPackage hideAsParsed() { + return this; + } + + @Override + public AndroidPackage hideAsFinal() { + updateFlags(); + return this; + } + + @Override + @Deprecated + public AndroidPackageWrite mutate() { + return this; + } + + private void updateFlags() { + if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; + } + if (supportsNormalScreens != 0) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; + } + if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; + } + if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.GINGERBREAD)) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; + } + if (resizeable < 0 || (resizeable > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + this.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; + } + if (anyDensity < 0 || (anyDensity > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + this.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; + } + } + + @Override + public boolean usesCompatibilityMode() { + int flags = 0; + + if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; + } + if (supportsNormalScreens != 0) { + flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; + } + if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; + } + if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 + && targetSdkVersion + >= Build.VERSION_CODES.GINGERBREAD)) { + flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; + } + if (resizeable < 0 || (resizeable > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; + } + if (anyDensity < 0 || (anyDensity > 0 + && targetSdkVersion + >= Build.VERSION_CODES.DONUT)) { + flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; + } + + return targetSdkVersion < DONUT + || (flags & (ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS + | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES + | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)) == 0; + } + + @Override + public String getBaseCodePath() { + return baseCodePath; + } + + @Override + public int getTargetSdkVersion() { + return targetSdkVersion; + } + + @Override + public String getPackageName() { + return packageName; + } + + @Override + public String getProcessName() { + return processName; + } + + @Override + public String getPermission() { + return permission; + } + + @Override + public String getStaticSharedLibName() { + return staticSharedLibName; + } + + @Override + public long getStaticSharedLibVersion() { + return staticSharedLibVersion; + } + + @Override + public String getSharedUserId() { + return sharedUserId; + } + + @Override + public List<String> getRequestedPermissions() { + return requestedPermissions == null ? Collections.emptyList() : requestedPermissions; + } + + @Nullable + @Override + public List<ParsedInstrumentation> getInstrumentations() { + return instrumentations; + } + + @Override + public Map<String, ArraySet<PublicKey>> getKeySetMapping() { + return keySetMapping == null ? Collections.emptyMap() : keySetMapping; + } + + @Override + public float getMaxAspectRatio() { + return maxAspectRatio; + } + + @Override + public float getMinAspectRatio() { + return minAspectRatio; + } + + @NonNull + @Override + public List<String> getLibraryNames() { + return libraryNames == null ? Collections.emptyList() : libraryNames; + } + + @Override + public List<ParsedActivity> getActivities() { + return activities == null ? Collections.emptyList() + : activities; + } + + @Override + public Bundle getAppMetaData() { + return appMetaData; + } + + @Nullable + @Override + public List<String> getUsesLibraries() { + return usesLibraries; + } + + @Nullable + @Override + public List<String> getUsesStaticLibraries() { + return usesStaticLibraries; + } + + @Override + public boolean isBaseHardwareAccelerated() { + return baseHardwareAccelerated; + } + + @Override + public int getUiOptions() { + return uiOptions; + } + + // TODO(b/135203078): Checking flags directly can be error prone, + // consider separate interface methods? + @Override + public int getFlags() { + return flags; + } + + // TODO(b/135203078): Checking flags directly can be error prone, + // consider separate interface methods? + @Override + public int getPrivateFlags() { + return privateFlags; + } + + @Override + public String getTaskAffinity() { + return taskAffinity; + } + + @Nullable + @Override + public List<String> getOriginalPackages() { + return originalPackages; + } + + @Override + public PackageParser.SigningDetails getSigningDetails() { + return signingDetails; + } + + @Override + public String getVolumeUuid() { + return volumeUuid; + } + + @Nullable + @Override + public List<ParsedPermissionGroup> getPermissionGroups() { + return permissionGroups; + } + + @Nullable + @Override + public List<ParsedPermission> getPermissions() { + return permissions; + } + + @Override + public String getCpuAbiOverride() { + return cpuAbiOverride; + } + + @Override + public String getPrimaryCpuAbi() { + return primaryCpuAbi; + } + + @Override + public String getSecondaryCpuAbi() { + return secondaryCpuAbi; + } + + @Override + public boolean isUse32BitAbi() { + return use32BitAbi; + } + + @Override + public boolean isForceQueryable() { + return forceQueryable; + } + + @Override + public String getCodePath() { + return codePath; + } + + @Override + public String getNativeLibraryDir() { + return nativeLibraryDir; + } + + @Override + public String getNativeLibraryRootDir() { + return nativeLibraryRootDir; + } + + @Override + public boolean isNativeLibraryRootRequiresIsa() { + return nativeLibraryRootRequiresIsa; + } + + // TODO(b/135203078): Does nothing, remove? + @Override + public int getPreferredOrder() { + return preferredOrder; + } + + @Override + public long getLongVersionCode() { + return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode); + } + + @Override + public PackageImpl setIsOverlay(boolean isOverlay) { + this.privateFlags = isOverlay + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY; + return this; + } + + @Override + public PackageImpl setExternalStorage(boolean externalStorage) { + this.flags = externalStorage + ? this.flags | ApplicationInfo.FLAG_EXTERNAL_STORAGE + : this.flags & ~ApplicationInfo.FLAG_EXTERNAL_STORAGE; + return this; + } + + @Override + public PackageImpl setIsolatedSplitLoading(boolean isolatedSplitLoading) { + this.privateFlags = isolatedSplitLoading + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING; + return this; + } + + @Override + public PackageImpl sortActivities() { + Collections.sort(this.activities, (a1, a2) -> Integer.compare(a2.order, a1.order)); + return this; + } + + @Override + public PackageImpl sortReceivers() { + Collections.sort(this.receivers, (a1, a2) -> Integer.compare(a2.order, a1.order)); + return this; + } + + @Override + public PackageImpl sortServices() { + Collections.sort(this.services, (a1, a2) -> Integer.compare(a2.order, a1.order)); + return this; + } + + @Override + public PackageImpl setBaseRevisionCode(int baseRevisionCode) { + this.baseRevisionCode = baseRevisionCode; + return this; + } + + @Override + public PackageImpl setPreferredOrder(int preferredOrder) { + this.preferredOrder = preferredOrder; + return this; + } + + @Override + public PackageImpl setVersionName(String versionName) { + this.versionName = TextUtils.safeIntern(versionName); + return this; + } + + @Override + public ParsingPackage setCompileSdkVersion(int compileSdkVersion) { + this.compileSdkVersion = compileSdkVersion; + return this; + } + + @Override + public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) { + this.compileSdkVersionCodename = TextUtils.safeIntern(compileSdkVersionCodename); + return this; + } + + @Override + public PackageImpl setMaxAspectRatio(float maxAspectRatio) { + this.maxAspectRatio = maxAspectRatio; + return this; + } + + @Override + public PackageImpl setMinAspectRatio(float minAspectRatio) { + this.minAspectRatio = minAspectRatio; + return this; + } + + @Override + public PackageImpl setMinSdkVersion(int minSdkVersion) { + this.minSdkVersion = minSdkVersion; + return this; + } + + @Override + public PackageImpl setTargetSdkVersion(int targetSdkVersion) { + this.targetSdkVersion = targetSdkVersion; + return this; + } + + @Override + public PackageImpl setRealPackage(String realPackage) { + this.realPackage = realPackage; + return this; + } + + @Override + public PackageImpl addConfigPreference(ConfigurationInfo configPreference) { + this.configPreferences = ArrayUtils.add(this.configPreferences, configPreference); + return this; + } + + @Override + public PackageImpl addReqFeature(FeatureInfo reqFeature) { + this.reqFeatures = ArrayUtils.add(this.reqFeatures, reqFeature); + return this; + } + + @Override + public PackageImpl addFeatureGroup(FeatureGroupInfo featureGroup) { + this.featureGroups = ArrayUtils.add(this.featureGroups, featureGroup); + return this; + } + + @Override + public PackageImpl addProtectedBroadcast(String protectedBroadcast) { + if (this.protectedBroadcasts == null + || !this.protectedBroadcasts.contains(protectedBroadcast)) { + this.protectedBroadcasts = ArrayUtils.add(this.protectedBroadcasts, + TextUtils.safeIntern(protectedBroadcast)); + } + return this; + } + + @Override + public PackageImpl addInstrumentation(ParsedInstrumentation instrumentation) { + this.instrumentations = ArrayUtils.add(this.instrumentations, instrumentation); + return this; + } + + @Override + public PackageImpl addOriginalPackage(String originalPackage) { + this.originalPackages = ArrayUtils.add(this.originalPackages, originalPackage); + return this; + } + + @Override + public PackageImpl addAdoptPermission(String adoptPermission) { + this.adoptPermissions = ArrayUtils.add(this.adoptPermissions, adoptPermission); + return this; + } + + @Override + public PackageImpl addPermission(ParsedPermission permission) { + this.permissions = ArrayUtils.add(this.permissions, permission); + return this; + } + + @Override + public PackageImpl removePermission(int index) { + this.permissions.remove(index); + return this; + } + + @Override + public PackageImpl addPermissionGroup(ParsedPermissionGroup permissionGroup) { + this.permissionGroups = ArrayUtils.add(this.permissionGroups, permissionGroup); + return this; + } + + @Override + public PackageImpl addRequestedPermission(String permission) { + this.requestedPermissions = ArrayUtils.add(this.requestedPermissions, + TextUtils.safeIntern(permission)); + return this; + } + + @Override + public PackageImpl addImplicitPermission(String permission) { + this.implicitPermissions = ArrayUtils.add(this.implicitPermissions, + TextUtils.safeIntern(permission)); + return this; + } + + @Override + public PackageImpl addKeySet(String keySetName, PublicKey publicKey) { + if (keySetMapping == null) { + keySetMapping = new ArrayMap<>(); + } + + ArraySet<PublicKey> publicKeys = keySetMapping.get(keySetName); + if (publicKeys == null) { + publicKeys = new ArraySet<>(); + keySetMapping.put(keySetName, publicKeys); + } + + publicKeys.add(publicKey); + + return this; + } + + @Override + public ParsingPackage addActivity(ParsedActivity parsedActivity) { + this.activities = ArrayUtils.add(this.activities, parsedActivity); + return this; + } + + @Override + public ParsingPackage addReceiver(ParsedActivity parsedReceiver) { + this.receivers = ArrayUtils.add(this.receivers, parsedReceiver); + return this; + } + + @Override + public ParsingPackage addService(ParsedService parsedService) { + this.services = ArrayUtils.add(this.services, parsedService); + return this; + } + + @Override + public ParsingPackage addProvider(ParsedProvider parsedProvider) { + this.providers = ArrayUtils.add(this.providers, parsedProvider); + return this; + } + + @Override + public PackageImpl addLibraryName(String libraryName) { + this.libraryNames = ArrayUtils.add(this.libraryNames, TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl addUsesLibrary(String libraryName) { + this.usesLibraries = ArrayUtils.add(this.usesLibraries, TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl addUsesOptionalLibrary(String libraryName) { + this.usesOptionalLibraries = ArrayUtils.add(this.usesOptionalLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl removeUsesOptionalLibrary(String libraryName) { + this.usesOptionalLibraries = ArrayUtils.remove(this.usesOptionalLibraries, libraryName); + return this; + } + + @Override + public PackageImpl addUsesStaticLibrary(String libraryName) { + this.usesStaticLibraries = ArrayUtils.add(this.usesStaticLibraries, + TextUtils.safeIntern(libraryName)); + return this; + } + + @Override + public PackageImpl addUsesStaticLibraryVersion(long version) { + this.usesStaticLibrariesVersions = ArrayUtils.appendLong(this.usesStaticLibrariesVersions, + version, true); + return this; + } + + @Override + public PackageImpl addUsesStaticLibraryCertDigests(String[] certSha256Digests) { + this.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class, + this.usesStaticLibrariesCertDigests, certSha256Digests, true); + return this; + } + + @Override + public PackageImpl addPreferredActivityFilter( + ParsedActivityIntentInfo parsedActivityIntentInfo) { + this.preferredActivityFilters = ArrayUtils.add(this.preferredActivityFilters, + parsedActivityIntentInfo); + return this; + } + + @Override + public PackageImpl addQueriesIntent(Intent intent) { + this.queriesIntents = ArrayUtils.add(this.queriesIntents, intent); + return this; + } + + @Override + public PackageImpl addQueriesPackage(String packageName) { + this.queriesPackages = ArrayUtils.add(this.queriesPackages, + TextUtils.safeIntern(packageName)); + return this; + } + + @Override + public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) { + if (supportsSmallScreens == 1) { + return this; + } + + this.supportsSmallScreens = supportsSmallScreens; + return this; + } + + @Override + public PackageImpl setSupportsNormalScreens(int supportsNormalScreens) { + if (supportsNormalScreens == 1) { + return this; + } + + this.supportsNormalScreens = supportsNormalScreens; + return this; + } + + @Override + public PackageImpl setSupportsLargeScreens(int supportsLargeScreens) { + if (supportsLargeScreens == 1) { + return this; + } + + this.supportsLargeScreens = supportsLargeScreens; + return this; + } + + @Override + public PackageImpl setSupportsXLargeScreens(int supportsXLargeScreens) { + if (supportsXLargeScreens == 1) { + return this; + } + + this.supportsXLargeScreens = supportsXLargeScreens; + return this; + } + + @Override + public PackageImpl setResizeable(int resizeable) { + if (resizeable == 1) { + return this; + } + + this.resizeable = resizeable; + return this; + } + + @Override + public PackageImpl setAnyDensity(int anyDensity) { + if (anyDensity == 1) { + return this; + } + + this.anyDensity = anyDensity; + return this; + } + + @Override + public PackageImpl setRequiresSmallestWidthDp(int requiresSmallestWidthDp) { + this.requiresSmallestWidthDp = requiresSmallestWidthDp; + return this; + } + + @Override + public PackageImpl setCompatibleWidthLimitDp(int compatibleWidthLimitDp) { + this.compatibleWidthLimitDp = compatibleWidthLimitDp; + return this; + } + + @Override + public PackageImpl setLargestWidthLimitDp(int largestWidthLimitDp) { + this.largestWidthLimitDp = largestWidthLimitDp; + return this; + } + + @Override + public PackageImpl setInstallLocation(int installLocation) { + this.installLocation = installLocation; + return this; + } + + @Override + public PackageImpl setTargetSandboxVersion(int targetSandboxVersion) { + this.targetSandboxVersion = targetSandboxVersion; + return this; + } + + @Override + public PackageImpl setRequiredForAllUsers(boolean requiredForAllUsers) { + this.requiredForAllUsers = requiredForAllUsers; + return this; + } + + @Override + public PackageImpl setRestrictedAccountType(String restrictedAccountType) { + this.restrictedAccountType = restrictedAccountType; + return this; + } + + @Override + public PackageImpl setRequiredAccountType(String requiredAccountType) { + this.requiredAccountType = requiredAccountType; + return this; + } + + @Override + public PackageImpl setBaseHardwareAccelerated(boolean baseHardwareAccelerated) { + this.baseHardwareAccelerated = baseHardwareAccelerated; + + this.flags = baseHardwareAccelerated + ? this.flags | ApplicationInfo.FLAG_HARDWARE_ACCELERATED + : this.flags & ~ApplicationInfo.FLAG_HARDWARE_ACCELERATED; + + return this; + } + + @Override + public PackageImpl setHasDomainUrls(boolean hasDomainUrls) { + this.privateFlags = hasDomainUrls + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS; + return this; + } + + @Override + public PackageImpl setAppMetaData(Bundle appMetaData) { + this.appMetaData = appMetaData; + return this; + } + + @Override + public PackageImpl setOverlayTarget(String overlayTarget) { + this.overlayTarget = overlayTarget; + return this; + } + + @Override + public PackageImpl setOverlayTargetName(String overlayTargetName) { + this.overlayTargetName = overlayTargetName; + return this; + } + + @Override + public PackageImpl setOverlayCategory(String overlayCategory) { + this.overlayCategory = overlayCategory; + return this; + } + + @Override + public PackageImpl setOverlayPriority(int overlayPriority) { + this.overlayPriority = overlayPriority; + return this; + } + + @Override + public PackageImpl setOverlayIsStatic(boolean overlayIsStatic) { + this.overlayIsStatic = overlayIsStatic; + return this; + } + + @Override + public PackageImpl setStaticSharedLibName(String staticSharedLibName) { + this.staticSharedLibName = TextUtils.safeIntern(staticSharedLibName); + return this; + } + + @Override + public PackageImpl setStaticSharedLibVersion(long staticSharedLibVersion) { + this.staticSharedLibVersion = staticSharedLibVersion; + return this; + } + + @Override + public PackageImpl setSharedUserId(String sharedUserId) { + this.sharedUserId = TextUtils.safeIntern(sharedUserId); + return this; + } + + @Override + public PackageImpl setSharedUserLabel(int sharedUserLabel) { + this.sharedUserLabel = sharedUserLabel; + return this; + } + + @Override + public PackageImpl setRestrictUpdateHash(byte[] restrictUpdateHash) { + this.restrictUpdateHash = restrictUpdateHash; + return this; + } + + @Override + public PackageImpl setUpgradeKeySets(ArraySet<String> upgradeKeySets) { + this.upgradeKeySets = upgradeKeySets; + return this; + } + + @Override + public PackageImpl setVolumeUuid(String volumeUuid) { + this.volumeUuid = volumeUuid; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationVolumeUuid(String applicationVolumeUuid) { + this.applicationVolumeUuid = applicationVolumeUuid; + return this; + } + + @Override + public PackageImpl setSigningDetails(PackageParser.SigningDetails signingDetails) { + this.signingDetails = signingDetails; + return this; + } + + @Override + public PackageImpl setCodePath(String codePath) { + this.codePath = codePath; + return this; + } + + @Override + public PackageImpl setUse32BitAbi(boolean use32BitAbi) { + this.use32BitAbi = use32BitAbi; + return this; + } + + @Override + public PackageImpl setCpuAbiOverride(String cpuAbiOverride) { + this.cpuAbiOverride = cpuAbiOverride; + return this; + } + + @Override + public PackageImpl setForceQueryable(boolean forceQueryable) { + this.forceQueryable = forceQueryable; + return this; + } + + // TODO(b/135203078): Remove and move PackageManagerService#renameStaticSharedLibraryPackage + // into initial package parsing + @Override + public PackageImpl setPackageName(String packageName) { + this.packageName = packageName.intern(); + + if (permissions != null) { + for (ParsedPermission permission : permissions) { + permission.setPackageName(this.packageName); + } + } + + if (permissionGroups != null) { + for (ParsedPermissionGroup permissionGroup : permissionGroups) { + permissionGroup.setPackageName(this.packageName); + } + } + + if (activities != null) { + for (ParsedActivity parsedActivity : activities) { + parsedActivity.setPackageName(this.packageName); + } + } + + if (receivers != null) { + for (ParsedActivity receiver : receivers) { + receiver.setPackageName(this.packageName); + } + } + + if (providers != null) { + for (ParsedProvider provider : providers) { + provider.setPackageName(this.packageName); + } + } + + if (services != null) { + for (ParsedService service : services) { + service.setPackageName(this.packageName); + } + } + + if (instrumentations != null) { + for (ParsedInstrumentation instrumentation : instrumentations) { + instrumentation.setPackageName(this.packageName); + } + } + + return this; + } + + // Under this is parseBaseApplication + + @Override + public PackageImpl setAllowBackup(boolean allowBackup) { + this.flags = allowBackup + ? this.flags | ApplicationInfo.FLAG_ALLOW_BACKUP + : this.flags & ~ApplicationInfo.FLAG_ALLOW_BACKUP; + return this; + } + + @Override + public PackageImpl setKillAfterRestore(boolean killAfterRestore) { + this.flags = killAfterRestore + ? this.flags | ApplicationInfo.FLAG_KILL_AFTER_RESTORE + : this.flags & ~ApplicationInfo.FLAG_KILL_AFTER_RESTORE; + return this; + } + + @Override + public PackageImpl setRestoreAnyVersion(boolean restoreAnyVersion) { + this.flags = restoreAnyVersion + ? this.flags | ApplicationInfo.FLAG_RESTORE_ANY_VERSION + : this.flags & ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; + return this; + } + + @Override + public PackageImpl setFullBackupOnly(boolean fullBackupOnly) { + this.flags = fullBackupOnly + ? this.flags | ApplicationInfo.FLAG_FULL_BACKUP_ONLY + : this.flags & ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY; + return this; + } + + @Override + public PackageImpl setPersistent(boolean persistent) { + this.flags = persistent + ? this.flags | ApplicationInfo.FLAG_PERSISTENT + : this.flags & ~ApplicationInfo.FLAG_PERSISTENT; + return this; + } + + @Override + public PackageImpl setDebuggable(boolean debuggable) { + this.flags = debuggable + ? this.flags | ApplicationInfo.FLAG_DEBUGGABLE + : this.flags & ~ApplicationInfo.FLAG_DEBUGGABLE; + return this; + } + + @Override + public PackageImpl setProfileableByShell(boolean profileableByShell) { + this.privateFlags = profileableByShell + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL; + return this; + } + + @Override + public PackageImpl setVmSafeMode(boolean vmSafeMode) { + this.flags = vmSafeMode + ? this.flags | ApplicationInfo.FLAG_VM_SAFE_MODE + : this.flags & ~ApplicationInfo.FLAG_VM_SAFE_MODE; + return this; + } + + @Override + public PackageImpl setHasCode(boolean hasCode) { + this.flags = hasCode + ? this.flags | ApplicationInfo.FLAG_HAS_CODE + : this.flags & ~ApplicationInfo.FLAG_HAS_CODE; + return this; + } + + @Override + public PackageImpl setAllowTaskReparenting(boolean allowTaskReparenting) { + this.flags = allowTaskReparenting + ? this.flags | ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING + : this.flags & ~ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING; + return this; + } + + @Override + public PackageImpl setAllowClearUserData(boolean allowClearUserData) { + this.flags = allowClearUserData + ? this.flags | ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA + : this.flags & ~ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA; + return this; + } + + @Override + public PackageImpl setLargeHeap(boolean largeHeap) { + this.flags = largeHeap + ? this.flags | ApplicationInfo.FLAG_LARGE_HEAP + : this.flags & ~ApplicationInfo.FLAG_LARGE_HEAP; + return this; + } + + @Override + public PackageImpl setUsesCleartextTraffic(boolean usesCleartextTraffic) { + this.flags = usesCleartextTraffic + ? this.flags | ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC + : this.flags & ~ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; + return this; + } + + @Override + public PackageImpl setSupportsRtl(boolean supportsRtl) { + this.flags = supportsRtl + ? this.flags | ApplicationInfo.FLAG_SUPPORTS_RTL + : this.flags & ~ApplicationInfo.FLAG_SUPPORTS_RTL; + return this; + } + + @Override + public PackageImpl setTestOnly(boolean testOnly) { + this.flags = testOnly + ? this.flags | ApplicationInfo.FLAG_TEST_ONLY + : this.flags & ~ApplicationInfo.FLAG_TEST_ONLY; + return this; + } + + @Override + public PackageImpl setMultiArch(boolean multiArch) { + this.flags = multiArch + ? this.flags | ApplicationInfo.FLAG_MULTIARCH + : this.flags & ~ApplicationInfo.FLAG_MULTIARCH; + return this; + } + + @Override + public PackageImpl setExtractNativeLibs(boolean extractNativeLibs) { + this.flags = extractNativeLibs + ? this.flags | ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS + : this.flags & ~ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; + return this; + } + + @Override + public PackageImpl setIsGame(boolean isGame) { + this.flags = isGame + ? this.flags | ApplicationInfo.FLAG_IS_GAME + : this.flags & ~ApplicationInfo.FLAG_IS_GAME; + return this; + } + + @Override + public PackageImpl setBackupInForeground(boolean backupInForeground) { + this.privateFlags = backupInForeground + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; + return this; + } + + @Override + public PackageImpl setUseEmbeddedDex(boolean useEmbeddedDex) { + this.privateFlags = useEmbeddedDex + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX; + return this; + } + + @Override + public PackageImpl setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage) { + this.privateFlags = defaultToDeviceProtectedStorage + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; + return this; + } + + @Override + public PackageImpl setDirectBootAware(boolean directBootAware) { + this.privateFlags = directBootAware + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; + return this; + } + + @Override + public PackageImpl setPartiallyDirectBootAware(boolean partiallyDirectBootAware) { + this.privateFlags = partiallyDirectBootAware + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; + return this; + } + + @Override + public PackageImpl setActivitiesResizeModeResizeableViaSdkVersion( + boolean resizeableViaSdkVersion + ) { + this.privateFlags = resizeableViaSdkVersion + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; + return this; + } + + @Override + public PackageImpl setActivitiesResizeModeResizeable(boolean resizeable) { + this.privateFlags = resizeable + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; + + this.privateFlags = !resizeable + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; + return this; + } + + @Override + public PackageImpl setAllowClearUserDataOnFailedRestore( + boolean allowClearUserDataOnFailedRestore + ) { + this.privateFlags = allowClearUserDataOnFailedRestore + ? this.privateFlags | ApplicationInfo + .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE + : this.privateFlags & ~ApplicationInfo + .PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE; + return this; + } + + @Override + public PackageImpl setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture) { + this.privateFlags = allowAudioPlaybackCapture + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE; + return this; + } + + @Override + public PackageImpl setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage) { + this.privateFlags = requestLegacyExternalStorage + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE; + return this; + } + + @Override + public PackageImpl setUsesNonSdkApi(boolean usesNonSdkApi) { + this.privateFlags = usesNonSdkApi + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API; + return this; + } + + @Override + public PackageImpl setHasFragileUserData(boolean hasFragileUserData) { + this.privateFlags = hasFragileUserData + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA; + return this; + } + + @Override + public PackageImpl setCantSaveState(boolean cantSaveState) { + this.privateFlags = cantSaveState + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; + return this; + } + + @Override + public boolean cantSaveState() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0; + } + + @Override + public boolean isLibrary() { + return staticSharedLibName != null || !ArrayUtils.isEmpty(libraryNames); + } + + // TODO(b/135203078): This does nothing until the final stage without applyPolicy being + // part of PackageParser + @Override + public boolean isSystemApp() { + return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + // TODO(b/135203078): This does nothing until the final stage without applyPolicy being + // part of PackageParser + @Override + public boolean isSystemExt() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0; + } + + // TODO(b/135203078): This does nothing until the final stage without applyPolicy being + // part of PackageParser + @Override + public boolean isUpdatedSystemApp() { + return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; + } + + @Override + public PackageImpl setStaticSharedLibrary(boolean staticSharedLibrary) { + this.privateFlags = staticSharedLibrary + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY; + return this; + } + + @Override + public boolean isStaticSharedLibrary() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0; + } + + @Override + public PackageImpl setVisibleToInstantApps(boolean visibleToInstantApps) { + this.visibleToInstantApps = visibleToInstantApps; + return this; + } + + @Override + public PackageImpl setIconRes(int iconRes) { + this.iconRes = iconRes; + return this; + } + + @Override + public PackageImpl setRoundIconRes(int roundIconRes) { + this.roundIconRes = roundIconRes; + return this; + } + + @Override + public PackageImpl setClassName(String className) { + this.className = className; + return this; + } + + @Override + public PackageImpl setManageSpaceActivityName(String manageSpaceActivityName) { + this.manageSpaceActivityName = manageSpaceActivityName; + return this; + } + + @Override + public PackageImpl setBackupAgentName(String backupAgentName) { + this.backupAgentName = backupAgentName; + return this; + } + + @Override + public PackageImpl setFullBackupContent(int fullBackupContent) { + this.fullBackupContent = fullBackupContent; + return this; + } + + @Override + public PackageImpl setTheme(int theme) { + this.theme = theme; + return this; + } + + @Override + public PackageImpl setDescriptionRes(int descriptionRes) { + this.descriptionRes = descriptionRes; + return this; + } + + @Override + public PackageImpl setNetworkSecurityConfigRes(int networkSecurityConfigRes) { + this.networkSecurityConfigRes = networkSecurityConfigRes; + return this; + } + + @Override + public PackageImpl setCategory(int category) { + this.category = category; + return this; + } + + @Override + public PackageImpl setPermission(String permission) { + this.permission = permission; + return this; + } + + @Override + public PackageImpl setTaskAffinity(String taskAffinity) { + this.taskAffinity = taskAffinity; + return this; + } + + @Override + public PackageImpl setAppComponentFactory(String appComponentFactory) { + this.appComponentFactory = appComponentFactory; + return this; + } + + @Override + public PackageImpl setProcessName(String processName) { + if (processName == null) { + this.processName = packageName; + } else { + this.processName = processName; + } + return this; + } + + @Override + public PackageImpl setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + @Override + public PackageImpl setUiOptions(int uiOptions) { + this.uiOptions = uiOptions; + return this; + } + + @Override + public PackageImpl setClassLoaderName(String classLoaderName) { + this.classLoaderName = classLoaderName; + return this; + } + + @Override + public PackageImpl setZygotePreloadName(String zygotePreloadName) { + this.zygotePreloadName = zygotePreloadName; + return this; + } + + // parsePackageItemInfo + + @Override + public String getName() { + return name; + } + + @Override + public PackageImpl setName(String name) { + this.name = name; + return this; + } + + @Override + public PackageImpl setIcon(int icon) { + this.icon = icon; + return this; + } + + @Override + public PackageImpl setNonLocalizedLabel(CharSequence nonLocalizedLabel) { + this.nonLocalizedLabel = nonLocalizedLabel; + return this; + } + + @Override + public PackageImpl setLogo(int logo) { + this.logo = logo; + return this; + } + + @Override + public PackageImpl setBanner(int banner) { + this.banner = banner; + return this; + } + + @Override + public PackageImpl setLabelRes(int labelRes) { + this.labelRes = labelRes; + return this; + } + + @Override + public PackageImpl asSplit( + String[] splitNames, + String[] splitCodePaths, + int[] splitRevisionCodes, + SparseArray<int[]> splitDependencies + ) { + this.splitNames = splitNames; + + if (this.splitNames != null) { + for (int index = 0; index < this.splitNames.length; index++) { + splitNames[index] = TextUtils.safeIntern(splitNames[index]); + } + } + + this.splitCodePaths = splitCodePaths; + this.splitRevisionCodes = splitRevisionCodes; + this.splitDependencies = splitDependencies; + + int count = splitNames.length; + this.splitFlags = new int[count]; + this.splitClassLoaderNames = new String[count]; + return this; + } + + @Override + public String[] getSplitNames() { + return splitNames; + } + + @Override + public String[] getSplitCodePaths() { + return splitCodePaths; + } + + @Override + public PackageImpl setSplitHasCode(int splitIndex, boolean splitHasCode) { + this.splitFlags[splitIndex] = splitHasCode + ? this.splitFlags[splitIndex] | ApplicationInfo.FLAG_HAS_CODE + : this.splitFlags[splitIndex] & ~ApplicationInfo.FLAG_HAS_CODE; + return this; + } + + @Override + public PackageImpl setSplitClassLoaderName(int splitIndex, String classLoaderName) { + this.splitClassLoaderNames[splitIndex] = classLoaderName; + return this; + } + + @Override + public List<String> makeListAllCodePaths() { + ArrayList<String> paths = new ArrayList<>(); + paths.add(baseCodePath); + + if (!ArrayUtils.isEmpty(splitCodePaths)) { + Collections.addAll(paths, splitCodePaths); + } + return paths; + } + + @Override + public PackageImpl setBaseCodePath(String baseCodePath) { + this.baseCodePath = baseCodePath; + return this; + } + + @Override + public PackageImpl setSplitCodePaths(String[] splitCodePaths) { + this.splitCodePaths = splitCodePaths; + return this; + } + + @Override + public String toString() { + return "Package{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + packageName + "}"; + } + + @Override + public PackageImpl setPrimaryCpuAbi(String primaryCpuAbi) { + this.primaryCpuAbi = primaryCpuAbi; + return this; + } + + @Override + public PackageImpl setSecondaryCpuAbi(String secondaryCpuAbi) { + this.secondaryCpuAbi = secondaryCpuAbi; + return this; + } + + @Override + public PackageImpl setNativeLibraryRootDir(String nativeLibraryRootDir) { + this.nativeLibraryRootDir = nativeLibraryRootDir; + return this; + } + + @Override + public PackageImpl setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa) { + this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; + return this; + } + + @Override + public PackageImpl setNativeLibraryDir(String nativeLibraryDir) { + this.nativeLibraryDir = nativeLibraryDir; + return this; + } + + @Override + public PackageImpl setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir) { + this.secondaryNativeLibraryDir = secondaryNativeLibraryDir; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationInfoCodePath(String applicationInfoCodePath) { + this.applicationInfoCodePath = applicationInfoCodePath; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationInfoResourcePath(String applicationInfoResourcePath) { + this.applicationInfoResourcePath = applicationInfoResourcePath; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationInfoBaseResourcePath( + String applicationInfoBaseResourcePath) { + this.applicationInfoBaseResourcePath = applicationInfoBaseResourcePath; + return this; + } + + @Deprecated + @Override + public PackageImpl setApplicationInfoSplitResourcePaths( + String[] applicationInfoSplitResourcePaths) { + this.applicationInfoSplitResourcePaths = applicationInfoSplitResourcePaths; + return this; + } + + @Override + public boolean isDirectBootAware() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0; + } + + @Override + public PackageImpl setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware) { + if (activities != null) { + for (ParsedActivity parsedActivity : activities) { + parsedActivity.directBootAware = allComponentsDirectBootAware; + } + } + + if (receivers != null) { + for (ParsedActivity parsedReceiver : receivers) { + parsedReceiver.directBootAware = allComponentsDirectBootAware; + } + } + + if (providers != null) { + for (ParsedProvider parsedProvider : providers) { + parsedProvider.directBootAware = allComponentsDirectBootAware; + } + } + + if (services != null) { + for (ParsedService parsedService : services) { + parsedService.directBootAware = allComponentsDirectBootAware; + } + } + + return this; + } + + @Override + public PackageImpl setSystem(boolean system) { + this.flags = system + ? this.flags | ApplicationInfo.FLAG_SYSTEM + : this.flags & ~ApplicationInfo.FLAG_SYSTEM; + return this; + } + + @Override + public PackageImpl setSystemExt(boolean systemExt) { + this.privateFlags = systemExt + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT; + return this; + } + + @Override + public PackageImpl setIsStub(boolean isStub) { + this.isStub = isStub; + return this; + } + + @Override + public PackageImpl setCoreApp(boolean coreApp) { + this.coreApp = coreApp; + return this; + } + + @Override + public ParsedPackage capPermissionPriorities() { + if (permissionGroups != null && !permissionGroups.isEmpty()) { + for (int i = permissionGroups.size() - 1; i >= 0; --i) { + // TODO(b/135203078): Builder/immutability + permissionGroups.get(i).priority = 0; + } + } + return this; + } + + @Override + public ParsedPackage clearProtectedBroadcasts() { + if (protectedBroadcasts != null) { + protectedBroadcasts.clear(); + } + return this; + } + + @Override + public ParsedPackage markNotActivitiesAsNotExportedIfSingleUser() { + // ignore export request for single user receivers + if (receivers != null) { + for (ParsedActivity receiver : receivers) { + if ((receiver.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) { + receiver.exported = false; + } + } + } + // ignore export request for single user services + if (services != null) { + for (ParsedService service : services) { + if ((service.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) { + service.exported = false; + } + } + } + // ignore export request for single user providers + if (providers != null) { + for (ParsedProvider provider : providers) { + if ((provider.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) { + provider.exported = false; + } + } + } + + return this; + } + + @Override + public ParsedPackage setPrivileged(boolean privileged) { + this.privateFlags = privileged + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRIVILEGED + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; + return this; + } + + @Override + public ParsedPackage setOem(boolean oem) { + this.privateFlags = oem + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_OEM + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_OEM; + return this; + } + + @Override + public ParsedPackage setVendor(boolean vendor) { + this.privateFlags = vendor + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_VENDOR + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_VENDOR; + return this; + } + + @Override + public ParsedPackage setProduct(boolean product) { + this.privateFlags = product + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_PRODUCT + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_PRODUCT; + return this; + } + + @Override + public ParsedPackage setOdm(boolean odm) { + this.privateFlags = odm + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_ODM + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_ODM; + return this; + } + + @Override + public ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey) { + this.privateFlags = signedWithPlatformKey + ? this.privateFlags | ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY + : this.privateFlags & ~ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY; + return this; + } + + @Override + public ParsedPackage clearOriginalPackages() { + if (originalPackages != null) { + originalPackages.clear(); + } + return this; + } + + @Override + public ParsedPackage clearAdoptPermissions() { + if (adoptPermissions != null) { + adoptPermissions.clear(); + } + return this; + } + + @Override + public PackageImpl addUsesLibrary(int index, String libraryName) { + this.usesLibraries = ArrayUtils.add(usesLibraries, index, libraryName); + return this; + } + + @Override + public ParsedPackage removeUsesLibrary(String libraryName) { + this.usesLibraries = ArrayUtils.remove(this.usesLibraries, libraryName); + return this; + } + + @Override + public PackageImpl addUsesOptionalLibrary(int index, String libraryName) { + this.usesOptionalLibraries = ArrayUtils.add(usesOptionalLibraries, index, libraryName); + return this; + } + + @Nullable + @Override + public List<String> getUsesOptionalLibraries() { + return usesOptionalLibraries; + } + + @Override + public int getVersionCode() { + return versionCode; + } + + @Nullable + @Override + public long[] getUsesStaticLibrariesVersions() { + return usesStaticLibrariesVersions; + } + + @Override + public PackageImpl setPackageSettingCallback(PackageSettingCallback packageSettingCallback) { + packageSettingCallback.setAndroidPackage(this); + return this; + } + + @Override + public PackageImpl setUpdatedSystemApp(boolean updatedSystemApp) { + this.flags = updatedSystemApp + ? this.flags | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP + : this.flags & ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + return this; + } + + @Override + public boolean isPrivileged() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + } + + @Override + public PackageImpl setSeInfo(String seInfo) { + this.seInfo = seInfo; + return this; + } + + @Override + public PackageImpl setSeInfoUser(String seInfoUser) { + this.seInfoUser = seInfoUser; + return this; + } + + @Override + public PackageImpl initForUser(int userId) { + // TODO(b/135203078): Move this user state to some other data structure + this.uid = UserHandle.getUid(userId, UserHandle.getAppId(this.uid)); + + if ("android".equals(packageName)) { + dataDir = Environment.getDataSystemDirectory().getAbsolutePath(); + return this; + } + + deviceProtectedDataDir = Environment + .getDataUserDePackageDirectory(applicationVolumeUuid, userId, packageName) + .getAbsolutePath(); + credentialProtectedDataDir = Environment + .getDataUserCePackageDirectory(applicationVolumeUuid, userId, packageName) + .getAbsolutePath(); + + if ((privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0 + && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { + dataDir = deviceProtectedDataDir; + } else { + dataDir = credentialProtectedDataDir; + } + return this; + } + + @Override + public ParsedPackage setFactoryTest(boolean factoryTest) { + this.flags = factoryTest + ? this.flags | ApplicationInfo.FLAG_FACTORY_TEST + : this.flags & ~ApplicationInfo.FLAG_FACTORY_TEST; + return this; + } + + @Override + public String getManifestPackageName() { + return manifestPackageName; + } + + @Override + public String getRealPackage() { + return realPackage; + } + + @Override + public String getOverlayTarget() { + return overlayTarget; + } + + @Override + public String getOverlayTargetName() { + return overlayTargetName; + } + + @Override + public boolean isOverlayIsStatic() { + return overlayIsStatic; + } + + @Override + public int[] getSplitFlags() { + return splitFlags; + } + + @Deprecated + @Override + public String getApplicationInfoVolumeUuid() { + return applicationVolumeUuid; + } + + @Nullable + @Override + public List<String> getProtectedBroadcasts() { + return protectedBroadcasts; + } + + @Nullable + @Override + public Set<String> getUpgradeKeySets() { + return upgradeKeySets; + } + + @Nullable + @Override + public String[][] getUsesStaticLibrariesCertDigests() { + return usesStaticLibrariesCertDigests; + } + + @Override + public int getOverlayPriority() { + return overlayPriority; + } + + @Deprecated + @Override + public String getAppInfoPackageName() { + return packageName; + } + + @Override + public UUID getStorageUuid() { + return StorageManager.convert(applicationVolumeUuid); + } + + @Override + public int getUid() { + return uid; + } + + @Override + public boolean isStub() { + return isStub; + } + + @Deprecated + @Override + public String getAppInfoCodePath() { + return applicationInfoCodePath; + } + + @Override + public boolean isSystem() { + return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + @Override + public boolean isMatch(int flags) { + if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { + return isSystem(); + } + return true; + } + + @Override + public boolean isVisibleToInstantApps() { + return visibleToInstantApps; + } + + @Override + public PackageImpl setLastPackageUsageTimeInMills(int reason, long time) { + lastPackageUsageTimeInMills[reason] = time; + return this; + } + + @Override + public List<SharedLibraryInfo> getUsesLibraryInfos() { + return usesLibraryInfos; + } + + @NonNull + @Override + public List<String> getAllCodePaths() { + return makeListAllCodePaths(); + } + + @Nullable + @Override + public String[] getUsesLibraryFiles() { + return usesLibraryFiles; + } + + @Override + public PackageImpl setUsesLibraryInfos( + @Nullable List<SharedLibraryInfo> usesLibraryInfos) { + this.usesLibraryInfos = usesLibraryInfos; + return this; + } + + @Override + public PackageImpl setUsesLibraryFiles(@Nullable String[] usesLibraryFiles) { + this.usesLibraryFiles = usesLibraryFiles; + return this; + } + + @Override + public PackageImpl setUid(int uid) { + this.uid = uid; + return this; + } + + @Override + public List<String> getAdoptPermissions() { + return adoptPermissions; + } + + @Override + public ApplicationInfo toAppInfo() { + updateFlags(); + + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = packageName; + applicationInfo.flags = flags; + applicationInfo.privateFlags = privateFlags; + applicationInfo.sharedLibraryFiles = usesLibraryFiles; + applicationInfo.sharedLibraryInfos = usesLibraryInfos; + + applicationInfo.appComponentFactory = appComponentFactory; + applicationInfo.backupAgentName = backupAgentName; + applicationInfo.banner = banner; + applicationInfo.category = category; + applicationInfo.classLoaderName = classLoaderName; + applicationInfo.className = className; + applicationInfo.compatibleWidthLimitDp = compatibleWidthLimitDp; + applicationInfo.credentialProtectedDataDir = credentialProtectedDataDir; + applicationInfo.dataDir = dataDir; + applicationInfo.descriptionRes = descriptionRes; + applicationInfo.deviceProtectedDataDir = deviceProtectedDataDir; + applicationInfo.enabled = enabled; + applicationInfo.fullBackupContent = fullBackupContent; + applicationInfo.icon = icon; + applicationInfo.iconRes = iconRes; + applicationInfo.installLocation = installLocation; + applicationInfo.labelRes = labelRes; + applicationInfo.largestWidthLimitDp = largestWidthLimitDp; + applicationInfo.logo = logo; + applicationInfo.manageSpaceActivityName = manageSpaceActivityName; + applicationInfo.maxAspectRatio = maxAspectRatio; + applicationInfo.minAspectRatio = minAspectRatio; + applicationInfo.minSdkVersion = minSdkVersion; + applicationInfo.name = name; + applicationInfo.nativeLibraryDir = nativeLibraryDir; + applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir; + applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; + applicationInfo.networkSecurityConfigRes = networkSecurityConfigRes; + applicationInfo.nonLocalizedLabel = nonLocalizedLabel; + applicationInfo.permission = permission; + applicationInfo.primaryCpuAbi = primaryCpuAbi; + applicationInfo.processName = processName; + applicationInfo.requiresSmallestWidthDp = requiresSmallestWidthDp; + applicationInfo.roundIconRes = roundIconRes; + applicationInfo.secondaryCpuAbi = secondaryCpuAbi; + applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; + applicationInfo.seInfo = seInfo; + applicationInfo.seInfoUser = seInfoUser; + applicationInfo.splitClassLoaderNames = splitClassLoaderNames; + applicationInfo.splitDependencies = splitDependencies; + applicationInfo.splitNames = splitNames; + applicationInfo.storageUuid = StorageManager.convert(applicationVolumeUuid); + applicationInfo.targetSandboxVersion = targetSandboxVersion; + applicationInfo.targetSdkVersion = targetSdkVersion; + applicationInfo.taskAffinity = taskAffinity; + applicationInfo.theme = theme; + applicationInfo.uid = uid; + applicationInfo.uiOptions = uiOptions; + applicationInfo.volumeUuid = applicationVolumeUuid; + applicationInfo.zygotePreloadName = zygotePreloadName; + + applicationInfo.setBaseCodePath(baseCodePath); + applicationInfo.setBaseResourcePath(applicationInfoBaseResourcePath); + applicationInfo.setCodePath(applicationInfoCodePath); + applicationInfo.setResourcePath(applicationInfoResourcePath); + applicationInfo.setSplitCodePaths(splitCodePaths); + applicationInfo.setSplitResourcePaths(applicationInfoSplitResourcePaths); + + return applicationInfo; + } + + @Override + public PackageImpl setVersionCode(int versionCode) { + this.versionCode = versionCode; + return this; + } + + @Override + public PackageImpl setHiddenUntilInstalled(boolean hidden) { + this.hiddenUntilInstalled = hidden; + return this; + } + + @Override + public String getSeInfo() { + return seInfo; + } + + @Deprecated + @Override + public String getAppInfoResourcePath() { + return applicationInfoResourcePath; + } + + @Override + public boolean isForwardLocked() { + // TODO(b/135203078): Unused? Move to debug flag? + return false; + } + + @Override + public byte[] getRestrictUpdateHash() { + return restrictUpdateHash; + } + + @Override + public boolean hasComponentClassName(String className) { + if (activities != null) { + for (ParsedActivity parsedActivity : activities) { + if (Objects.equals(className, parsedActivity.className)) { + return true; + } + } + } + + if (receivers != null) { + for (ParsedActivity receiver : receivers) { + if (Objects.equals(className, receiver.className)) { + return true; + } + } + } + + if (providers != null) { + for (ParsedProvider provider : providers) { + if (Objects.equals(className, provider.className)) { + return true; + } + } + } + + if (services != null) { + for (ParsedService service : services) { + if (Objects.equals(className, service.className)) { + return true; + } + } + } + + if (instrumentations != null) { + for (ParsedInstrumentation instrumentation : instrumentations) { + if (Objects.equals(className, instrumentation.className)) { + return true; + } + } + } + + return false; + } + + @Override + public boolean isDefaultToDeviceProtectedStorage() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) + != 0; + } + + @Override + public boolean isInternal() { + return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0; + } + + @Override + public int getBaseRevisionCode() { + return baseRevisionCode; + } + + @Override + public int[] getSplitRevisionCodes() { + return splitRevisionCodes; + } + + @Override + public boolean canHaveOatDir() { + // The following app types CANNOT have oat directory + // - non-updated system apps + return !isSystem() || isUpdatedSystemApp(); + } + + @Override + public long getLatestPackageUseTimeInMills() { + long latestUse = 0L; + for (long use : lastPackageUsageTimeInMills) { + latestUse = Math.max(latestUse, use); + } + return latestUse; + } + + @Override + public long getLatestForegroundPackageUseTimeInMills() { + int[] foregroundReasons = { + PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY, + PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE + }; + + long latestUse = 0L; + for (int reason : foregroundReasons) { + latestUse = Math.max(latestUse, lastPackageUsageTimeInMills[reason]); + } + return latestUse; + } + + @Override + public boolean isCoreApp() { + return coreApp; + } + + @Override + public String getVersionName() { + return versionName; + } + + @Override + public PackageImpl setVersionCodeMajor(int versionCodeMajor) { + this.versionCodeMajor = versionCodeMajor; + return this; + } + + @Override + public long[] getLastPackageUsageTimeInMills() { + return lastPackageUsageTimeInMills; + } + + @Override + public String getDataDir() { + return dataDir; + } + + @Override + public boolean isExternal() { + return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; + } + + @Override + public List<String> getImplicitPermissions() { + return implicitPermissions == null ? Collections.emptyList() : implicitPermissions; + } + + /** + * TODO(b/135203078): Remove, ensure b/140256621 is fixed or irrelevant + * TODO(b/140256621): Remove after fixing instant app check + * @deprecated This method always returns false because there's no paired set method + */ + @Deprecated + @Override + public boolean isInstantApp() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_INSTANT) != 0; + } + + @Override + public boolean hasRequestedLegacyExternalStorage() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0; + } + + @Override + public boolean isVendor() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + } + + @Override + public boolean isProduct() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; + } + + @Override + public boolean isOem() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; + } + + @Override + public boolean isEncryptionAware() { + boolean isPartiallyDirectBootAware = + (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0; + return isDirectBootAware() || isPartiallyDirectBootAware; + } + + @Override + public boolean isEmbeddedDexUsed() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX) != 0; + } + + @Deprecated + @Override + public String getAppInfoProcessName() { + return processName; + } + + @Override + public List<String> getAllCodePathsExcludingResourceOnly() { + ArrayList<String> paths = new ArrayList<>(); + if ((flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { + paths.add(baseCodePath); + } + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { + paths.add(splitCodePaths[i]); + } + } + } + return paths; + } + + @Deprecated + @Override + public String getAppInfoName() { + return name; + } + + private boolean isSignedWithPlatformKey() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY) != 0; + } + + private boolean usesNonSdkApi() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API) != 0; + } + + private boolean isPackageWhitelistedForHiddenApis() { + return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName); + } + + private boolean isAllowedToUseHiddenApis() { + if (isSignedWithPlatformKey()) { + return true; + } else if (isSystemApp() || isUpdatedSystemApp()) { + return usesNonSdkApi() || isPackageWhitelistedForHiddenApis(); + } else { + return false; + } + } + + @Override + public int getHiddenApiEnforcementPolicy() { + if (isAllowedToUseHiddenApis()) { + return ApplicationInfo.HIDDEN_API_ENFORCEMENT_DISABLED; + } + + // TODO(b/135203078): Handle maybeUpdateHiddenApiEnforcementPolicy. Right now it's done + // entirely through ApplicationInfo and shouldn't touch this specific class, but that + // may not always hold true. +// if (mHiddenApiPolicy != ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT) { +// return mHiddenApiPolicy; +// } + return ApplicationInfo.HIDDEN_API_ENFORCEMENT_ENABLED; + } + + @Nullable + @Override + public SparseArray<int[]> getSplitDependencies() { + return splitDependencies; + } + + @Override + public boolean requestsIsolatedSplitLoading() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING) != 0; + } + + @Deprecated + @Override + public String getAppInfoClassLoaderName() { + return classLoaderName; + } + + @Override + public String getClassLoaderName() { + return classLoaderName; + } + + @Override + public String[] getSplitClassLoaderNames() { + return splitClassLoaderNames; + } + + @Override + public String getOverlayCategory() { + return overlayCategory; + } + + @Override + public boolean isProfileableByShell() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL) != 0; + } + + @Nullable + @Override + public List<ParsedActivityIntentInfo> getPreferredActivityFilters() { + return preferredActivityFilters; + } + + @Override + public boolean isHiddenUntilInstalled() { + return hiddenUntilInstalled; + } + + @Override + public int getMinSdkVersion() { + return minSdkVersion; + } + + @Override + public String getRestrictedAccountType() { + return restrictedAccountType; + } + + @Override + public String getRequiredAccountType() { + return requiredAccountType; + } + + @Override + public int getInstallLocation() { + return installLocation; + } + + @Override + public List<ParsedActivity> getReceivers() { + return receivers; + } + + @Override + public List<ParsedService> getServices() { + return services; + } + + @Override + public List<ParsedProvider> getProviders() { + return providers; + } + + @Override + public int getSharedUserLabel() { + return sharedUserLabel; + } + + @Override + public int getVersionCodeMajor() { + return versionCodeMajor; + } + + @Override + public boolean isRequiredForAllUsers() { + return requiredForAllUsers; + } + + @Override + public int getCompileSdkVersion() { + return compileSdkVersion; + } + + @Override + public String getCompileSdkVersionCodeName() { + return compileSdkVersionCodename; + } + + @Nullable + @Override + public List<ConfigurationInfo> getConfigPreferences() { + return configPreferences; + } + + @Nullable + @Override + public List<FeatureInfo> getReqFeatures() { + return reqFeatures; + } + + @Override + public List<FeatureGroupInfo> getFeatureGroups() { + return featureGroups; + } + + @Override + public String getDeviceProtectedDataDir() { + return deviceProtectedDataDir; + } + + @Override + public String getCredentialProtectedDataDir() { + return credentialProtectedDataDir; + } + + @Override + public String getSeInfoUser() { + return seInfoUser; + } + + @Override + public String getClassName() { + return className; + } + + @Override + public int getTheme() { + return theme; + } + + @Override + public int getRequiresSmallestWidthDp() { + return requiresSmallestWidthDp; + } + + @Override + public int getCompatibleWidthLimitDp() { + return compatibleWidthLimitDp; + } + + @Override + public int getLargestWidthLimitDp() { + return largestWidthLimitDp; + } + + @Override + public String getScanSourceDir() { + return applicationInfoCodePath; + } + + @Override + public String getScanPublicSourceDir() { + return applicationInfoResourcePath; + } + + @Override + public String getPublicSourceDir() { + return applicationInfoBaseResourcePath; + } + + @Override + public String[] getSplitPublicSourceDirs() { + return applicationInfoSplitResourcePaths; + } + + @Override + public String getSecondaryNativeLibraryDir() { + return secondaryNativeLibraryDir; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public String getManageSpaceActivityName() { + return manageSpaceActivityName; + } + + @Override + public int getDescriptionRes() { + return descriptionRes; + } + + @Override + public String getBackupAgentName() { + return backupAgentName; + } + + @Override + public int getFullBackupContent() { + return fullBackupContent; + } + + @Override + public int getNetworkSecurityConfigRes() { + return networkSecurityConfigRes; + } + + @Override + public int getCategory() { + return category; + } + + @Override + public int getTargetSandboxVersion() { + return targetSandboxVersion; + } + + @Override + public String getAppComponentFactory() { + return appComponentFactory; + } + + @Override + public int getIconRes() { + return iconRes; + } + + @Override + public int getRoundIconRes() { + return roundIconRes; + } + + @Override + public String getZygotePreloadName() { + return zygotePreloadName; + } + + @Override + public int getLabelRes() { + return labelRes; + } + + @Override + public CharSequence getNonLocalizedLabel() { + return nonLocalizedLabel; + } + + @Override + public int getIcon() { + return icon; + } + + @Override + public int getBanner() { + return banner; + } + + @Override + public int getLogo() { + return logo; + } + + @Override + public Bundle getMetaData() { + return appMetaData; + } + + @Override + @Nullable + public List<Intent> getQueriesIntents() { + return queriesIntents; + } + + @Override + @Nullable + public List<String> getQueriesPackages() { + return queriesPackages; + } + + private static void internStringArrayList(List<String> list) { + if (list != null) { + final int N = list.size(); + for (int i = 0; i < N; ++i) { + list.set(i, list.get(i).intern()); + } + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(this.supportsSmallScreens); + dest.writeInt(this.supportsNormalScreens); + dest.writeInt(this.supportsLargeScreens); + dest.writeInt(this.supportsXLargeScreens); + dest.writeInt(this.resizeable); + dest.writeInt(this.anyDensity); + dest.writeLongArray(this.lastPackageUsageTimeInMills); + dest.writeInt(this.versionCode); + dest.writeInt(this.versionCodeMajor); + dest.writeInt(this.baseRevisionCode); + dest.writeString(this.versionName); + dest.writeBoolean(this.coreApp); + dest.writeInt(this.compileSdkVersion); + dest.writeString(this.compileSdkVersionCodename); + dest.writeString(this.packageName); + dest.writeString(this.realPackage); + dest.writeString(this.manifestPackageName); + dest.writeString(this.baseCodePath); + dest.writeBoolean(this.requiredForAllUsers); + dest.writeString(this.restrictedAccountType); + dest.writeString(this.requiredAccountType); + dest.writeBoolean(this.baseHardwareAccelerated); + dest.writeString(this.overlayTarget); + dest.writeString(this.overlayTargetName); + dest.writeString(this.overlayCategory); + dest.writeInt(this.overlayPriority); + dest.writeBoolean(this.overlayIsStatic); + dest.writeString(this.staticSharedLibName); + dest.writeLong(this.staticSharedLibVersion); + dest.writeStringList(this.libraryNames); + dest.writeStringList(this.usesLibraries); + dest.writeStringList(this.usesOptionalLibraries); + dest.writeStringList(this.usesStaticLibraries); + dest.writeLongArray(this.usesStaticLibrariesVersions); + + if (this.usesStaticLibrariesCertDigests == null) { + dest.writeInt(-1); + } else { + dest.writeInt(this.usesStaticLibrariesCertDigests.length); + for (int index = 0; index < this.usesStaticLibrariesCertDigests.length; index++) { + dest.writeStringArray(this.usesStaticLibrariesCertDigests[index]); + } + } + + dest.writeString(this.sharedUserId); + dest.writeInt(this.sharedUserLabel); + dest.writeTypedList(this.configPreferences); + dest.writeTypedList(this.reqFeatures); + dest.writeTypedList(this.featureGroups); + dest.writeByteArray(this.restrictUpdateHash); + dest.writeStringList(this.originalPackages); + dest.writeStringList(this.adoptPermissions); + dest.writeStringList(this.requestedPermissions); + dest.writeStringList(this.implicitPermissions); + dest.writeArraySet(this.upgradeKeySets); + dest.writeMap(this.keySetMapping); + dest.writeStringList(this.protectedBroadcasts); + dest.writeTypedList(this.activities); + dest.writeTypedList(this.receivers); + dest.writeTypedList(this.services); + dest.writeTypedList(this.providers); + dest.writeTypedList(this.permissions); + dest.writeTypedList(this.permissionGroups); + dest.writeTypedList(this.instrumentations); + ParsedIntentInfo.writeIntentsList(this.preferredActivityFilters, dest, flags); + dest.writeBundle(this.appMetaData); + dest.writeString(this.volumeUuid); + dest.writeString(this.applicationVolumeUuid); + dest.writeParcelable(this.signingDetails, flags); + dest.writeString(this.codePath); + dest.writeBoolean(this.use32BitAbi); + dest.writeBoolean(this.visibleToInstantApps); + dest.writeString(this.cpuAbiOverride); + dest.writeBoolean(this.isStub); + dest.writeInt(this.preferredOrder); + dest.writeBoolean(this.forceQueryable); + dest.writeParcelableList(this.queriesIntents, flags); + dest.writeStringList(this.queriesPackages); + dest.writeString(this.applicationInfoBaseResourcePath); + dest.writeString(this.applicationInfoCodePath); + dest.writeString(this.applicationInfoResourcePath); + dest.writeStringArray(this.applicationInfoSplitResourcePaths); + dest.writeString(this.appComponentFactory); + dest.writeString(this.backupAgentName); + dest.writeInt(this.banner); + dest.writeInt(this.category); + dest.writeString(this.classLoaderName); + dest.writeString(this.className); + dest.writeInt(this.compatibleWidthLimitDp); + dest.writeString(this.credentialProtectedDataDir); + dest.writeString(this.dataDir); + dest.writeInt(this.descriptionRes); + dest.writeString(this.deviceProtectedDataDir); + dest.writeBoolean(this.enabled); + dest.writeInt(this.flags); + dest.writeInt(this.fullBackupContent); + dest.writeBoolean(this.hiddenUntilInstalled); + dest.writeInt(this.icon); + dest.writeInt(this.iconRes); + dest.writeInt(this.installLocation); + dest.writeInt(this.labelRes); + dest.writeInt(this.largestWidthLimitDp); + dest.writeInt(this.logo); + dest.writeString(this.manageSpaceActivityName); + dest.writeFloat(this.maxAspectRatio); + dest.writeFloat(this.minAspectRatio); + dest.writeInt(this.minSdkVersion); + dest.writeString(this.name); + dest.writeString(this.nativeLibraryDir); + dest.writeString(this.nativeLibraryRootDir); + dest.writeBoolean(this.nativeLibraryRootRequiresIsa); + dest.writeInt(this.networkSecurityConfigRes); + dest.writeCharSequence(this.nonLocalizedLabel); + dest.writeString(this.permission); + dest.writeString(this.primaryCpuAbi); + dest.writeInt(this.privateFlags); + dest.writeString(this.processName); + dest.writeInt(this.requiresSmallestWidthDp); + dest.writeInt(this.roundIconRes); + dest.writeString(this.secondaryCpuAbi); + dest.writeString(this.secondaryNativeLibraryDir); + dest.writeString(this.seInfo); + dest.writeString(this.seInfoUser); + dest.writeInt(this.targetSandboxVersion); + dest.writeInt(this.targetSdkVersion); + dest.writeString(this.taskAffinity); + dest.writeInt(this.theme); + dest.writeInt(this.uid); + dest.writeInt(this.uiOptions); + dest.writeStringArray(this.usesLibraryFiles); + dest.writeTypedList(this.usesLibraryInfos); + dest.writeString(this.zygotePreloadName); + dest.writeStringArray(this.splitClassLoaderNames); + dest.writeStringArray(this.splitCodePaths); + dest.writeSparseArray(this.splitDependencies); + dest.writeIntArray(this.splitFlags); + dest.writeStringArray(this.splitNames); + dest.writeIntArray(this.splitRevisionCodes); + } + + public PackageImpl(Parcel in) { + // We use the boot classloader for all classes that we load. + final ClassLoader boot = Object.class.getClassLoader(); + this.supportsSmallScreens = in.readInt(); + this.supportsNormalScreens = in.readInt(); + this.supportsLargeScreens = in.readInt(); + this.supportsXLargeScreens = in.readInt(); + this.resizeable = in.readInt(); + this.anyDensity = in.readInt(); + this.lastPackageUsageTimeInMills = in.createLongArray(); + this.versionCode = in.readInt(); + this.versionCodeMajor = in.readInt(); + this.baseRevisionCode = in.readInt(); + this.versionName = TextUtils.safeIntern(in.readString()); + this.coreApp = in.readBoolean(); + this.compileSdkVersion = in.readInt(); + this.compileSdkVersionCodename = TextUtils.safeIntern(in.readString()); + this.packageName = TextUtils.safeIntern(in.readString()); + this.realPackage = in.readString(); + this.manifestPackageName = in.readString(); + this.baseCodePath = in.readString(); + this.requiredForAllUsers = in.readBoolean(); + this.restrictedAccountType = in.readString(); + this.requiredAccountType = in.readString(); + this.baseHardwareAccelerated = in.readBoolean(); + this.overlayTarget = in.readString(); + this.overlayTargetName = in.readString(); + this.overlayCategory = in.readString(); + this.overlayPriority = in.readInt(); + this.overlayIsStatic = in.readBoolean(); + this.staticSharedLibName = TextUtils.safeIntern(in.readString()); + this.staticSharedLibVersion = in.readLong(); + this.libraryNames = in.createStringArrayList(); + internStringArrayList(this.libraryNames); + this.usesLibraries = in.createStringArrayList(); + internStringArrayList(this.usesLibraries); + this.usesOptionalLibraries = in.createStringArrayList(); + internStringArrayList(this.usesOptionalLibraries); + this.usesStaticLibraries = in.createStringArrayList(); + internStringArrayList(usesStaticLibraries); + this.usesStaticLibrariesVersions = in.createLongArray(); + + int digestsSize = in.readInt(); + if (digestsSize >= 0) { + this.usesStaticLibrariesCertDigests = new String[digestsSize][]; + for (int index = 0; index < digestsSize; index++) { + this.usesStaticLibrariesCertDigests[index] = in.readStringArray(); + } + } + + this.sharedUserId = TextUtils.safeIntern(in.readString()); + this.sharedUserLabel = in.readInt(); + this.configPreferences = in.createTypedArrayList(ConfigurationInfo.CREATOR); + this.reqFeatures = in.createTypedArrayList(FeatureInfo.CREATOR); + this.featureGroups = in.createTypedArrayList(FeatureGroupInfo.CREATOR); + this.restrictUpdateHash = in.createByteArray(); + this.originalPackages = in.createStringArrayList(); + this.adoptPermissions = in.createStringArrayList(); + this.requestedPermissions = in.createStringArrayList(); + internStringArrayList(this.requestedPermissions); + this.implicitPermissions = in.createStringArrayList(); + internStringArrayList(this.implicitPermissions); + this.upgradeKeySets = (ArraySet<String>) in.readArraySet(boot); + this.keySetMapping = in.readHashMap(boot); + this.protectedBroadcasts = in.createStringArrayList(); + internStringArrayList(this.protectedBroadcasts); + this.activities = in.createTypedArrayList(ParsedActivity.CREATOR); + this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR); + this.services = in.createTypedArrayList(ParsedService.CREATOR); + this.providers = in.createTypedArrayList(ParsedProvider.CREATOR); + this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR); + this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR); + this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR); + this.preferredActivityFilters = ParsedIntentInfo.createIntentsList(in); + this.appMetaData = in.readBundle(boot); + this.volumeUuid = in.readString(); + this.applicationVolumeUuid = in.readString(); + this.signingDetails = in.readParcelable(boot); + this.codePath = in.readString(); + this.use32BitAbi = in.readBoolean(); + this.visibleToInstantApps = in.readBoolean(); + this.cpuAbiOverride = in.readString(); + this.isStub = in.readBoolean(); + this.preferredOrder = in.readInt(); + this.forceQueryable = in.readBoolean(); + this.queriesIntents = in.createTypedArrayList(Intent.CREATOR); + this.queriesPackages = in.createStringArrayList(); + internStringArrayList(this.queriesPackages); + this.applicationInfoBaseResourcePath = in.readString(); + this.applicationInfoCodePath = in.readString(); + this.applicationInfoResourcePath = in.readString(); + this.applicationInfoSplitResourcePaths = in.createStringArray(); + this.appComponentFactory = in.readString(); + this.backupAgentName = in.readString(); + this.banner = in.readInt(); + this.category = in.readInt(); + this.classLoaderName = in.readString(); + this.className = in.readString(); + this.compatibleWidthLimitDp = in.readInt(); + this.credentialProtectedDataDir = in.readString(); + this.dataDir = in.readString(); + this.descriptionRes = in.readInt(); + this.deviceProtectedDataDir = in.readString(); + this.enabled = in.readBoolean(); + this.flags = in.readInt(); + this.fullBackupContent = in.readInt(); + this.hiddenUntilInstalled = in.readBoolean(); + this.icon = in.readInt(); + this.iconRes = in.readInt(); + this.installLocation = in.readInt(); + this.labelRes = in.readInt(); + this.largestWidthLimitDp = in.readInt(); + this.logo = in.readInt(); + this.manageSpaceActivityName = in.readString(); + this.maxAspectRatio = in.readFloat(); + this.minAspectRatio = in.readFloat(); + this.minSdkVersion = in.readInt(); + this.name = in.readString(); + this.nativeLibraryDir = in.readString(); + this.nativeLibraryRootDir = in.readString(); + this.nativeLibraryRootRequiresIsa = in.readBoolean(); + this.networkSecurityConfigRes = in.readInt(); + this.nonLocalizedLabel = in.readCharSequence(); + this.permission = TextUtils.safeIntern(in.readString()); + this.primaryCpuAbi = in.readString(); + this.privateFlags = in.readInt(); + this.processName = in.readString(); + this.requiresSmallestWidthDp = in.readInt(); + this.roundIconRes = in.readInt(); + this.secondaryCpuAbi = in.readString(); + this.secondaryNativeLibraryDir = in.readString(); + this.seInfo = in.readString(); + this.seInfoUser = in.readString(); + this.targetSandboxVersion = in.readInt(); + this.targetSdkVersion = in.readInt(); + this.taskAffinity = in.readString(); + this.theme = in.readInt(); + this.uid = in.readInt(); + this.uiOptions = in.readInt(); + this.usesLibraryFiles = in.createStringArray(); + this.usesLibraryInfos = in.createTypedArrayList(SharedLibraryInfo.CREATOR); + this.zygotePreloadName = in.readString(); + this.splitClassLoaderNames = in.createStringArray(); + this.splitCodePaths = in.createStringArray(); + this.splitDependencies = in.readSparseArray(boot); + this.splitFlags = in.createIntArray(); + this.splitNames = in.createStringArray(); + this.splitRevisionCodes = in.createIntArray(); + } + + public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() { + @Override + public PackageImpl createFromParcel(Parcel source) { + return new PackageImpl(source); + } + + @Override + public PackageImpl[] newArray(int size) { + return new PackageImpl[size]; + } + }; +} diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java new file mode 100644 index 000000000000..7b329ebc5b83 --- /dev/null +++ b/core/java/android/content/pm/parsing/PackageInfoUtils.java @@ -0,0 +1,732 @@ +/* + * Copyright (C) 2019 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.parsing; + +import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; + +import android.annotation.Nullable; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FallbackCategoryProvider; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; +import android.content.pm.ProviderInfo; +import android.content.pm.SELinuxUtil; +import android.content.pm.ServiceInfo; +import android.content.pm.Signature; +import android.content.pm.SigningInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.os.Bundle; +import android.os.UserHandle; + +import com.android.internal.util.ArrayUtils; + +import java.util.Set; + +/** @hide */ +public class PackageInfoUtils { + + private static final String TAG = ApkParseUtils.TAG; + + /** + * Returns true if the package is installed and not hidden, or if the caller + * explicitly wanted all uninstalled and hidden packages as well. + */ + private static boolean checkUseInstalledOrHidden(AndroidPackage pkg, PackageUserState state, + @PackageManager.PackageInfoFlags int flags) { + // Returns false if the package is hidden system app until installed. + if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0 + && !state.installed + && pkg.isHiddenUntilInstalled()) { + return false; + } + + // If available for the target user, or trying to match uninstalled packages and it's + // a system app. + return state.isAvailable(flags) + || (pkg.isSystemApp() + && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0 + || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0)); + } + + public static PackageInfo generate(AndroidPackage pkg, int[] gids, + @PackageManager.PackageInfoFlags int flags, long firstInstallTime, long lastUpdateTime, + Set<String> grantedPermissions, PackageUserState state, int userId) { + if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) { + return null; + } + ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + + PackageInfo pi = new PackageInfo(); + pi.packageName = pkg.getPackageName(); + pi.splitNames = pkg.getSplitNames(); + pi.versionCode = pkg.getVersionCode(); + pi.versionCodeMajor = pkg.getVersionCodeMajor(); + pi.baseRevisionCode = pkg.getBaseRevisionCode(); + pi.splitRevisionCodes = pkg.getSplitRevisionCodes(); + pi.versionName = pkg.getVersionName(); + pi.sharedUserId = pkg.getSharedUserId(); + pi.sharedUserLabel = pkg.getSharedUserLabel(); + pi.applicationInfo = applicationInfo; + pi.installLocation = pkg.getInstallLocation(); + pi.isStub = pkg.isStub(); + pi.coreApp = pkg.isCoreApp(); + if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 + || (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + pi.requiredForAllUsers = pkg.isRequiredForAllUsers(); + } + pi.restrictedAccountType = pkg.getRestrictedAccountType(); + pi.requiredAccountType = pkg.getRequiredAccountType(); + pi.overlayTarget = pkg.getOverlayTarget(); + pi.targetOverlayableName = pkg.getOverlayTargetName(); + pi.overlayCategory = pkg.getOverlayCategory(); + pi.overlayPriority = pkg.getOverlayPriority(); + pi.mOverlayIsStatic = pkg.isOverlayIsStatic(); + pi.compileSdkVersion = pkg.getCompileSdkVersion(); + pi.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName(); + pi.firstInstallTime = firstInstallTime; + pi.lastUpdateTime = lastUpdateTime; + if ((flags & PackageManager.GET_GIDS) != 0) { + pi.gids = gids; + } + if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) { + int size = pkg.getConfigPreferences() != null ? pkg.getConfigPreferences().size() : 0; + if (size > 0) { + pi.configPreferences = new ConfigurationInfo[size]; + pkg.getConfigPreferences().toArray(pi.configPreferences); + } + size = pkg.getReqFeatures() != null ? pkg.getReqFeatures().size() : 0; + if (size > 0) { + pi.reqFeatures = new FeatureInfo[size]; + pkg.getReqFeatures().toArray(pi.reqFeatures); + } + size = pkg.getFeatureGroups() != null ? pkg.getFeatureGroups().size() : 0; + if (size > 0) { + pi.featureGroups = new FeatureGroupInfo[size]; + pkg.getFeatureGroups().toArray(pi.featureGroups); + } + } + if ((flags & PackageManager.GET_ACTIVITIES) != 0) { + if (pkg.getActivities() != null) { + final int N = pkg.getActivities().size(); + if (N > 0) { + int num = 0; + final ActivityInfo[] res = new ActivityInfo[N]; + for (int i = 0; i < N; i++) { + final ParsedActivity a = pkg.getActivities().get(i); + if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) { + if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals( + a.className)) { + continue; + } + res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, + userId); + } + } + pi.activities = ArrayUtils.trimToSize(res, num); + } + } + } + if ((flags & PackageManager.GET_RECEIVERS) != 0) { + if (pkg.getReceivers() != null) { + final int size = pkg.getReceivers().size(); + if (size > 0) { + int num = 0; + final ActivityInfo[] res = new ActivityInfo[size]; + for (int i = 0; i < size; i++) { + final ParsedActivity a = pkg.getReceivers().get(i); + if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), a, flags)) { + res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo, + userId); + } + } + pi.receivers = ArrayUtils.trimToSize(res, num); + } + } + } + if ((flags & PackageManager.GET_SERVICES) != 0) { + if (pkg.getServices() != null) { + final int size = pkg.getServices().size(); + if (size > 0) { + int num = 0; + final ServiceInfo[] res = new ServiceInfo[size]; + for (int i = 0; i < size; i++) { + final ComponentParseUtils.ParsedService s = pkg.getServices().get(i); + if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), s, flags)) { + res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo, + userId); + } + } + pi.services = ArrayUtils.trimToSize(res, num); + } + } + } + if ((flags & PackageManager.GET_PROVIDERS) != 0) { + if (pkg.getProviders() != null) { + final int size = pkg.getProviders().size(); + if (size > 0) { + int num = 0; + final ProviderInfo[] res = new ProviderInfo[size]; + for (int i = 0; i < size; i++) { + final ComponentParseUtils.ParsedProvider pr = pkg.getProviders() + .get(i); + if (state.isMatch(pkg.isSystem(), pkg.isEnabled(), pr, flags)) { + res[num++] = generateProviderInfo(pkg, pr, flags, state, + applicationInfo, userId); + } + } + pi.providers = ArrayUtils.trimToSize(res, num); + } + } + } + if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) { + if (pkg.getInstrumentations() != null) { + int N = pkg.getInstrumentations().size(); + if (N > 0) { + pi.instrumentation = new InstrumentationInfo[N]; + for (int i = 0; i < N; i++) { + pi.instrumentation[i] = generateInstrumentationInfo( + pkg.getInstrumentations().get(i), flags); + } + } + } + } + if ((flags & PackageManager.GET_PERMISSIONS) != 0) { + if (pkg.getPermissions() != null) { + int N = ArrayUtils.size(pkg.getPermissions()); + if (N > 0) { + pi.permissions = new PermissionInfo[N]; + for (int i = 0; i < N; i++) { + pi.permissions[i] = generatePermissionInfo( + pkg.getPermissions().get(i), + flags + ); + } + } + } + if (pkg.getRequestedPermissions() != null) { + int N = pkg.getRequestedPermissions().size(); + if (N > 0) { + pi.requestedPermissions = new String[N]; + pi.requestedPermissionsFlags = new int[N]; + for (int i = 0; i < N; i++) { + final String perm = pkg.getRequestedPermissions().get(i); + pi.requestedPermissions[i] = perm; + // The notion of required permissions is deprecated but for compatibility. + pi.requestedPermissionsFlags[i] |= + PackageInfo.REQUESTED_PERMISSION_REQUIRED; + if (grantedPermissions != null && grantedPermissions.contains(perm)) { + pi.requestedPermissionsFlags[i] |= + PackageInfo.REQUESTED_PERMISSION_GRANTED; + } + } + } + } + } + + PackageParser.SigningDetails signingDetails = pkg.getSigningDetails(); + // deprecated method of getting signing certificates + if ((flags & PackageManager.GET_SIGNATURES) != 0) { + if (signingDetails.hasPastSigningCertificates()) { + // Package has included signing certificate rotation information. Return the oldest + // cert so that programmatic checks keep working even if unaware of key rotation. + pi.signatures = new Signature[1]; + pi.signatures[0] = signingDetails.pastSigningCertificates[0]; + } else if (signingDetails.hasSignatures()) { + // otherwise keep old behavior + int numberOfSigs = signingDetails.signatures.length; + pi.signatures = new Signature[numberOfSigs]; + System.arraycopy(signingDetails.signatures, 0, pi.signatures, 0, + numberOfSigs); + } + } + + // replacement for GET_SIGNATURES + if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) { + if (signingDetails != PackageParser.SigningDetails.UNKNOWN) { + // only return a valid SigningInfo if there is signing information to report + pi.signingInfo = new SigningInfo(signingDetails); + } else { + pi.signingInfo = null; + } + } + + return pi; + } + + // TODO(b/135203078): Remove this in favor of AndroidPackage.toAppInfo() + private static ApplicationInfo appInfoFromFinalPackage(AndroidPackage pkg) { + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.name = pkg.getName(); + if (appInfo.name != null) appInfo.name = appInfo.name.trim(); + appInfo.packageName = pkg.getPackageName(); + appInfo.labelRes = pkg.getLabelRes(); + appInfo.nonLocalizedLabel = pkg.getNonLocalizedLabel(); + if (appInfo.nonLocalizedLabel != null) { + appInfo.nonLocalizedLabel = appInfo.nonLocalizedLabel.toString().trim(); + } + appInfo.icon = pkg.getIcon(); + appInfo.banner = pkg.getBanner(); + appInfo.logo = pkg.getLogo(); + appInfo.metaData = pkg.getMetaData(); + + // TODO(b/135203078): Can this be removed? Looks only used in ActivityInfo. +// appInfo.showUserIcon = pkg.getShowUserIcon(); + + appInfo.taskAffinity = pkg.getTaskAffinity(); + appInfo.permission = pkg.getPermission(); + appInfo.processName = pkg.getProcessName(); + appInfo.className = pkg.getClassName(); + appInfo.theme = pkg.getTheme(); + appInfo.flags = pkg.getFlags(); + appInfo.privateFlags = pkg.getPrivateFlags(); + appInfo.requiresSmallestWidthDp = pkg.getRequiresSmallestWidthDp(); + appInfo.compatibleWidthLimitDp = pkg.getCompatibleWidthLimitDp(); + appInfo.largestWidthLimitDp = pkg.getLargestWidthLimitDp(); + appInfo.volumeUuid = pkg.getVolumeUuid(); + appInfo.storageUuid = pkg.getStorageUuid(); + appInfo.scanSourceDir = pkg.getScanSourceDir(); + appInfo.scanPublicSourceDir = pkg.getScanPublicSourceDir(); + appInfo.sourceDir = pkg.getBaseCodePath(); + appInfo.publicSourceDir = pkg.getPublicSourceDir(); + appInfo.splitNames = pkg.getSplitNames(); + appInfo.splitSourceDirs = pkg.getSplitCodePaths(); + appInfo.splitPublicSourceDirs = pkg.getSplitPublicSourceDirs(); + appInfo.splitDependencies = pkg.getSplitDependencies(); + appInfo.nativeLibraryDir = pkg.getNativeLibraryDir(); + appInfo.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir(); + appInfo.nativeLibraryRootDir = pkg.getNativeLibraryRootDir(); + appInfo.nativeLibraryRootRequiresIsa = pkg.isNativeLibraryRootRequiresIsa(); + appInfo.primaryCpuAbi = pkg.getPrimaryCpuAbi(); + appInfo.secondaryCpuAbi = pkg.getSecondaryCpuAbi(); + + // TODO(b/135203078): Unused? +// appInfo.resourceDirs = pkg.getResourceDirs(); + appInfo.seInfo = pkg.getSeInfo(); + appInfo.seInfoUser = pkg.getSeInfoUser(); + appInfo.sharedLibraryFiles = pkg.getUsesLibraryFiles(); + appInfo.sharedLibraryInfos = pkg.getUsesLibraryInfos(); + appInfo.dataDir = pkg.getDataDir(); + appInfo.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir(); + appInfo.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir(); + appInfo.uid = pkg.getUid(); + appInfo.minSdkVersion = pkg.getMinSdkVersion(); + appInfo.targetSdkVersion = pkg.getTargetSdkVersion(); + appInfo.setVersionCode(pkg.getLongVersionCode()); + appInfo.enabled = pkg.isEnabled(); + + // TODO(b/135203078): Unused? +// appInfo.enabledSetting = pkg.getEnabledSetting(); + appInfo.installLocation = pkg.getInstallLocation(); + appInfo.manageSpaceActivityName = pkg.getManageSpaceActivityName(); + appInfo.descriptionRes = pkg.getDescriptionRes(); + appInfo.uiOptions = pkg.getUiOptions(); + appInfo.backupAgentName = pkg.getBackupAgentName(); + appInfo.fullBackupContent = pkg.getFullBackupContent(); + appInfo.networkSecurityConfigRes = pkg.getNetworkSecurityConfigRes(); + appInfo.category = pkg.getCategory(); + appInfo.targetSandboxVersion = pkg.getTargetSandboxVersion(); + appInfo.classLoaderName = pkg.getClassLoaderName(); + appInfo.splitClassLoaderNames = pkg.getSplitClassLoaderNames(); + appInfo.appComponentFactory = pkg.getAppComponentFactory(); + appInfo.iconRes = pkg.getIconRes(); + appInfo.roundIconRes = pkg.getRoundIconRes(); + appInfo.compileSdkVersion = pkg.getCompileSdkVersion(); + appInfo.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName(); + + // TODO(b/135203078): See PackageImpl#getHiddenApiEnforcementPolicy +// appInfo.mHiddenApiPolicy = pkg.getHiddenApiPolicy(); + appInfo.hiddenUntilInstalled = pkg.isHiddenUntilInstalled(); + appInfo.zygotePreloadName = pkg.getZygotePreloadName(); + return appInfo; + } + + public static ApplicationInfo generateApplicationInfo(AndroidPackage pkg, + @PackageManager.ApplicationInfoFlags int flags, PackageUserState state, int userId) { + + if (pkg == null) return null; + if (!checkUseInstalledOrHidden(pkg, state, flags) || !pkg.isMatch(flags)) { + return null; + } + if (!copyNeeded(flags, pkg, state, null, userId) + && ((flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) == 0 + || state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) { + // TODO(b/135203078): This isn't applicable anymore, as AppInfo isn't cached and + // always built new in toAppInfo(). Remove entire copyNeeded flow? Or find a way to + // transiently cache AppInfo, since multiple calls in quick secession probably need + // the same AppInfo. + // In this case it is safe to directly modify the internal ApplicationInfo state: + // - CompatibilityMode is global state, so will be the same for every call. + // - We only come in to here if the app should reported as installed; this is the + // default state, and we will do a copy otherwise. + // - The enable state will always be reported the same for the application across + // calls; the only exception is for the UNTIL_USED mode, and in that case we will + // be doing a copy. + ApplicationInfo applicationInfo = pkg.toAppInfo(); + updateApplicationInfo(applicationInfo, flags, state); + return applicationInfo; + } + + // Make shallow copy so we can store the metadata/libraries safely + ApplicationInfo ai = appInfoFromFinalPackage(pkg); + ai.initForUser(userId); + if ((flags & PackageManager.GET_META_DATA) != 0) { + ai.metaData = pkg.getAppMetaData(); + } + if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { + ai.sharedLibraryFiles = pkg.getUsesLibraryFiles(); + ai.sharedLibraryInfos = pkg.getUsesLibraryInfos(); + } + if (state.stopped) { + ai.flags |= ApplicationInfo.FLAG_STOPPED; + } else { + ai.flags &= ~ApplicationInfo.FLAG_STOPPED; + } + updateApplicationInfo(ai, flags, state); + + return ai; + } + + private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, + @Nullable ApplicationInfo applicationInfo, int userId) { + if (a == null) return null; + if (!checkUseInstalledOrHidden(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + if (!copyNeeded(flags, pkg, state, a.metaData, userId)) { + updateApplicationInfo(applicationInfo, flags, state); + } + // Make shallow copies so we can store the metadata safely + ActivityInfo ai = new ActivityInfo(); + assignSharedFieldsForComponentInfo(ai, a); + ai.targetActivity = a.targetActivity; + ai.processName = a.getProcessName(); + ai.exported = a.exported; + ai.theme = a.theme; + ai.uiOptions = a.uiOptions; + ai.parentActivityName = a.parentActivityName; + ai.permission = a.getPermission(); + ai.taskAffinity = a.taskAffinity; + ai.flags = a.flags; + ai.privateFlags = a.privateFlags; + ai.launchMode = a.launchMode; + ai.documentLaunchMode = a.documentLaunchMode; + ai.maxRecents = a.maxRecents; + ai.configChanges = a.configChanges; + ai.softInputMode = a.softInputMode; + ai.persistableMode = a.persistableMode; + ai.lockTaskLaunchMode = a.lockTaskLaunchMode; + ai.screenOrientation = a.screenOrientation; + ai.resizeMode = a.resizeMode; + ai.maxAspectRatio = a.maxAspectRatio; + ai.minAspectRatio = a.minAspectRatio; + ai.requestedVrComponent = a.requestedVrComponent; + ai.rotationAnimation = a.rotationAnimation; + ai.colorMode = a.colorMode; + ai.windowLayout = a.windowLayout; + ai.metaData = a.metaData; + ai.applicationInfo = applicationInfo; + return ai; + } + + public static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a, + @PackageManager.ComponentInfoFlags int flags, PackageUserState state, int userId) { + return generateActivityInfo(pkg, a, flags, state, null, userId); + } + + private static ServiceInfo generateServiceInfo(AndroidPackage pkg, + ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags, + PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) { + if (s == null) return null; + if (!checkUseInstalledOrHidden(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + if (!copyNeeded(flags, pkg, state, s.metaData, userId)) { + updateApplicationInfo(applicationInfo, flags, state); + } + // Make shallow copies so we can store the metadata safely + ServiceInfo si = new ServiceInfo(); + assignSharedFieldsForComponentInfo(si, s); + si.exported = s.exported; + si.flags = s.flags; + si.metaData = s.metaData; + si.permission = s.getPermission(); + si.processName = s.getProcessName(); + si.mForegroundServiceType = s.foregroundServiceType; + si.metaData = s.metaData; + si.applicationInfo = applicationInfo; + return si; + } + + public static ServiceInfo generateServiceInfo(AndroidPackage pkg, + ComponentParseUtils.ParsedService s, @PackageManager.ComponentInfoFlags int flags, + PackageUserState state, int userId) { + return generateServiceInfo(pkg, s, flags, state, null, userId); + } + + private static ProviderInfo generateProviderInfo(AndroidPackage pkg, + ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags, + PackageUserState state, @Nullable ApplicationInfo applicationInfo, int userId) { + if (p == null) return null; + if (!checkUseInstalledOrHidden(pkg, state, flags)) { + return null; + } + if (applicationInfo == null) { + applicationInfo = generateApplicationInfo(pkg, flags, state, userId); + } + if (!copyNeeded(flags, pkg, state, p.metaData, userId) + && ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) != 0 + || p.uriPermissionPatterns == null)) { + updateApplicationInfo(applicationInfo, flags, state); + } + // Make shallow copies so we can store the metadata safely + ProviderInfo pi = new ProviderInfo(); + assignSharedFieldsForComponentInfo(pi, p); + pi.exported = p.exported; + pi.flags = p.flags; + pi.processName = p.getProcessName(); + pi.authority = p.getAuthority(); + pi.isSyncable = p.isSyncable; + pi.readPermission = p.getReadPermission(); + pi.writePermission = p.getWritePermission(); + pi.grantUriPermissions = p.grantUriPermissions; + pi.forceUriPermissions = p.forceUriPermissions; + pi.multiprocess = p.multiProcess; + pi.initOrder = p.initOrder; + pi.uriPermissionPatterns = p.uriPermissionPatterns; + pi.pathPermissions = p.pathPermissions; + pi.metaData = p.metaData; + if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { + pi.uriPermissionPatterns = null; + } + pi.applicationInfo = applicationInfo; + return pi; + } + + public static ProviderInfo generateProviderInfo(AndroidPackage pkg, + ComponentParseUtils.ParsedProvider p, @PackageManager.ComponentInfoFlags int flags, + PackageUserState state, int userId) { + return generateProviderInfo(pkg, p, flags, state, null, userId); + } + + public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i, + @PackageManager.ComponentInfoFlags int flags) { + if (i == null) return null; + + InstrumentationInfo ii = new InstrumentationInfo(); + assignSharedFieldsForPackageItemInfo(ii, i); + ii.targetPackage = i.getTargetPackage(); + ii.targetProcesses = i.getTargetProcesses(); + ii.handleProfiling = i.handleProfiling; + ii.functionalTest = i.functionalTest; + + ii.sourceDir = i.sourceDir; + ii.publicSourceDir = i.publicSourceDir; + ii.splitNames = i.splitNames; + ii.splitSourceDirs = i.splitSourceDirs; + ii.splitPublicSourceDirs = i.splitPublicSourceDirs; + ii.splitDependencies = i.splitDependencies; + ii.dataDir = i.dataDir; + ii.deviceProtectedDataDir = i.deviceProtectedDataDir; + ii.credentialProtectedDataDir = i.credentialProtectedDataDir; + ii.primaryCpuAbi = i.primaryCpuAbi; + ii.secondaryCpuAbi = i.secondaryCpuAbi; + ii.nativeLibraryDir = i.nativeLibraryDir; + ii.secondaryNativeLibraryDir = i.secondaryNativeLibraryDir; + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return ii; + } + ii.metaData = i.metaData; + return ii; + } + + public static PermissionInfo generatePermissionInfo(ParsedPermission p, + @PackageManager.ComponentInfoFlags int flags) { + if (p == null) return null; + + PermissionInfo pi = new PermissionInfo(p.backgroundPermission); + assignSharedFieldsForPackageItemInfo(pi, p); + pi.group = p.getGroup(); + pi.requestRes = p.requestRes; + pi.protectionLevel = p.protectionLevel; + pi.descriptionRes = p.descriptionRes; + pi.flags = p.flags; + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return pi; + } + pi.metaData = p.metaData; + return pi; + } + + public static PermissionGroupInfo generatePermissionGroupInfo(ParsedPermissionGroup pg, + @PackageManager.ComponentInfoFlags int flags) { + if (pg == null) return null; + + PermissionGroupInfo pgi = new PermissionGroupInfo( + pg.requestDetailResourceId, + pg.backgroundRequestResourceId, + pg.backgroundRequestDetailResourceId + ); + assignSharedFieldsForPackageItemInfo(pgi, pg); + pgi.priority = pg.priority; + pgi.requestRes = pg.requestRes; + pgi.flags = pg.flags; + + if ((flags & PackageManager.GET_META_DATA) == 0) { + return pgi; + } + pgi.metaData = pg.metaData; + return pgi; + } + + private static boolean copyNeeded(@PackageManager.ComponentInfoFlags int flags, + AndroidPackage pkg, PackageUserState state, Bundle metaData, int userId) { + if (userId != UserHandle.USER_SYSTEM) { + // We always need to copy for other users, since we need + // to fix up the uid. + return true; + } + if (state.enabled != PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + boolean enabled = state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED; + if (pkg.isEnabled() != enabled) { + return true; + } + } + boolean suspended = (pkg.getFlags() & FLAG_SUSPENDED) != 0; + if (state.suspended != suspended) { + return true; + } + if (!state.installed || state.hidden) { + return true; + } + if (state.stopped) { + return true; + } + if (state.instantApp != pkg.isInstantApp()) { + return true; + } + if ((flags & PackageManager.GET_META_DATA) != 0 + && (metaData != null || pkg.getAppMetaData() != null)) { + return true; + } + if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 + && pkg.getUsesLibraryFiles() != null) { + return true; + } + if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0 + && pkg.getUsesLibraryInfos() != null) { + return true; + } + return pkg.getStaticSharedLibName() != null; + } + + private static void updateApplicationInfo(ApplicationInfo ai, + @PackageManager.ApplicationInfoFlags int flags, + PackageUserState state) { + // CompatibilityMode is global state. + if (!PackageParser.sCompatibilityModeEnabled) { + ai.disableCompatibilityMode(); + } + if (state.installed) { + ai.flags |= ApplicationInfo.FLAG_INSTALLED; + } else { + ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; + } + if (state.suspended) { + ai.flags |= ApplicationInfo.FLAG_SUSPENDED; + } else { + ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED; + } + if (state.instantApp) { + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_INSTANT; + } else { + ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_INSTANT; + } + if (state.virtualPreload) { + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; + } else { + ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD; + } + if (state.hidden) { + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; + } else { + ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; + } + if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + ai.enabled = true; + } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { + ai.enabled = (flags & PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0; + } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED + || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { + ai.enabled = false; + } + ai.enabledSetting = state.enabled; + if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { + ai.category = state.categoryHint; + } + if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) { + ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName); + } + ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state); + ai.resourceDirs = state.overlayPaths; + ai.icon = (PackageParser.sUseRoundIcon && ai.roundIconRes != 0) + ? ai.roundIconRes : ai.iconRes; + } + + private static void assignSharedFieldsForPackageItemInfo(PackageItemInfo packageItemInfo, + ComponentParseUtils.ParsedComponent parsedComponent) { + packageItemInfo.banner = parsedComponent.banner; + packageItemInfo.icon = parsedComponent.icon; + packageItemInfo.labelRes = parsedComponent.labelRes; + packageItemInfo.logo = parsedComponent.logo; + packageItemInfo.name = parsedComponent.className; + packageItemInfo.nonLocalizedLabel = parsedComponent.nonLocalizedLabel; + packageItemInfo.packageName = parsedComponent.getPackageName(); + } + + private static void assignSharedFieldsForComponentInfo(ComponentInfo componentInfo, + ComponentParseUtils.ParsedComponent parsedComponent) { + assignSharedFieldsForPackageItemInfo(componentInfo, parsedComponent); + componentInfo.descriptionRes = parsedComponent.descriptionRes; + componentInfo.directBootAware = parsedComponent.directBootAware; + componentInfo.enabled = parsedComponent.enabled; + componentInfo.splitName = parsedComponent.getSplitName(); + } + +} diff --git a/core/java/android/content/pm/parsing/ParsedPackage.java b/core/java/android/content/pm/parsing/ParsedPackage.java new file mode 100644 index 000000000000..05cf586522f2 --- /dev/null +++ b/core/java/android/content/pm/parsing/ParsedPackage.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2019 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.parsing; + +import android.content.pm.PackageParser; + +/** + * Methods used for mutation after direct package parsing, mostly done inside + * {@link com.android.server.pm.PackageManagerService}. + * + * Java disallows defining this as an inner interface, so this must be a separate file. + * + * @hide + */ +public interface ParsedPackage extends AndroidPackage { + + AndroidPackage hideAsFinal(); + + ParsedPackage addUsesLibrary(int index, String libraryName); + + ParsedPackage addUsesOptionalLibrary(int index, String libraryName); + + ParsedPackage capPermissionPriorities(); + + ParsedPackage clearAdoptPermissions(); + + ParsedPackage clearOriginalPackages(); + + ParsedPackage clearProtectedBroadcasts(); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #setCodePath(String)} + */ + @Deprecated + ParsedPackage setApplicationInfoCodePath(String applicationInfoCodePath); + + /** + * TODO(b/135203078): Use non-AppInfo method + * @deprecated use {@link #setCodePath(String)} + */ + @Deprecated + ParsedPackage setApplicationInfoResourcePath(String applicationInfoResourcePath); + + ParsedPackage setBaseCodePath(String baseCodePath); + + ParsedPackage setCodePath(String codePath); + + ParsedPackage setCpuAbiOverride(String cpuAbiOverride); + + ParsedPackage setNativeLibraryDir(String nativeLibraryDir); + + ParsedPackage setNativeLibraryRootDir(String nativeLibraryRootDir); + + ParsedPackage setPackageName(String packageName); + + ParsedPackage setPrimaryCpuAbi(String primaryCpuAbi); + + ParsedPackage setProcessName(String processName); + + ParsedPackage setRealPackage(String realPackage); + + ParsedPackage setSecondaryCpuAbi(String secondaryCpuAbi); + + ParsedPackage setSigningDetails(PackageParser.SigningDetails signingDetails); + + ParsedPackage setSplitCodePaths(String[] splitCodePaths); + + ParsedPackage initForUser(int userId); + + ParsedPackage setNativeLibraryRootRequiresIsa(boolean nativeLibraryRootRequiresIsa); + + ParsedPackage setAllComponentsDirectBootAware(boolean allComponentsDirectBootAware); + + ParsedPackage setFactoryTest(boolean factoryTest); + + ParsedPackage markNotActivitiesAsNotExportedIfSingleUser(); + + ParsedPackage setOdm(boolean odm); + + ParsedPackage setOem(boolean oem); + + ParsedPackage setPrivileged(boolean privileged); + + ParsedPackage setProduct(boolean product); + + ParsedPackage setSignedWithPlatformKey(boolean signedWithPlatformKey); + + ParsedPackage setSystem(boolean system); + + ParsedPackage setSystemExt(boolean systemExt); + + ParsedPackage setUpdatedSystemApp(boolean updatedSystemApp); + + ParsedPackage setVendor(boolean vendor); + + ParsedPackage removePermission(int index); + + ParsedPackage removeUsesLibrary(String libraryName); + + ParsedPackage removeUsesOptionalLibrary(String libraryName); + + ParsedPackage setApplicationInfoBaseResourcePath(String applicationInfoBaseResourcePath); + + ParsedPackage setApplicationInfoSplitResourcePaths( + String[] applicationInfoSplitResourcePaths); + + ParsedPackage setApplicationVolumeUuid(String applicationVolumeUuid); + + ParsedPackage setCoreApp(boolean coreApp); + + ParsedPackage setIsStub(boolean isStub); + + // TODO(b/135203078): Remove entirely + ParsedPackage setPackageSettingCallback(PackageSettingCallback packageSettingCallback); + + ParsedPackage setRestrictUpdateHash(byte[] restrictUpdateHash); + + ParsedPackage setSeInfo(String seInfo); + + ParsedPackage setSeInfoUser(String seInfoUser); + + ParsedPackage setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir); + + ParsedPackage setUid(int uid); + + ParsedPackage setVersionCode(int versionCode); + + ParsedPackage setVersionCodeMajor(int versionCodeMajor); + + // TODO(b/135203078): Move logic earlier in parse chain so nothing needs to be reverted + ParsedPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage); + + ParsedPackage setDirectBootAware(boolean directBootAware); + + ParsedPackage setPersistent(boolean persistent); + + interface PackageSettingCallback { + default void setAndroidPackage(AndroidPackage pkg){} + } +} diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java new file mode 100644 index 000000000000..43c1f6e335b0 --- /dev/null +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2019 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.parsing; + +import android.annotation.Nullable; +import android.content.Intent; +import android.content.pm.ConfigurationInfo; +import android.content.pm.FeatureGroupInfo; +import android.content.pm.FeatureInfo; +import android.content.pm.PackageParser; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.os.Bundle; +import android.util.ArraySet; +import android.util.SparseArray; + +import java.security.PublicKey; + +/** + * Methods used for mutation during direct package parsing. + * + * Java disallows defining this as an inner interface, so this must be a separate file. + * + * @hide + */ +public interface ParsingPackage extends AndroidPackage { + + ParsingPackage addActivity(ParsedActivity parsedActivity); + + ParsingPackage addAdoptPermission(String adoptPermission); + + ParsingPackage addConfigPreference(ConfigurationInfo configPreference); + + ParsingPackage addFeatureGroup(FeatureGroupInfo featureGroup); + + ParsingPackage addImplicitPermission(String permission); + + ParsingPackage addInstrumentation(ParsedInstrumentation instrumentation); + + ParsingPackage addKeySet(String keySetName, PublicKey publicKey); + + ParsingPackage addLibraryName(String libraryName); + + ParsingPackage addOriginalPackage(String originalPackage); + + ParsingPackage addPermission(ParsedPermission permission); + + ParsingPackage addPermissionGroup(ParsedPermissionGroup permissionGroup); + + ParsingPackage addPreferredActivityFilter(ParsedActivityIntentInfo activityIntentInfo); + + ParsingPackage addProtectedBroadcast(String protectedBroadcast); + + ParsingPackage addProvider(ParsedProvider parsedProvider); + + ParsingPackage addReceiver(ParsedActivity parsedReceiver); + + ParsingPackage addReqFeature(FeatureInfo reqFeature); + + ParsingPackage addRequestedPermission(String permission); + + ParsingPackage addService(ParsedService parsedService); + + ParsingPackage addUsesLibrary(String libraryName); + + ParsingPackage addUsesOptionalLibrary(String libraryName); + + ParsingPackage addUsesStaticLibrary(String libraryName); + + ParsingPackage addUsesStaticLibraryCertDigests(String[] certSha256Digests); + + ParsingPackage addUsesStaticLibraryVersion(long version); + + ParsingPackage addQueriesIntent(Intent intent); + + ParsingPackage addQueriesPackage(String packageName); + + ParsingPackage asSplit( + String[] splitNames, + String[] splitCodePaths, + int[] splitRevisionCodes, + @Nullable SparseArray<int[]> splitDependencies + ); + + ParsingPackage setAppMetaData(Bundle appMetaData); + + ParsingPackage setForceQueryable(boolean forceQueryable); + + ParsingPackage setMaxAspectRatio(float maxAspectRatio); + + ParsingPackage setMinAspectRatio(float minAspectRatio); + + ParsingPackage setName(String name); + + ParsingPackage setPermission(String permission); + + ParsingPackage setProcessName(String processName); + + ParsingPackage setSharedUserId(String sharedUserId); + + ParsingPackage setStaticSharedLibName(String staticSharedLibName); + + ParsingPackage setTaskAffinity(String taskAffinity); + + ParsingPackage setTargetSdkVersion(int targetSdkVersion); + + ParsingPackage setUiOptions(int uiOptions); + + ParsingPackage setBaseHardwareAccelerated(boolean baseHardwareAccelerated); + + ParsingPackage setActivitiesResizeModeResizeable(boolean resizeable); + + ParsingPackage setActivitiesResizeModeResizeableViaSdkVersion(boolean resizeableViaSdkVersion); + + ParsingPackage setAllowAudioPlaybackCapture(boolean allowAudioPlaybackCapture); + + ParsingPackage setAllowBackup(boolean allowBackup); + + ParsingPackage setAllowClearUserData(boolean allowClearUserData); + + ParsingPackage setAllowClearUserDataOnFailedRestore(boolean allowClearUserDataOnFailedRestore); + + ParsingPackage setAllowTaskReparenting(boolean allowTaskReparenting); + + ParsingPackage setIsOverlay(boolean isOverlay); + + ParsingPackage setBackupInForeground(boolean backupInForeground); + + ParsingPackage setCantSaveState(boolean cantSaveState); + + ParsingPackage setDebuggable(boolean debuggable); + + ParsingPackage setDefaultToDeviceProtectedStorage(boolean defaultToDeviceProtectedStorage); + + ParsingPackage setDirectBootAware(boolean directBootAware); + + ParsingPackage setExternalStorage(boolean externalStorage); + + ParsingPackage setExtractNativeLibs(boolean extractNativeLibs); + + ParsingPackage setFullBackupOnly(boolean fullBackupOnly); + + ParsingPackage setHasCode(boolean hasCode); + + ParsingPackage setHasFragileUserData(boolean hasFragileUserData); + + ParsingPackage setIsGame(boolean isGame); + + ParsingPackage setIsolatedSplitLoading(boolean isolatedSplitLoading); + + ParsingPackage setKillAfterRestore(boolean killAfterRestore); + + ParsingPackage setLargeHeap(boolean largeHeap); + + ParsingPackage setMultiArch(boolean multiArch); + + ParsingPackage setPartiallyDirectBootAware(boolean partiallyDirectBootAware); + + ParsingPackage setPersistent(boolean persistent); + + ParsingPackage setProfileableByShell(boolean profileableByShell); + + ParsingPackage setRequestLegacyExternalStorage(boolean requestLegacyExternalStorage); + + ParsingPackage setRestoreAnyVersion(boolean restoreAnyVersion); + + ParsingPackage setSplitHasCode(int splitIndex, boolean splitHasCode); + + ParsingPackage setStaticSharedLibrary(boolean staticSharedLibrary); + + ParsingPackage setSupportsRtl(boolean supportsRtl); + + ParsingPackage setTestOnly(boolean testOnly); + + ParsingPackage setUseEmbeddedDex(boolean useEmbeddedDex); + + ParsingPackage setUsesCleartextTraffic(boolean usesCleartextTraffic); + + ParsingPackage setUsesNonSdkApi(boolean usesNonSdkApi); + + ParsingPackage setVisibleToInstantApps(boolean visibleToInstantApps); + + ParsingPackage setVmSafeMode(boolean vmSafeMode); + + ParsingPackage removeUsesOptionalLibrary(String libraryName); + + ParsingPackage setAnyDensity(int anyDensity); + + ParsingPackage setAppComponentFactory(String appComponentFactory); + + ParsingPackage setApplicationVolumeUuid(String applicationVolumeUuid); + + ParsingPackage setBackupAgentName(String backupAgentName); + + ParsingPackage setBanner(int banner); + + ParsingPackage setCategory(int category); + + ParsingPackage setClassLoaderName(String classLoaderName); + + ParsingPackage setClassName(String className); + + ParsingPackage setCodePath(String codePath); + + ParsingPackage setCompatibleWidthLimitDp(int compatibleWidthLimitDp); + + ParsingPackage setDescriptionRes(int descriptionRes); + + ParsingPackage setEnabled(boolean enabled); + + ParsingPackage setFullBackupContent(int fullBackupContent); + + ParsingPackage setHasDomainUrls(boolean hasDomainUrls); + + ParsingPackage setIcon(int icon); + + ParsingPackage setIconRes(int iconRes); + + ParsingPackage setInstallLocation(int installLocation); + + ParsingPackage setLabelRes(int labelRes); + + ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp); + + ParsingPackage setLogo(int logo); + + ParsingPackage setManageSpaceActivityName(String manageSpaceActivityName); + + ParsingPackage setMinSdkVersion(int minSdkVersion); + + ParsingPackage setNetworkSecurityConfigRes(int networkSecurityConfigRes); + + ParsingPackage setNonLocalizedLabel(CharSequence nonLocalizedLabel); + + ParsingPackage setOverlayCategory(String overlayCategory); + + ParsingPackage setOverlayIsStatic(boolean overlayIsStatic); + + ParsingPackage setOverlayPriority(int overlayPriority); + + ParsingPackage setOverlayTarget(String overlayTarget); + + ParsingPackage setOverlayTargetName(String overlayTargetName); + + ParsingPackage setRealPackage(String realPackage); + + ParsingPackage setRequiredAccountType(String requiredAccountType); + + ParsingPackage setRequiredForAllUsers(boolean requiredForAllUsers); + + ParsingPackage setRequiresSmallestWidthDp(int requiresSmallestWidthDp); + + ParsingPackage setResizeable(int resizeable); + + ParsingPackage setRestrictUpdateHash(byte[] restrictUpdateHash); + + ParsingPackage setRestrictedAccountType(String restrictedAccountType); + + ParsingPackage setRoundIconRes(int roundIconRes); + + ParsingPackage setSharedUserLabel(int sharedUserLabel); + + ParsingPackage setSigningDetails(PackageParser.SigningDetails signingDetails); + + ParsingPackage setSplitClassLoaderName(int splitIndex, String classLoaderName); + + ParsingPackage setStaticSharedLibVersion(long staticSharedLibVersion); + + ParsingPackage setSupportsLargeScreens(int supportsLargeScreens); + + ParsingPackage setSupportsNormalScreens(int supportsNormalScreens); + + ParsingPackage setSupportsSmallScreens(int supportsSmallScreens); + + ParsingPackage setSupportsXLargeScreens(int supportsXLargeScreens); + + ParsingPackage setTargetSandboxVersion(int targetSandboxVersion); + + ParsingPackage setTheme(int theme); + + ParsingPackage setUpgradeKeySets(ArraySet<String> upgradeKeySets); + + ParsingPackage setUse32BitAbi(boolean use32BitAbi); + + ParsingPackage setVolumeUuid(String volumeUuid); + + ParsingPackage setZygotePreloadName(String zygotePreloadName); + + ParsingPackage sortActivities(); + + ParsingPackage sortReceivers(); + + ParsingPackage sortServices(); + + ParsedPackage hideAsParsed(); + + ParsingPackage setBaseRevisionCode(int baseRevisionCode); + + ParsingPackage setPreferredOrder(int preferredOrder); + + ParsingPackage setVersionName(String versionName); + + ParsingPackage setCompileSdkVersion(int compileSdkVersion); + + ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename); + + boolean usesCompatibilityMode(); +} diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java index d0657e5eb8ec..81b4bc574197 100644 --- a/core/java/android/content/pm/AndroidHidlUpdater.java +++ b/core/java/android/content/pm/parsing/library/AndroidHidlUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER; -import android.content.pm.PackageParser.Package; +import android.content.pm.parsing.ParsedPackage; import android.os.Build; import com.android.internal.annotations.VisibleForTesting; @@ -33,20 +33,18 @@ import com.android.internal.annotations.VisibleForTesting; public class AndroidHidlUpdater extends PackageSharedLibraryUpdater { @Override - public void updatePackage(Package pkg) { - ApplicationInfo info = pkg.applicationInfo; - + public void updatePackage(ParsedPackage parsedPackage) { // This was the default <= P and is maintained for backwards compatibility. - boolean isLegacy = info.targetSdkVersion <= Build.VERSION_CODES.P; + boolean isLegacy = parsedPackage.getTargetSdkVersion() <= Build.VERSION_CODES.P; // Only system apps use these libraries - boolean isSystem = info.isSystemApp() || info.isUpdatedSystemApp(); + boolean isSystem = parsedPackage.isSystemApp() || parsedPackage.isUpdatedSystemApp(); if (isLegacy && isSystem) { - prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE); - prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER); + prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_BASE); + prefixRequiredLibrary(parsedPackage, ANDROID_HIDL_MANAGER); } else { - removeLibrary(pkg, ANDROID_HIDL_BASE); - removeLibrary(pkg, ANDROID_HIDL_MANAGER); + removeLibrary(parsedPackage, ANDROID_HIDL_BASE); + removeLibrary(parsedPackage, ANDROID_HIDL_MANAGER); } } } diff --git a/core/java/android/content/pm/AndroidTestBaseUpdater.java b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java index da1a693b13c3..25c309931554 100644 --- a/core/java/android/content/pm/AndroidTestBaseUpdater.java +++ b/core/java/android/content/pm/parsing/library/AndroidTestBaseUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -13,12 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; -import android.content.pm.PackageParser.Package; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.os.Build; import com.android.internal.annotations.VisibleForTesting; @@ -38,23 +39,22 @@ import com.android.internal.annotations.VisibleForTesting; @VisibleForTesting public class AndroidTestBaseUpdater extends PackageSharedLibraryUpdater { - private static boolean apkTargetsApiLevelLessThanOrEqualToQ(Package pkg) { - int targetSdkVersion = pkg.applicationInfo.targetSdkVersion; - return targetSdkVersion <= Build.VERSION_CODES.Q; + private static boolean apkTargetsApiLevelLessThanOrEqualToQ(AndroidPackage pkg) { + return pkg.getTargetSdkVersion() <= Build.VERSION_CODES.Q; } @Override - public void updatePackage(Package pkg) { + public void updatePackage(ParsedPackage parsedPackage) { // Packages targeted at <= Q expect the classes in the android.test.base library // to be accessible so this maintains backward compatibility by adding the // android.test.base library to those packages. - if (apkTargetsApiLevelLessThanOrEqualToQ(pkg)) { - prefixRequiredLibrary(pkg, ANDROID_TEST_BASE); + if (apkTargetsApiLevelLessThanOrEqualToQ(parsedPackage)) { + prefixRequiredLibrary(parsedPackage, ANDROID_TEST_BASE); } else { // If a package already depends on android.test.runner then add a dependency on // android.test.base because android.test.runner depends on classes from the // android.test.base library. - prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_BASE); + prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_BASE); } } } diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java index 707443b19679..613a06b636e9 100644 --- a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java +++ b/core/java/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.PackageParser.Package; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.os.Build; import com.android.internal.annotations.VisibleForTesting; @@ -31,18 +32,17 @@ import com.android.internal.annotations.VisibleForTesting; @VisibleForTesting public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater { - private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) { - int targetSdkVersion = pkg.applicationInfo.targetSdkVersion; - return targetSdkVersion < Build.VERSION_CODES.P; + private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(AndroidPackage pkg) { + return pkg.getTargetSdkVersion() < Build.VERSION_CODES.P; } @Override - public void updatePackage(Package pkg) { + public void updatePackage(ParsedPackage parsedPackage) { // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library // to be accessible so this maintains backward compatibility by adding the // org.apache.http.legacy library to those packages. - if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) { - prefixRequiredLibrary(pkg, ORG_APACHE_HTTP_LEGACY); + if (apkTargetsApiLevelLessThanOrEqualToOMR1(parsedPackage)) { + prefixRequiredLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY); } } } diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java index 4331bd4ac4d4..1220fc497b04 100644 --- a/core/java/android/content/pm/PackageBackwardCompatibility.java +++ b/core/java/android/content/pm/parsing/library/PackageBackwardCompatibility.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2019 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. @@ -14,14 +14,14 @@ * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.PackageParser.Package; +import android.content.pm.parsing.ParsedPackage; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -31,7 +31,7 @@ import java.util.List; import java.util.function.Supplier; /** - * Modifies {@link Package} in order to maintain backwards compatibility. + * Modifies {@link ParsedPackage} in order to maintain backwards compatibility. * * @hide */ @@ -60,7 +60,7 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { // will remove any references to org.apache.http.library from the package so that it does // not try and load the library when it is on the bootclasspath. boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters, - "android.content.pm.AndroidTestBaseUpdater", + "android.content.pm.parsing.library.AndroidTestBaseUpdater", RemoveUnnecessaryAndroidTestBaseLibrary::new); PackageSharedLibraryUpdater[] updaterArray = packageUpdaters @@ -123,20 +123,20 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { } /** - * Modify the shared libraries in the supplied {@link Package} to maintain backwards + * Modify the shared libraries in the supplied {@link ParsedPackage} to maintain backwards * compatibility. * - * @param pkg the {@link Package} to modify. + * @param parsedPackage the {@link ParsedPackage} to modify. */ @VisibleForTesting - public static void modifySharedLibraries(Package pkg) { - INSTANCE.updatePackage(pkg); + public static void modifySharedLibraries(ParsedPackage parsedPackage) { + INSTANCE.updatePackage(parsedPackage); } @Override - public void updatePackage(Package pkg) { + public void updatePackage(ParsedPackage parsedPackage) { for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) { - packageUpdater.updatePackage(pkg); + packageUpdater.updatePackage(parsedPackage); } } @@ -161,10 +161,10 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater { @Override - public void updatePackage(Package pkg) { + public void updatePackage(ParsedPackage parsedPackage) { // android.test.runner has a dependency on android.test.mock so if android.test.runner // is present but android.test.mock is not then add android.test.mock. - prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK); + prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK); } } @@ -177,8 +177,8 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { extends PackageSharedLibraryUpdater { @Override - public void updatePackage(Package pkg) { - removeLibrary(pkg, ORG_APACHE_HTTP_LEGACY); + public void updatePackage(ParsedPackage parsedPackage) { + removeLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY); } } @@ -192,8 +192,8 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { extends PackageSharedLibraryUpdater { @Override - public void updatePackage(Package pkg) { - removeLibrary(pkg, ANDROID_TEST_BASE); + public void updatePackage(ParsedPackage parsedPackage) { + removeLibrary(parsedPackage, ANDROID_TEST_BASE); } } } diff --git a/core/java/android/content/pm/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java index 1565d9ce77d4..8b27d140a8f4 100644 --- a/core/java/android/content/pm/PackageSharedLibraryUpdater.java +++ b/core/java/android/content/pm/parsing/library/PackageSharedLibraryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -13,18 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.parsing.ParsedPackage; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.util.ArrayList; +import java.util.List; /** - * Base for classes that update a {@link PackageParser.Package}'s shared libraries. + * Base for classes that update a {@link ParsedPackage}'s shared libraries. * * @hide */ @@ -34,14 +36,13 @@ public abstract class PackageSharedLibraryUpdater { /** * Update the package's shared libraries. * - * @param pkg the package to update. + * @param parsedPackage the package to update. */ - public abstract void updatePackage(PackageParser.Package pkg); + public abstract void updatePackage(ParsedPackage parsedPackage); - static void removeLibrary(PackageParser.Package pkg, String libraryName) { - pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, libraryName); - pkg.usesOptionalLibraries = - ArrayUtils.remove(pkg.usesOptionalLibraries, libraryName); + static void removeLibrary(ParsedPackage parsedPackage, String libraryName) { + parsedPackage.removeUsesLibrary(libraryName) + .removeUsesOptionalLibrary(libraryName); } static @NonNull @@ -53,8 +54,8 @@ public abstract class PackageSharedLibraryUpdater { return cur; } - private static boolean isLibraryPresent(ArrayList<String> usesLibraries, - ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) { + private static boolean isLibraryPresent(List<String> usesLibraries, + List<String> usesOptionalLibraries, String apacheHttpLegacy) { return ArrayUtils.contains(usesLibraries, apacheHttpLegacy) || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy); } @@ -65,37 +66,32 @@ public abstract class PackageSharedLibraryUpdater { * <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with * the {@code implicitDependency} if it is not already in the list of libraries. * - * @param pkg the {@link PackageParser.Package} to update. + * @param parsedPackage the {@link ParsedPackage} to update. * @param existingLibrary the existing library. * @param implicitDependency the implicit dependency to add */ - void prefixImplicitDependency(PackageParser.Package pkg, String existingLibrary, + void prefixImplicitDependency(ParsedPackage parsedPackage, String existingLibrary, String implicitDependency) { - ArrayList<String> usesLibraries = pkg.usesLibraries; - ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries; + List<String> usesLibraries = parsedPackage.getUsesLibraries(); + List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries(); if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) { if (ArrayUtils.contains(usesLibraries, existingLibrary)) { - prefix(usesLibraries, implicitDependency); + parsedPackage.addUsesLibrary(0, implicitDependency); } else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) { - prefix(usesOptionalLibraries, implicitDependency); + parsedPackage.addUsesOptionalLibrary(0, implicitDependency); } - - pkg.usesLibraries = usesLibraries; - pkg.usesOptionalLibraries = usesOptionalLibraries; } } - void prefixRequiredLibrary(PackageParser.Package pkg, String libraryName) { - ArrayList<String> usesLibraries = pkg.usesLibraries; - ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries; + void prefixRequiredLibrary(ParsedPackage parsedPackage, String libraryName) { + List<String> usesLibraries = parsedPackage.getUsesLibraries(); + List<String> usesOptionalLibraries = parsedPackage.getUsesOptionalLibraries(); boolean alreadyPresent = isLibraryPresent( usesLibraries, usesOptionalLibraries, libraryName); if (!alreadyPresent) { - usesLibraries = prefix(usesLibraries, libraryName); - - pkg.usesLibraries = usesLibraries; + parsedPackage.addUsesLibrary(0, libraryName); } } } diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java index a607a9ff682b..7b691c06718e 100644 --- a/core/java/android/content/pm/SharedLibraryNames.java +++ b/core/java/android/content/pm/parsing/library/SharedLibraryNames.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; /** * A set of shared library names diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 2420a6109155..567e26b4c2f6 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -1376,7 +1376,6 @@ public final class AssetManager implements AutoCloseable { /** * @hide */ - @TestApi @GuardedBy("this") public @Nullable Map<String, String> getOverlayableMap(String packageName) { synchronized (this) { @@ -1385,6 +1384,18 @@ public final class AssetManager implements AutoCloseable { } } + /** + * @hide + */ + @TestApi + @GuardedBy("this") + public @Nullable String getOverlayablesToString(String packageName) { + synchronized (this) { + ensureValidLocked(); + return nativeGetOverlayablesToString(mObject, packageName); + } + } + @GuardedBy("this") private void incRefsLocked(long id) { if (DEBUG_REFS) { @@ -1504,6 +1515,8 @@ public final class AssetManager implements AutoCloseable { private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); private static native @Nullable Map nativeGetOverlayableMap(long ptr, @NonNull String packageName); + private static native @Nullable String nativeGetOverlayablesToString(long ptr, + @NonNull String packageName); // Global debug native methods. /** diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index 9af9edae9a3f..45a9cf5ab869 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -295,6 +295,10 @@ public class Handler { /** {@hide} */ @NonNull public String getTraceName(@NonNull Message message) { + if (message.callback instanceof TraceNameSupplier) { + return ((TraceNameSupplier) message.callback).getTraceName(); + } + final StringBuilder sb = new StringBuilder(); sb.append(getClass().getName()).append(": "); if (message.callback != null) { diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java b/core/java/android/os/TraceNameSupplier.java index 57afcb0e1a0d..e4b3a4edce38 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java +++ b/core/java/android/os/TraceNameSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 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. @@ -12,13 +12,20 @@ * 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.os; -package com.android.frameworks.coretests; - -import android.app.Activity; +import android.annotation.NonNull; -public class FirstChildTestActivity extends Activity { +/** + * Supplier for custom trace messages. + * + * @hide + */ +public interface TraceNameSupplier { + /** + * Gets the name used for trace messages. + */ + @NonNull String getTraceName(); } diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java index a5b71f64668d..59fb3d9fcdad 100644 --- a/core/java/android/os/UserManagerInternal.java +++ b/core/java/android/os/UserManagerInternal.java @@ -86,12 +86,22 @@ public abstract class UserManagerInternal { public abstract void setDeviceManaged(boolean isManaged); /** + * Returns whether the device is managed by device owner. + */ + public abstract boolean isDeviceManaged(); + + /** * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to update * whether the user is managed by profile owner. */ public abstract void setUserManaged(int userId, boolean isManaged); /** + * whether a profile owner manages this user. + */ + public abstract boolean isUserManaged(int userId); + + /** * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to omit * restriction check, because DevicePolicyManager must always be able to set user icon * regardless of any restriction. diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 5b9205d16898..351462f8d68e 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -153,6 +153,11 @@ public class StorageManager { public static final String PROP_ISOLATED_STORAGE = "persist.sys.isolated_storage"; /** {@hide} */ public static final String PROP_ISOLATED_STORAGE_SNAPSHOT = "sys.isolated_storage_snapshot"; + /** {@hide} */ + public static final String PROP_FUSE = "persist.sys.fuse"; + /** {@hide} */ + public static final String PROP_FUSE_SNAPSHOT = "sys.fuse_snapshot"; + /** {@hide} */ public static final String UUID_PRIVATE_INTERNAL = null; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 61d8eb13bcf2..3c26df3c560b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7631,6 +7631,19 @@ public final class Settings { "face_unlock_always_require_confirmation"; /** + * Whether or not a user should re enroll their face. + * + * Face unlock re enroll. + * 0 = No re enrollment. + * 1 = Re enrollment is suggested. + * 2 = Re enrollment is required after a set time period. + * 3 = Re enrollment is required immediately. + * + * @hide + */ + public static final String FACE_UNLOCK_RE_ENROLL = "face_unlock_re_enroll"; + + /** * Whether or not debugging is enabled. * @hide */ diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java index 5143f1820c2d..2470d197c3fc 100644 --- a/core/java/android/service/textclassifier/TextClassifierService.java +++ b/core/java/android/service/textclassifier/TextClassifierService.java @@ -58,8 +58,8 @@ import java.util.concurrent.Executors; * Abstract base class for the TextClassifier service. * * <p>A TextClassifier service provides text classification related features for the system. - * The system's default TextClassifierService is configured in - * {@code config_defaultTextClassifierService}. If this config has no value, a + * The system's default TextClassifierService provider is configured in + * {@code config_defaultTextClassifierPackage}. If this config has no value, a * {@link android.view.textclassifier.TextClassifierImpl} is loaded in the calling app's process. * * <p>See: {@link TextClassifier}. diff --git a/core/java/android/view/CompositionSamplingListener.java b/core/java/android/view/CompositionSamplingListener.java index 368445cde72c..677a559cd3b0 100644 --- a/core/java/android/view/CompositionSamplingListener.java +++ b/core/java/android/view/CompositionSamplingListener.java @@ -28,7 +28,7 @@ import java.util.concurrent.Executor; */ public abstract class CompositionSamplingListener { - private final long mNativeListener; + private long mNativeListener; private final Executor mExecutor; public CompositionSamplingListener(Executor executor) { @@ -36,13 +36,19 @@ public abstract class CompositionSamplingListener { mNativeListener = nativeCreate(this); } + public void destroy() { + if (mNativeListener == 0) { + return; + } + unregister(this); + nativeDestroy(mNativeListener); + mNativeListener = 0; + } + @Override protected void finalize() throws Throwable { try { - if (mNativeListener != 0) { - unregister(this); - nativeDestroy(mNativeListener); - } + destroy(); } finally { super.finalize(); } @@ -58,6 +64,9 @@ public abstract class CompositionSamplingListener { */ public static void register(CompositionSamplingListener listener, int displayId, SurfaceControl stopLayer, Rect samplingArea) { + if (listener.mNativeListener == 0) { + return; + } Preconditions.checkArgument(displayId == Display.DEFAULT_DISPLAY, "default display only for now"); long nativeStopLayerObject = stopLayer != null ? stopLayer.mNativeObject : 0; @@ -69,6 +78,9 @@ public abstract class CompositionSamplingListener { * Unregisters a sampling listener. */ public static void unregister(CompositionSamplingListener listener) { + if (listener.mNativeListener == 0) { + return; + } nativeUnregister(listener.mNativeListener); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index d5559aaa7146..6639fbf9551e 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -187,8 +187,7 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject, InputWindowHandle handle); - private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken, - IBinder toToken); + private static native boolean nativeGetProtectedContentSupport(); private static native void nativeSetMetadata(long transactionObj, long nativeObject, int key, Parcel data); @@ -2239,22 +2238,6 @@ public final class SurfaceControl implements Parcelable { } /** - * Transfers touch focus from one window to another. It is possible for multiple windows to - * have touch focus if they support split touch dispatch - * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this - * method only transfers touch focus of the specified window without affecting - * other windows that may also have touch focus at the same time. - * @param fromToken The token of a window that currently has touch focus. - * @param toToken The token of the window that should receive touch focus in - * place of the first. - * @hide - */ - public Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) { - nativeTransferTouchFocus(mNativeObject, fromToken, toToken); - return this; - } - - /** * Waits until any changes to input windows have been sent from SurfaceFlinger to * InputFlinger before returning. * diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index db3ef20d5859..06ff568202d5 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1128,11 +1128,12 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return; } - if (frameNumber > 0) { - final ViewRootImpl viewRoot = getViewRootImpl(); - - mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface, - frameNumber); + final ViewRootImpl viewRoot = getViewRootImpl(); + if (frameNumber > 0 && viewRoot != null) { + if (viewRoot.mSurface.isValid()) { + mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface, + frameNumber); + } } mRtTransaction.hide(mSurfaceControl); diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java index 80de6fc65f90..562cc4ffeeaa 100644 --- a/core/java/android/widget/SimpleMonthView.java +++ b/core/java/android/widget/SimpleMonthView.java @@ -1103,6 +1103,7 @@ class SimpleMonthView extends View { } node.setEnabled(isDayEnabled); + node.setClickable(true); if (virtualViewId == mActivatedDay) { // TODO: This should use activated once that's supported. diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java index 1ce071bd005a..8283eb749376 100644 --- a/core/java/com/android/internal/compat/ChangeReporter.java +++ b/core/java/com/android/internal/compat/ChangeReporter.java @@ -16,14 +16,88 @@ package com.android.internal.compat; +import android.util.Log; +import android.util.Slog; import android.util.StatsLog; +import com.android.internal.annotations.GuardedBy; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + /** * A helper class to report changes to stats log. * * @hide */ public final class ChangeReporter { + private static final String TAG = "CompatibilityChangeReporter"; + private int mSource; + + private final class ChangeReport { + int mUid; + long mChangeId; + int mState; + + ChangeReport(int uid, long changeId, int state) { + mUid = uid; + mChangeId = changeId; + mState = state; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ChangeReport that = (ChangeReport) o; + return mUid == that.mUid + && mChangeId == that.mChangeId + && mState == that.mState; + } + + @Override + public int hashCode() { + return Objects.hash(mUid, mChangeId, mState); + } + } + + @GuardedBy("mReportedChanges") + private Set<ChangeReport> mReportedChanges = new HashSet<>(); + + public ChangeReporter(int source) { + mSource = source; + } + + /** + * Report the change to stats log. + * + * @param uid affected by the change + * @param changeId the reported change id + * @param state of the reported change - enabled/disabled/only logged + */ + public void reportChange(int uid, long changeId, int state) { + ChangeReport report = new ChangeReport(uid, changeId, state); + synchronized (mReportedChanges) { + if (!mReportedChanges.contains(report)) { + debugLog(uid, changeId, state); + StatsLog.write(StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, changeId, + state, mSource); + mReportedChanges.add(report); + } + } + } + + private void debugLog(int uid, long changeId, int state) { + String message = String.format("Compat change id reported: %d; UID %d; state: %s", changeId, + uid, stateToString(state)); + if (mSource == StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER) { + Slog.d(TAG, message); + } else { + Log.d(TAG, message); + } + + } /** * Transforms StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE enum to a string. @@ -43,31 +117,4 @@ public final class ChangeReporter { return "UNKNOWN"; } } - - /** - * Constructs and returns a string to be logged to logcat when a change is reported. - * - * @param uid affected by the change - * @param changeId the reported change id - * @param state of the reported change - enabled/disabled/only logged - * @return string to log - */ - public static String createLogString(int uid, long changeId, int state) { - return String.format("Compat change id reported: %d; UID %d; state: %s", changeId, uid, - stateToString(state)); - } - - /** - * Report the change to stats log. - * - * @param uid affected by the change - * @param changeId the reported change id - * @param state of the reported change - enabled/disabled/only logged - * @param source of the logging - app process or system server - */ - public void reportChange(int uid, long changeId, int state, int source) { - //TODO(b/138374585): Implement rate limiting for stats log. - StatsLog.write(StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, changeId, - state, source); - } } diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index fee8345d1660..f04a6715e55f 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -28,12 +28,11 @@ import static android.system.OsConstants.S_IXOTH; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Package; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.SELinux; -import android.os.SystemProperties; import android.system.ErrnoException; import android.system.Os; import android.util.Slog; @@ -88,11 +87,12 @@ public class NativeLibraryHelper { } } - public static Handle create(Package pkg) throws IOException { - return create(pkg.getAllCodePaths(), - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0, - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0, - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0); + public static Handle create(AndroidPackage pkg) throws IOException { + return create( + pkg.makeListAllCodePaths(), + (pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0, + (pkg.getFlags() & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0, + (pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0); } public static Handle create(PackageLite lite) throws IOException { diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java index d6862f0188ce..98d679eb776b 100644 --- a/core/java/com/android/internal/infra/ServiceConnector.java +++ b/core/java/com/android/internal/infra/ServiceConnector.java @@ -32,6 +32,7 @@ import android.text.TextUtils; import android.util.DebugUtils; import android.util.Log; +import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledLambda; import java.io.PrintWriter; @@ -351,7 +352,7 @@ public interface ServiceConnector<I extends IInterface> { @Override public <R> CompletionAwareJob<I, R> postForResult(@NonNull Job<I, R> job) { CompletionAwareJob<I, R> task = new CompletionAwareJob<>(); - task.mDelegate = job; + task.mDelegate = Preconditions.checkNotNull(job); enqueue(task); return task; } @@ -359,7 +360,7 @@ public interface ServiceConnector<I extends IInterface> { @Override public <R> AndroidFuture<R> postAsync(@NonNull Job<I, CompletableFuture<R>> job) { CompletionAwareJob<I, R> task = new CompletionAwareJob<>(); - task.mDelegate = (Job) job; + task.mDelegate = Preconditions.checkNotNull((Job) job); task.mAsync = true; enqueue(task); return task; diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 1de2e7272f4d..d6caa0930243 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -192,6 +192,15 @@ public class RuntimeInit { } } + /** + * Common initialization that (unlike {@link #commonInit()} should happen prior to + * the Zygote fork. + */ + public static void preForkInit() { + if (DEBUG) Slog.d(TAG, "Entered preForkInit."); + RuntimeInit.enableDdms(); + } + @UnsupportedAppUsage protected static final void commonInit() { if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); @@ -324,7 +333,7 @@ public class RuntimeInit { @UnsupportedAppUsage public static final void main(String[] argv) { - enableDdms(); + preForkInit(); if (argv.length == 2 && argv[1].equals("application")) { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application"); redirectLogStreams(); @@ -418,7 +427,7 @@ public class RuntimeInit { /** * Enable DDMS. */ - static final void enableDdms() { + private static void enableDdms() { // Register handlers for DDM messages. android.ddm.DdmRegister.registerHandlers(); } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 3be1a1aefe57..158700b2a449 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -847,7 +847,7 @@ public class ZygoteInit { TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag, Trace.TRACE_TAG_DALVIK); bootTimingsTraceLog.traceBegin("ZygoteInit"); - RuntimeInit.enableDdms(); + RuntimeInit.preForkInit(); boolean startSystemServer = false; String zygoteSocketName = "zygote"; diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 821022f1f917..bc8019796d22 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -600,6 +600,14 @@ public class ArrayUtils { return cur; } + public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, int index, T val) { + if (cur == null) { + cur = new ArrayList<>(); + } + cur.add(index, val); + return cur; + } + public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) { if (cur == null) { return null; diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java index 1fdb1f30125f..e12c031f0036 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java @@ -16,6 +16,7 @@ package com.android.internal.util.function.pooled; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Message; import android.text.TextUtils; @@ -527,6 +528,36 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, return r; } + // TODO: add unit test + @NonNull + private static String getFriendlyName(@NonNull Object function) { + // Full function has one of the following formats: + // package-$$Lambda$class$randomId + // package-$$Lambda$randomId + // + // We just want just package.class$Lambda (or package$Lambda) respectively + + final String fullFunction = function.toString(); + + final int endPkgIdx = fullFunction.indexOf("-$$"); + if (endPkgIdx == -1) return fullFunction; + + // firstDollarIdx could be either beginning of class or beginning of the random id + final int firstDollarIdx = fullFunction.indexOf('$', endPkgIdx + 3); + if (firstDollarIdx == -1) return fullFunction; + + final int endClassIdx = fullFunction.indexOf('$', firstDollarIdx + 1); + if (endClassIdx == -1) { + // Just package + return fullFunction.substring(0, endPkgIdx - 1) + "$Lambda"; + } + + // Package + class + return fullFunction.substring(0, endPkgIdx) + + fullFunction.substring(firstDollarIdx + 1, endClassIdx) + + "$Lambda"; + } + private static void setIfInBounds(Object[] array, int i, Object a) { if (i < ArrayUtils.size(array)) array[i] = a; } @@ -566,6 +597,11 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object, return this; } + @Override + public String getTraceName() { + return getFriendlyName(mFunc); + } + private boolean isRecycled() { return (mFlags & FLAG_RECYCLED) != 0; } diff --git a/core/java/com/android/internal/util/function/pooled/PooledRunnable.java b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java index 89ca82e2f3ce..f0bc2cadb1c5 100644 --- a/core/java/com/android/internal/util/function/pooled/PooledRunnable.java +++ b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java @@ -16,6 +16,8 @@ package com.android.internal.util.function.pooled; +import android.os.TraceNameSupplier; + import com.android.internal.util.FunctionalUtils.ThrowingRunnable; /** @@ -24,7 +26,8 @@ import com.android.internal.util.FunctionalUtils.ThrowingRunnable; * @see PooledLambda * @hide */ -public interface PooledRunnable extends PooledLambda, Runnable, ThrowingRunnable { +public interface PooledRunnable + extends PooledLambda, Runnable, ThrowingRunnable, TraceNameSupplier { /** @inheritDoc */ PooledRunnable recycleOnUse(); } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 5a0f16e589ce..e3b8560ae749 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -54,6 +54,8 @@ cc_library_shared { whole_static_libs: ["libandroid_graphics"], + export_static_lib_headers: ["libandroid_graphics"], + shared_libs: [ "libbase", "libcutils", @@ -337,7 +339,9 @@ cc_library_static { cppflags: ["-Wno-conversion-null"], srcs: [ + "android/graphics/apex/android_bitmap.cpp", "android/graphics/apex/android_region.cpp", + "android/graphics/apex/android_paint.cpp", "android_graphics_Canvas.cpp", "android_graphics_ColorSpace.cpp", @@ -390,7 +394,6 @@ cc_library_static { ], export_include_dirs: [ - ".", "android/graphics/apex/include", ], diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 18a1b43d3f5f..89c12f88594d 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -265,6 +265,20 @@ void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) { info->format = ANDROID_BITMAP_FORMAT_NONE; break; } + switch (imageInfo.alphaType()) { + case kUnknown_SkAlphaType: + LOG_ALWAYS_FATAL("Bitmap has no alpha type"); + break; + case kOpaque_SkAlphaType: + info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE; + break; + case kPremul_SkAlphaType: + info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_PREMUL; + break; + case kUnpremul_SkAlphaType: + info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL; + break; + } } void* lockPixels(JNIEnv* env, jobject bitmap) { diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h index 06e31a1518ca..59adbb207a0c 100644 --- a/core/jni/android/graphics/Bitmap.h +++ b/core/jni/android/graphics/Bitmap.h @@ -39,8 +39,6 @@ jobject createBitmap(JNIEnv* env, Bitmap* bitmap, jobject ninePatchInsets = nullptr, int density = -1); -void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap); - Bitmap& toBitmap(JNIEnv* env, jobject bitmap); Bitmap& toBitmap(jlong bitmapHandle); diff --git a/core/jni/android/graphics/apex/TypeCast.h b/core/jni/android/graphics/apex/TypeCast.h new file mode 100644 index 000000000000..96721d007951 --- /dev/null +++ b/core/jni/android/graphics/apex/TypeCast.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef ANDROID_GRAPHICS_TYPECAST_H +#define ANDROID_GRAPHICS_TYPECAST_H + +struct ABitmap; +struct ACanvas; +struct APaint; + +namespace android { + + class Bitmap; + class Canvas; + class Paint; + + class TypeCast { + public: + static inline Bitmap& toBitmapRef(const ABitmap* bitmap) { + return const_cast<Bitmap&>(reinterpret_cast<const Bitmap&>(*bitmap)); + } + + static inline Bitmap* toBitmap(ABitmap* bitmap) { + return reinterpret_cast<Bitmap*>(bitmap); + } + + static inline ABitmap* toABitmap(Bitmap* bitmap) { + return reinterpret_cast<ABitmap*>(bitmap); + } + + static inline Canvas* toCanvas(ACanvas* canvas) { + return reinterpret_cast<Canvas*>(canvas); + } + + static inline ACanvas* toACanvas(Canvas* canvas) { + return reinterpret_cast<ACanvas *>(canvas); + } + + static inline const Paint& toPaintRef(const APaint* paint) { + return reinterpret_cast<const Paint&>(*paint); + } + + static inline const Paint* toPaint(const APaint* paint) { + return reinterpret_cast<const Paint*>(paint); + } + + static inline Paint* toPaint(APaint* paint) { + return reinterpret_cast<Paint*>(paint); + } + + static inline APaint* toAPaint(Paint* paint) { + return reinterpret_cast<APaint*>(paint); + } + }; +}; // namespace android + +#endif // ANDROID_GRAPHICS_TYPECAST_H diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp new file mode 100644 index 000000000000..96cc5db8a5a4 --- /dev/null +++ b/core/jni/android/graphics/apex/android_bitmap.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 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. + */ + +#include "android/graphics/bitmap.h" +#include "Bitmap.h" +#include "TypeCast.h" + +#include <hwui/Bitmap.h> + +using namespace android; + +ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj) { + Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapObj); + bitmap.ref(); + return TypeCast::toABitmap(&bitmap); +} + +void ABitmap_acquireRef(ABitmap* bitmap) { + SkSafeRef(TypeCast::toBitmap(bitmap)); +} + +void ABitmap_releaseRef(ABitmap* bitmap) { + SkSafeUnref(TypeCast::toBitmap(bitmap)); +} + +static AndroidBitmapFormat getFormat(Bitmap* bitmap) { + switch (bitmap->colorType()) { + case kN32_SkColorType: + return ANDROID_BITMAP_FORMAT_RGBA_8888; + case kRGB_565_SkColorType: + return ANDROID_BITMAP_FORMAT_RGB_565; + case kARGB_4444_SkColorType: + return ANDROID_BITMAP_FORMAT_RGBA_4444; + case kAlpha_8_SkColorType: + return ANDROID_BITMAP_FORMAT_A_8; + case kRGBA_F16_SkColorType: + return ANDROID_BITMAP_FORMAT_RGBA_F16; + default: + return ANDROID_BITMAP_FORMAT_NONE; + } +} + +static SkColorType getColorType(AndroidBitmapFormat format) { + switch (format) { + case ANDROID_BITMAP_FORMAT_RGBA_8888: + return kN32_SkColorType; + case ANDROID_BITMAP_FORMAT_RGB_565: + return kRGB_565_SkColorType; + case ANDROID_BITMAP_FORMAT_RGBA_4444: + return kARGB_4444_SkColorType; + case ANDROID_BITMAP_FORMAT_A_8: + return kAlpha_8_SkColorType; + case ANDROID_BITMAP_FORMAT_RGBA_F16: + return kRGBA_F16_SkColorType; + default: + return kUnknown_SkColorType; + } +} + +ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) { + SkColorType dstColorType = getColorType(dstFormat); + if (srcBitmapHandle && dstColorType != kUnknown_SkColorType) { + SkBitmap srcBitmap; + TypeCast::toBitmap(srcBitmapHandle)->getSkBitmap(&srcBitmap); + + sk_sp<Bitmap> dstBitmap = + Bitmap::allocateHeapBitmap(srcBitmap.info().makeColorType(dstColorType)); + if (dstBitmap && srcBitmap.readPixels(dstBitmap->info(), dstBitmap->pixels(), + dstBitmap->rowBytes(), 0, 0)) { + return TypeCast::toABitmap(dstBitmap.release()); + } + } + return nullptr; +} + +AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) { + Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); + + AndroidBitmapInfo info; + info.width = bitmap->width(); + info.height = bitmap->height(); + info.stride = bitmap->rowBytes(); + info.format = getFormat(bitmap); + return info; +} + +void* ABitmap_getPixels(ABitmap* bitmapHandle) { + Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); + if (bitmap->isHardware()) { + return nullptr; + } + return bitmap->pixels(); +} diff --git a/core/jni/android/graphics/apex/android_canvas.cpp b/core/jni/android/graphics/apex/android_canvas.cpp index 7a4495f4f259..527a745426e3 100644 --- a/core/jni/android/graphics/apex/android_canvas.cpp +++ b/core/jni/android/graphics/apex/android_canvas.cpp @@ -16,6 +16,7 @@ #include "android/graphics/canvas.h" +#include "TypeCast.h" #include "GraphicsJNI.h" #include <hwui/Canvas.h> @@ -25,14 +26,6 @@ using namespace android; -static inline Canvas* toCanvas(ACanvas* aCanvas) { - return reinterpret_cast<Canvas*>(aCanvas); -} - -static inline ACanvas* toACanvas(Canvas* canvas) { - return reinterpret_cast<ACanvas*>(canvas); -} - bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat) { ANativeWindow_Buffer buffer { 0, 0, 0, bufferFormat, nullptr, {0} }; const SkColorType colorType = uirenderer::ANativeWindowToImageInfo(buffer, nullptr).colorType(); @@ -40,11 +33,11 @@ bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat) { } ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvasObj) { - return toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj)); + return TypeCast::toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj)); } -void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer, - int32_t /*android_dataspace_t*/ dataspace) { +static SkBitmap convert(const ANativeWindow_Buffer* buffer, + int32_t /*android_dataspace_t*/ dataspace) { SkBitmap bitmap; if (buffer != nullptr && buffer->width > 0 && buffer->height > 0) { sk_sp<SkColorSpace> cs(uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace)); @@ -53,18 +46,44 @@ void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer, bitmap.setInfo(imageInfo, rowBytes); bitmap.setPixels(buffer->bits); } + return bitmap; +} - toCanvas(canvas)->setBitmap(bitmap); +ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer, + int32_t /*android_dataspace_t*/ dataspace) { + return TypeCast::toACanvas(Canvas::create_canvas(convert(buffer, dataspace))); } -void ACanvas_clipRect(ACanvas* canvas, const ARect& clipRect, bool /*doAA*/) { +void ACanvas_destroyCanvas(ACanvas* canvas) { + delete TypeCast::toCanvas(canvas); +} + +void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer, + int32_t /*android_dataspace_t*/ dataspace) { + + + TypeCast::toCanvas(canvas)->setBitmap(convert(buffer, dataspace)); +} + +void ACanvas_clipRect(ACanvas* canvas, const ARect* clipRect, bool /*doAA*/) { //TODO update Canvas to take antialias param - toCanvas(canvas)->clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkClipOp::kIntersect); + TypeCast::toCanvas(canvas)->clipRect(clipRect->left, clipRect->top, clipRect->right, + clipRect->bottom, SkClipOp::kIntersect); } -void ACanvas_clipOutRect(ACanvas* canvas, const ARect& clipRect, bool /*doAA*/) { +void ACanvas_clipOutRect(ACanvas* canvas, const ARect* clipRect, bool /*doAA*/) { //TODO update Canvas to take antialias param - toCanvas(canvas)->clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkClipOp::kDifference); + TypeCast::toCanvas(canvas)->clipRect(clipRect->left, clipRect->top, clipRect->right, + clipRect->bottom, SkClipOp::kDifference); +} + +void ACanvas_drawRect(ACanvas* canvas, const ARect* rect, const APaint* paint) { + TypeCast::toCanvas(canvas)->drawRect(rect->left, rect->top, rect->right, rect->bottom, + TypeCast::toPaintRef(paint)); +} + +void ACanvas_drawBitmap(ACanvas* canvas, const ABitmap* bitmap, float left, float top, + const APaint* paint) { + TypeCast::toCanvas(canvas)->drawBitmap(TypeCast::toBitmapRef(bitmap), left, top, + TypeCast::toPaint(paint)); } diff --git a/core/jni/android/graphics/apex/android_paint.cpp b/core/jni/android/graphics/apex/android_paint.cpp new file mode 100644 index 000000000000..70bd085343ce --- /dev/null +++ b/core/jni/android/graphics/apex/android_paint.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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. + */ + +#include "android/graphics/paint.h" + +#include "TypeCast.h" + +#include <hwui/Paint.h> + +using namespace android; + + +APaint* APaint_createPaint() { + return TypeCast::toAPaint(new Paint()); +} + +void APaint_destroyPaint(APaint* paint) { + delete TypeCast::toPaint(paint); +} + +static SkBlendMode convertBlendMode(ABlendMode blendMode) { + switch (blendMode) { + case ABLEND_MODE_CLEAR: + return SkBlendMode::kClear; + case ABLEND_MODE_SRC_OVER: + return SkBlendMode::kSrcOver; + case ABLEND_MODE_SRC: + return SkBlendMode::kSrc; + } +} + +void APaint_setBlendMode(APaint* paint, ABlendMode blendMode) { + TypeCast::toPaint(paint)->setBlendMode(convertBlendMode(blendMode)); +} diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h new file mode 100644 index 000000000000..bfa4c8df407f --- /dev/null +++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 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. + */ +#ifndef ANDROID_GRAPHICS_BITMAP_H +#define ANDROID_GRAPHICS_BITMAP_H + +#include <android/bitmap.h> +#include <jni.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * Opaque handle for a native graphics bitmap. + */ +typedef struct ABitmap ABitmap; + +ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj); + +ABitmap* ABitmap_copy(ABitmap* srcBitmap, AndroidBitmapFormat dstFormat); + +void ABitmap_acquireRef(ABitmap* bitmap); +void ABitmap_releaseRef(ABitmap* bitmap); + +AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap); + +void* ABitmap_getPixels(ABitmap* bitmap); + +__END_DECLS + +#ifdef __cplusplus +namespace android { +namespace graphics { + class Bitmap { + public: + Bitmap() : mBitmap(nullptr) {} + Bitmap(JNIEnv* env, jobject bitmapObj) : + mBitmap(ABitmap_acquireBitmapFromJava(env, bitmapObj)) {} + Bitmap(const Bitmap& src) : mBitmap(src.mBitmap) { ABitmap_acquireRef(src.mBitmap); } + ~Bitmap() { ABitmap_releaseRef(mBitmap); } + + // copy operator + Bitmap& operator=(const Bitmap& other) { + if (&other != this) { + ABitmap_releaseRef(mBitmap); + mBitmap = other.mBitmap; + ABitmap_acquireRef(mBitmap); + } + return *this; + } + + // move operator + Bitmap& operator=(Bitmap&& other) { + if (&other != this) { + ABitmap_releaseRef(mBitmap); + mBitmap = other.mBitmap; + other.mBitmap = nullptr; + } + return *this; + } + + Bitmap copy(AndroidBitmapFormat dstFormat) const { + return Bitmap(ABitmap_copy(mBitmap, dstFormat)); + } + + bool isValid() const { return mBitmap != nullptr; } + bool isEmpty() const { + AndroidBitmapInfo info = getInfo(); + return info.width <= 0 || info.height <= 0; + } + void reset() { + ABitmap_releaseRef(mBitmap); + mBitmap = nullptr; + } + + const ABitmap* get() const { return mBitmap; } + + AndroidBitmapInfo getInfo() const { return ABitmap_getInfo(mBitmap); } + void* getPixels() const { return ABitmap_getPixels(mBitmap); } + private: + // takes ownership of the provided ABitmap + Bitmap(ABitmap* bitmap) : mBitmap(bitmap) {} + + ABitmap* mBitmap; + }; +}; // namespace graphics +}; // namespace android +#endif // __cplusplus + +#endif // ANDROID_GRAPHICS_BITMAP_H
\ No newline at end of file diff --git a/core/jni/android/graphics/apex/include/android/graphics/canvas.h b/core/jni/android/graphics/apex/include/android/graphics/canvas.h index c35a7d69b836..190aba4565f8 100644 --- a/core/jni/android/graphics/apex/include/android/graphics/canvas.h +++ b/core/jni/android/graphics/apex/include/android/graphics/canvas.h @@ -16,6 +16,8 @@ #ifndef ANDROID_GRAPHICS_CANVAS_H #define ANDROID_GRAPHICS_CANVAS_H +#include <android/graphics/bitmap.h> +#include <android/graphics/paint.h> #include <android/native_window.h> #include <android/rect.h> #include <jni.h> @@ -23,8 +25,8 @@ __BEGIN_DECLS /** -* Opaque handle for a native graphics canvas. -*/ + * Opaque handle for a native graphics canvas. + */ typedef struct ACanvas ACanvas; // One of AHardwareBuffer_Format. @@ -33,34 +35,104 @@ bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat); /** * Returns a native handle to a Java android.graphics.Canvas * - * @param env - * @param canvas * @return ACanvas* that is only valid for the life of the jobject. */ ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvas); /** + * Creates a canvas that wraps the buffer + * + * @param buffer required + */ +ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer, + int32_t /*android_dataspace_t*/ dataspace); + +void ACanvas_destroyCanvas(ACanvas* canvas); + +/** * Updates the canvas to render into the pixels in the provided buffer * - * @param canvas * @param buffer The buffer that will provide the backing store for this canvas. The buffer must * remain valid until the this method is called again with either another active * buffer or nullptr. If nullptr is given the canvas will release the previous buffer * and set an empty backing store. - * @param dataspace */ void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer, int32_t /*android_dataspace_t*/ dataspace); /** * Clips operations on the canvas to the intersection of the current clip and the provided clipRect. + * + * @param clipRect required */ -void ACanvas_clipRect(ACanvas* canvas, const ARect& clipRect, bool doAntiAlias = false); +void ACanvas_clipRect(ACanvas* canvas, const ARect* clipRect, bool doAntiAlias = false); /** * Clips operations on the canvas to the difference of the current clip and the provided clipRect. + * + * @param clipRect required + */ +void ACanvas_clipOutRect(ACanvas* canvas, const ARect* clipRect, bool doAntiAlias = false); + +/** + * + * @param rect required + * @param paint required + */ +void ACanvas_drawRect(ACanvas* canvas, const ARect* rect, const APaint* paint); + +/** + * + * @param bitmap required + * @param left + * @param top + * @param paint */ -void ACanvas_clipOutRect(ACanvas* canvas, const ARect& clipRect, bool doAntiAlias = false); +void ACanvas_drawBitmap(ACanvas* canvas, const ABitmap* bitmap, float left, float top, + const APaint* paint); __END_DECLS + +#ifdef __cplusplus +namespace android { +namespace graphics { + class Canvas { + public: + Canvas(JNIEnv* env, jobject canvasObj) : + mCanvas(ACanvas_getNativeHandleFromJava(env, canvasObj)), + mOwnedPtr(false) {} + Canvas(const ANativeWindow_Buffer& buffer, int32_t /*android_dataspace_t*/ dataspace) : + mCanvas(ACanvas_createCanvas(&buffer, dataspace)), + mOwnedPtr(true) {} + ~Canvas() { + if (mOwnedPtr) { + ACanvas_destroyCanvas(mCanvas); + } + } + + void setBuffer(const ANativeWindow_Buffer* buffer, + int32_t /*android_dataspace_t*/ dataspace) { + ACanvas_setBuffer(mCanvas, buffer, dataspace); + } + + void clipRect(const ARect& clipRect, bool doAntiAlias = false) { + ACanvas_clipRect(mCanvas, &clipRect, doAntiAlias); + } + + void drawRect(const ARect& rect, const Paint& paint) { + ACanvas_drawRect(mCanvas, &rect, &paint.get()); + } + void drawBitmap(const Bitmap& bitmap, float left, float top, const Paint* paint) { + const APaint* aPaint = (paint) ? &paint->get() : nullptr; + ACanvas_drawBitmap(mCanvas, bitmap.get(), left, top, aPaint); + } + + private: + ACanvas* mCanvas; + const bool mOwnedPtr; + }; +}; // namespace graphics +}; // namespace android +#endif // __cplusplus + #endif // ANDROID_GRAPHICS_CANVAS_H
\ No newline at end of file diff --git a/core/jni/android/graphics/apex/include/android/graphics/paint.h b/core/jni/android/graphics/apex/include/android/graphics/paint.h new file mode 100644 index 000000000000..5895e006bf93 --- /dev/null +++ b/core/jni/android/graphics/apex/include/android/graphics/paint.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 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. + */ +#ifndef ANDROID_GRAPHICS_PAINT_H +#define ANDROID_GRAPHICS_PAINT_H + +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * Opaque handle for a native graphics canvas. + */ +typedef struct APaint APaint; + +/** Bitmap pixel format. */ +enum ABlendMode { + /** replaces destination with zero: fully transparent */ + ABLEND_MODE_CLEAR = 0, + /** source over destination */ + ABLEND_MODE_SRC_OVER = 1, + /** replaces destination **/ + ABLEND_MODE_SRC = 2, +}; + +APaint* APaint_createPaint(); + +void APaint_destroyPaint(APaint* paint); + +void APaint_setBlendMode(APaint* paint, ABlendMode blendMode); + +__END_DECLS + +#ifdef __cplusplus +namespace android { +namespace graphics { + class Paint { + public: + Paint() : mPaint(APaint_createPaint()) {} + ~Paint() { APaint_destroyPaint(mPaint); } + + void setBlendMode(ABlendMode blendMode) { APaint_setBlendMode(mPaint, blendMode); } + + const APaint& get() const { return *mPaint; } + + private: + APaint* mPaint; + }; +}; // namespace graphics +}; // namespace android +#endif // __cplusplus + + +#endif // ANDROID_GRAPHICS_PAINT_H
\ No newline at end of file diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index 58c5871aba28..82601baee914 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -24,15 +24,13 @@ #include <assert.h> #include <dlfcn.h> +#include <android/graphics/bitmap.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <GLES3/gl3.h> #include <ETC1/etc1.h> -#include <SkBitmap.h> - #include "core_jni_helpers.h" -#include "android/graphics/Bitmap.h" #undef LOG_TAG #define LOG_TAG "OpenGLUtil" @@ -628,31 +626,27 @@ void util_multiplyMV(JNIEnv *env, jclass clazz, // The internal format is no longer the same as pixel format, per Table 2 in // https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glTexImage2D.xhtml -static int checkInternalFormat(SkColorType colorType, int internalformat, - int type) +static bool checkInternalFormat(int32_t bitmapFormat, int internalformat, int type) { - switch(colorType) { - case kN32_SkColorType: - return (type == GL_UNSIGNED_BYTE && - internalformat == GL_RGBA) || - (type == GL_UNSIGNED_BYTE && - internalformat == GL_SRGB8_ALPHA8) ? 0 : -1; - case kAlpha_8_SkColorType: - return (type == GL_UNSIGNED_BYTE && - internalformat == GL_ALPHA) ? 0 : -1; - case kARGB_4444_SkColorType: - return (type == GL_UNSIGNED_SHORT_4_4_4_4 && - internalformat == GL_RGBA) ? 0 : -1; - case kRGB_565_SkColorType: - return (type == GL_UNSIGNED_SHORT_5_6_5 && - internalformat == GL_RGB) ? 0 : -1; - case kRGBA_F16_SkColorType: - return (type == GL_HALF_FLOAT && - internalformat == GL_RGBA16F) ? 0 : -1; + if (internalformat == GL_PALETTE8_RGBA8_OES) { + return false; + } + switch(bitmapFormat) { + case ANDROID_BITMAP_FORMAT_RGBA_8888: + return (type == GL_UNSIGNED_BYTE && internalformat == GL_RGBA) || + (type == GL_UNSIGNED_BYTE && internalformat == GL_SRGB8_ALPHA8); + case ANDROID_BITMAP_FORMAT_A_8: + return (type == GL_UNSIGNED_BYTE && internalformat == GL_ALPHA); + case ANDROID_BITMAP_FORMAT_RGBA_4444: + return (type == GL_UNSIGNED_SHORT_4_4_4_4 && internalformat == GL_RGBA); + case ANDROID_BITMAP_FORMAT_RGB_565: + return (type == GL_UNSIGNED_SHORT_5_6_5 && internalformat == GL_RGB); + case ANDROID_BITMAP_FORMAT_RGBA_F16: + return (type == GL_HALF_FLOAT && internalformat == GL_RGBA16F); default: break; } - return -1; + return false; } // The internal format is no longer the same as pixel format, per Table 2 in @@ -670,107 +664,92 @@ static int getPixelFormatFromInternalFormat(uint32_t internalFormat) { } } -static int getInternalFormat(SkColorType colorType) -{ - switch(colorType) { - case kAlpha_8_SkColorType: +static int getInternalFormat(int32_t bitmapFormat) { + switch(bitmapFormat) { + case ANDROID_BITMAP_FORMAT_A_8: return GL_ALPHA; - case kARGB_4444_SkColorType: + case ANDROID_BITMAP_FORMAT_RGBA_4444: return GL_RGBA; - case kN32_SkColorType: + case ANDROID_BITMAP_FORMAT_RGBA_8888: return GL_RGBA; - case kRGB_565_SkColorType: + case ANDROID_BITMAP_FORMAT_RGB_565: return GL_RGB; - case kRGBA_F16_SkColorType: + case ANDROID_BITMAP_FORMAT_RGBA_F16: return GL_RGBA16F; default: return -1; } } -static int getType(SkColorType colorType) -{ - switch(colorType) { - case kAlpha_8_SkColorType: +static int getType(int32_t bitmapFormat) { + switch(bitmapFormat) { + case ANDROID_BITMAP_FORMAT_A_8: return GL_UNSIGNED_BYTE; - case kARGB_4444_SkColorType: + case ANDROID_BITMAP_FORMAT_RGBA_4444: return GL_UNSIGNED_SHORT_4_4_4_4; - case kN32_SkColorType: + case ANDROID_BITMAP_FORMAT_RGBA_8888: return GL_UNSIGNED_BYTE; - case kRGB_565_SkColorType: + case ANDROID_BITMAP_FORMAT_RGB_565: return GL_UNSIGNED_SHORT_5_6_5; - case kRGBA_F16_SkColorType: + case ANDROID_BITMAP_FORMAT_RGBA_F16: return GL_HALF_FLOAT; default: return -1; } } -static jint util_getInternalFormat(JNIEnv *env, jclass clazz, - jlong bitmapPtr) +static jint util_getInternalFormat(JNIEnv *env, jclass clazz, jobject bitmapObj) { - SkBitmap nativeBitmap; - bitmap::toSkBitmap(bitmapPtr, &nativeBitmap); - return getInternalFormat(nativeBitmap.colorType()); + graphics::Bitmap bitmap(env, bitmapObj); + return getInternalFormat(bitmap.getInfo().format); } -static jint util_getType(JNIEnv *env, jclass clazz, - jlong bitmapPtr) +static jint util_getType(JNIEnv *env, jclass clazz, jobject bitmapObj) { - SkBitmap nativeBitmap; - bitmap::toSkBitmap(bitmapPtr, &nativeBitmap); - return getType(nativeBitmap.colorType()); + graphics::Bitmap bitmap(env, bitmapObj); + return getType(bitmap.getInfo().format); } -static jint util_texImage2D(JNIEnv *env, jclass clazz, - jint target, jint level, jint internalformat, - jlong bitmapPtr, jint type, jint border) +static jint util_texImage2D(JNIEnv *env, jclass clazz, jint target, jint level, + jint internalformat, jobject bitmapObj, jint type, jint border) { - SkBitmap bitmap; - bitmap::toSkBitmap(bitmapPtr, &bitmap); - SkColorType colorType = bitmap.colorType(); + graphics::Bitmap bitmap(env, bitmapObj); + AndroidBitmapInfo bitmapInfo = bitmap.getInfo(); + if (internalformat < 0) { - internalformat = getInternalFormat(colorType); + internalformat = getInternalFormat(bitmapInfo.format); } if (type < 0) { - type = getType(colorType); - } - int err = checkInternalFormat(colorType, internalformat, type); - if (err) - return err; - const int w = bitmap.width(); - const int h = bitmap.height(); - const void* p = bitmap.getPixels(); - if (internalformat == GL_PALETTE8_RGBA8_OES) { - err = -1; - } else { - glTexImage2D(target, level, internalformat, w, h, border, - getPixelFormatFromInternalFormat(internalformat), type, p); + type = getType(bitmapInfo.format); } - return err; + + if (checkInternalFormat(bitmapInfo.format, internalformat, type)) { + glTexImage2D(target, level, internalformat, bitmapInfo.width, bitmapInfo.height, border, + getPixelFormatFromInternalFormat(internalformat), type, bitmap.getPixels()); + return 0; + } + return -1; } -static jint util_texSubImage2D(JNIEnv *env, jclass clazz, - jint target, jint level, jint xoffset, jint yoffset, - jlong bitmapPtr, jint format, jint type) +static jint util_texSubImage2D(JNIEnv *env, jclass clazz, jint target, jint level, + jint xoffset, jint yoffset, jobject bitmapObj, jint format, jint type) { - SkBitmap bitmap; - bitmap::toSkBitmap(bitmapPtr, &bitmap); - SkColorType colorType = bitmap.colorType(); - int internalFormat = getInternalFormat(colorType); + graphics::Bitmap bitmap(env, bitmapObj); + AndroidBitmapInfo bitmapInfo = bitmap.getInfo(); + + int internalFormat = getInternalFormat(bitmapInfo.format); if (format < 0) { format = getPixelFormatFromInternalFormat(internalFormat); if (format == GL_PALETTE8_RGBA8_OES) return -1; // glCompressedTexSubImage2D() not supported } - int err = checkInternalFormat(colorType, internalFormat, type); - if (err) - return err; - const int w = bitmap.width(); - const int h = bitmap.height(); - const void* p = bitmap.getPixels(); - glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p); - return 0; + + if (checkInternalFormat(bitmapInfo.format, internalFormat, type)) { + glTexSubImage2D(target, level, xoffset, yoffset, bitmapInfo.width, bitmapInfo.height, + format, type, bitmap.getPixels()); + return 0; + } + return -1; } /* @@ -1036,10 +1015,10 @@ static const JNINativeMethod gVisibilityMethods[] = { }; static const JNINativeMethod gUtilsMethods[] = { - { "native_getInternalFormat", "(J)I", (void*) util_getInternalFormat }, - { "native_getType", "(J)I", (void*) util_getType }, - { "native_texImage2D", "(IIIJII)I", (void*)util_texImage2D }, - { "native_texSubImage2D", "(IIIIJII)I", (void*)util_texSubImage2D }, + { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat }, + { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType }, + { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D }, + { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D }, }; static const JNINativeMethod gEtc1Methods[] = { diff --git a/core/jni/android_graphics_GraphicBuffer.cpp b/core/jni/android_graphics_GraphicBuffer.cpp index 43d22eb7df0e..b6d50898a057 100644 --- a/core/jni/android_graphics_GraphicBuffer.cpp +++ b/core/jni/android_graphics_GraphicBuffer.cpp @@ -178,9 +178,9 @@ static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, nativeBuffer.format = AHardwareBuffer_convertFromPixelFormat(buffer->getPixelFormat()); nativeBuffer.bits = bits; - ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj); - ACanvas_setBuffer(canvas, &nativeBuffer, ADATASPACE_UNKNOWN); - ACanvas_clipRect(canvas, {rect.left, rect.top, rect.right, rect.bottom}); + graphics::Canvas canvas(env, canvasObj); + canvas.setBuffer(&nativeBuffer, ADATASPACE_UNKNOWN); + canvas.clipRect({rect.left, rect.top, rect.right, rect.bottom}); if (dirtyRect) { INVOKEV(dirtyRect, gRectClassInfo.set, @@ -193,8 +193,8 @@ static jboolean android_graphics_GraphicBuffer_lockCanvas(JNIEnv* env, jobject, static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject, jlong wrapperHandle, jobject canvasObj) { // release the buffer from the canvas - ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj); - ACanvas_setBuffer(canvas, nullptr, ADATASPACE_UNKNOWN); + graphics::Canvas canvas(env, canvasObj); + canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN); GraphicBufferWrapper* wrapper = reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle); diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index bf4ffc7e42e0..daf33f61105c 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -352,7 +352,7 @@ static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) { } static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr, - jstring package_name) { + jstring package_name) { ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); const ScopedUtfChars package_name_utf8(env, package_name); CHECK(package_name_utf8.c_str() != nullptr); @@ -397,6 +397,21 @@ static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr, return array_map; } +static jstring NativeGetOverlayablesToString(JNIEnv* env, jclass /*clazz*/, jlong ptr, + jstring package_name) { + ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); + const ScopedUtfChars package_name_utf8(env, package_name); + CHECK(package_name_utf8.c_str() != nullptr); + const std::string std_package_name(package_name_utf8.c_str()); + + std::string result; + if (!assetmanager->GetOverlayablesToString(std_package_name, &result)) { + return nullptr; + } + + return env->NewStringUTF(result.c_str()); +} + #ifdef __ANDROID__ // Layoutlib does not support parcel static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset, jlongArray out_offsets) { @@ -1608,6 +1623,8 @@ static const JNINativeMethod gAssetManagerMethods[] = { (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid}, {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;", (void*)NativeGetOverlayableMap}, + {"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;", + (void*)NativeGetOverlayablesToString}, // Global management/debug methods. {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount}, diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp index 4f79790dec51..ed2ce506ab23 100644 --- a/core/jni/android_view_PointerIcon.cpp +++ b/core/jni/android_view_PointerIcon.cpp @@ -23,7 +23,7 @@ #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <utils/Log.h> -#include <android/graphics/GraphicsJNI.h> +#include <android/graphics/bitmap.h> #include <nativehelper/ScopedLocalRef.h> #include "core_jni_helpers.h" @@ -88,7 +88,7 @@ status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIcon ScopedLocalRef<jobject> bitmapObj( env, env->GetObjectField(pointerIconObj, gPointerIconClassInfo.mBitmap)); if (bitmapObj.get()) { - GraphicsJNI::getSkBitmap(env, bitmapObj.get(), &(outPointerIcon->bitmap)); + outPointerIcon->bitmap = graphics::Bitmap(env, bitmapObj.get()); } ScopedLocalRef<jobjectArray> bitmapFramesObj(env, reinterpret_cast<jobjectArray>( @@ -100,7 +100,7 @@ status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIcon outPointerIcon->bitmapFrames.resize(size); for (jsize i = 0; i < size; ++i) { ScopedLocalRef<jobject> bitmapObj(env, env->GetObjectArrayElement(bitmapFramesObj.get(), i)); - GraphicsJNI::getSkBitmap(env, bitmapObj.get(), &(outPointerIcon->bitmapFrames[i])); + outPointerIcon->bitmapFrames[i] = graphics::Bitmap(env, bitmapObj.get()); } } diff --git a/core/jni/android_view_PointerIcon.h b/core/jni/android_view_PointerIcon.h index 00bdfb4bf04e..908948ea2aa4 100644 --- a/core/jni/android_view_PointerIcon.h +++ b/core/jni/android_view_PointerIcon.h @@ -21,8 +21,8 @@ #include <vector> +#include <android/graphics/bitmap.h> #include <utils/Errors.h> -#include <SkBitmap.h> namespace android { @@ -68,10 +68,10 @@ struct PointerIcon { } int32_t style; - SkBitmap bitmap; + graphics::Bitmap bitmap; float hotSpotX; float hotSpotY; - std::vector<SkBitmap> bitmapFrames; + std::vector<graphics::Bitmap> bitmapFrames; int32_t durationPerFrame; inline bool isNullIcon() { diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 4c2e91f986d0..058a4c8ee2f9 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -237,12 +237,11 @@ static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, return 0; } - ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj); - ACanvas_setBuffer(canvas, &buffer, static_cast<int32_t>(surface->getBuffersDataSpace())); + graphics::Canvas canvas(env, canvasObj); + canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace())); if (dirtyRectPtr) { - ACanvas_clipRect(canvas, {dirtyRect.left, dirtyRect.top, - dirtyRect.right, dirtyRect.bottom}); + canvas.clipRect({dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom}); } if (dirtyRectObj) { @@ -268,8 +267,8 @@ static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz, } // detach the canvas from the surface - ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj); - ACanvas_setBuffer(canvas, nullptr, ADATASPACE_UNKNOWN); + graphics::Canvas canvas(env, canvasObj); + canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN); // unlock surface status_t err = surface->unlockAndPost(); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index bf0f10eb50c6..1ca9383b920f 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -458,15 +458,6 @@ static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactio transaction->setInputWindowInfo(ctrl, *handle->getInfo()); } -static void nativeTransferTouchFocus(JNIEnv* env, jclass clazz, jlong transactionObj, - jobject fromTokenObj, jobject toTokenObj) { - auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); - - sp<IBinder> fromToken(ibinderForJavaObject(env, fromTokenObj)); - sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj)); - transaction->transferTouchFocus(fromToken, toToken); -} - static void nativeSyncInputWindows(JNIEnv* env, jclass clazz, jlong transactionObj) { auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); transaction->syncInputWindows(); @@ -1381,8 +1372,6 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeCaptureLayers }, {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V", (void*)nativeSetInputWindowInfo }, - {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V", - (void*)nativeTransferTouchFocus }, {"nativeSetMetadata", "(JJILandroid/os/Parcel;)V", (void*)nativeSetMetadata }, {"nativeGetDisplayedContentSamplingAttributes", diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp index 1ccb6a8f610c..8a3f54039d05 100644 --- a/core/jni/android_view_TextureLayer.cpp +++ b/core/jni/android_view_TextureLayer.cpp @@ -26,10 +26,7 @@ #include <gui/GLConsumer.h> #include <hwui/Paint.h> -#include <SkBitmap.h> -#include <SkCanvas.h> #include <SkMatrix.h> -#include <SkBlendMode.h> #include <DeferredLayerUpdater.h> #include <Rect.h> diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp index 1f69c8bbbe5d..391f515af115 100644 --- a/core/jni/android_view_TextureView.cpp +++ b/core/jni/android_view_TextureView.cpp @@ -124,9 +124,9 @@ static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject, int32_t status = native_window_lock(window.get(), &outBuffer, &rect); if (status) return JNI_FALSE; - ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj); - ACanvas_setBuffer(canvas, &outBuffer, ANativeWindow_getBuffersDataSpace(window.get())); - ACanvas_clipRect(canvas, {rect.left, rect.top, rect.right, rect.bottom}); + graphics::Canvas canvas(env, canvasObj); + canvas.setBuffer(&outBuffer, ANativeWindow_getBuffersDataSpace(window.get())); + canvas.clipRect({rect.left, rect.top, rect.right, rect.bottom}); if (dirtyRect) { INVOKEV(dirtyRect, gRectClassInfo.set, @@ -140,8 +140,8 @@ static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject, jlong nativeWindow, jobject canvasObj) { // release the buffer from the canvas - ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj); - ACanvas_setBuffer(canvas, nullptr, ADATASPACE_UNKNOWN); + graphics::Canvas canvas(env, canvasObj); + canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN); if (nativeWindow) { sp<ANativeWindow> window((ANativeWindow*) nativeWindow); diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 93ef75148df7..3516dce5d5ed 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -74,7 +74,6 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <bionic/malloc.h> -#include <cutils/ashmem.h> #include <cutils/fs.h> #include <cutils/multiuser.h> #include <cutils/sockets.h> @@ -1657,11 +1656,6 @@ static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jc if (!SetTaskProfiles(0, {})) { ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed"); } - - /* - * ashmem initialization to avoid dlopen overhead - */ - ashmem_init(); } /** diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index a4c504b9cbdf..c009f588f8a9 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -74,7 +74,6 @@ java_genrule { ":FrameworksCoreTests_install_loc_internal", ":FrameworksCoreTests_install_loc_sdcard", ":FrameworksCoreTests_install_loc_unspecified", - ":FrameworksCoreTests_install_multi_package", ":FrameworksCoreTests_install_split_base", ":FrameworksCoreTests_install_split_feature_a", ":FrameworksCoreTests_install_use_perm_good", diff --git a/core/tests/coretests/apks/install_multi_package/Android.bp b/core/tests/coretests/apks/install_multi_package/Android.bp deleted file mode 100644 index 249242e239e4..000000000000 --- a/core/tests/coretests/apks/install_multi_package/Android.bp +++ /dev/null @@ -1,6 +0,0 @@ -android_test_helper_app { - name: "FrameworksCoreTests_install_multi_package", - defaults: ["FrameworksCoreTests_apks_defaults"], - - srcs: ["**/*.java"], -} diff --git a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml b/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml deleted file mode 100644 index 5164cae9e5c0..000000000000 --- a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml +++ /dev/null @@ -1,104 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 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. ---> -<manifest - xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.frameworks.coretests.install_multi_package"> - -<!-- - This manifest is has child packages with components. ---> - - <uses-feature - android:name="com.android.frameworks.coretests.nonexistent" /> - <uses-configuration - android:reqFiveWayNav="false" /> - - <instrumentation - android:name="android.test.InstrumentationTestRunner" - android:targetPackage="com.android.frameworks.coretests" - android:label="Frameworks Core Tests" /> - - <permission - android:label="test permission" - android:name="test_permission" - android:protectionLevel="normal" /> - <uses-permission android:name="android.permission.INTERNET" /> - -<!-- - NOTE: This declares a child package, application, then another child - package, to test potential bugs that are order-dependent. Also, each - one varies the order. ---> - - <package package="com.android.frameworks.coretests.install_multi_package.first_child"> - <uses-permission android:name="android.permission.NFC" /> - <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. --> - <permission - android:label="test permission" - android:name="first_child_permission" - android:protectionLevel="signature" /> - <application - android:hasCode="true"> - <activity - android:name="com.android.frameworks.coretests.FirstChildTestActivity"> - </activity> - <provider - android:name="com.android.frameworks.coretests.FirstChildTestProvider" - android:authorities="com.android.frameworks.coretests.testprovider" /> - <receiver - android:name="com.android.frameworks.coretests.FirstChildTestReceiver" /> - <service - android:name="com.android.frameworks.coretests.FirstChildTestService" /> - </application> - </package> - - <application - android:hasCode="true"> - <service - android:name="com.android.frameworks.coretests.TestService" /> - <activity - android:name="com.android.frameworks.coretests.TestActivity"> - </activity> - <provider - android:name="com.android.frameworks.coretests.TestProvider" - android:authorities="com.android.frameworks.coretests.testprovider" /> - <receiver - android:name="com.android.frameworks.coretests.TestReceiver" /> - </application> - - <package package="com.android.frameworks.coretests.blah.second_child"> - <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" /> - <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. --> - <permission - android:label="test permission" - android:name="second_child_permission" - android:protectionLevel="dangerous" /> - <application - android:hasCode="true"> - <receiver - android:name="com.android.frameworks.coretests.SecondChildTestReceiver" /> - <service - android:name="com.android.frameworks.coretests.SecondChildTestService" /> - <activity - android:name="com.android.frameworks.coretests.SecondChildTestActivity"> - </activity> - <provider - android:name="com.android.frameworks.coretests.SecondChildTestProvider" - android:authorities="com.android.frameworks.coretests.testprovider" /> - </application> - </package> -</manifest> diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java deleted file mode 100644 index 2816865b2f1f..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class FirstChildTestProvider extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java deleted file mode 100644 index ffe84b73dd37..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class FirstChildTestReceiver extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java deleted file mode 100644 index 2bd40a5df94d..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class SecondChildTestProvider extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java deleted file mode 100644 index a6c4ddc90c6a..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class SecondChildTestReceiver extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java deleted file mode 100644 index 59f9f10c6efe..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class TestProvider extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java deleted file mode 100644 index 21f6263a38bc..000000000000 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 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 com.android.frameworks.coretests; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -public class TestReceiver extends ContentProvider { - - @Override - public boolean onCreate() { - return false; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java deleted file mode 100644 index cc48239c4526..000000000000 --- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2018 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 static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER; - -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Test for {@link AndroidHidlUpdater} - */ -@SmallTest -@RunWith(JUnit4.class) -public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_P() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.P); - - // no change, not system - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_P_system() { - PackageBuilder before = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P); - - // Should add both HIDL libraries - PackageBuilder after = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_P_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(OTHER_LIBRARY); - - // no change, not system - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_P_not_empty_usesLibraries_system() { - PackageBuilder before = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(OTHER_LIBRARY); - - // The hidl jars should be added at the start of the list because it - // is not on the bootclasspath and the package targets pre-P. - PackageBuilder after = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_P_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE); - - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.P); - - // Libraries are removed because they are not available for non-system apps - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_P_in_usesLibraries_system() { - PackageBuilder before = builder().asSystemApp() - .targetSdkVersion(Build.VERSION_CODES.P) - .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE); - - // No change is required because the package explicitly requests the HIDL libraries - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ANDROID_HIDL_BASE); - - // Dependency is removed, it is not available. - PackageBuilder after = builder(); - - // Libraries are removed because they are not available for apps targetting Q+ - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ANDROID_HIDL_BASE); - - // Dependency is removed, it is not available. - PackageBuilder after = builder(); - - // Libraries are removed because they are not available for apps targetting Q+ - checkBackwardsCompatibility(before, after); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new); - } -} diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java deleted file mode 100644 index 03108ced4816..000000000000 --- a/core/tests/coretests/src/android/content/pm/AndroidTestBaseUpdaterTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2018 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 static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; - -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test for {@link AndroidTestBaseUpdater} - */ -@SmallTest -@RunWith(OptionalClassRunner.class) -@OptionalClassRunner.OptionalClass("android.content.pm.AndroidTestBaseUpdater") -public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_Q() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.Q); - - // Should add org.apache.http.legacy. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .requiredLibraries(ANDROID_TEST_BASE); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_Q_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .requiredLibraries(OTHER_LIBRARY); - - // The org.apache.http.legacy jar should be added at the start of the list because it - // is not on the bootclasspath and the package targets pre-Q. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .requiredLibraries(ANDROID_TEST_BASE, OTHER_LIBRARY); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_Q_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .requiredLibraries(ANDROID_TEST_BASE); - - // No change is required because although org.apache.http.legacy has been removed from - // the bootclasspath the package explicitly requests it. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_Q_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.Q) - .optionalLibraries(ANDROID_TEST_BASE); - - // No change is required because although org.apache.http.legacy has been removed from - // the bootclasspath the package explicitly requests it. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE); - - // No change is required because the package explicitly requests org.apache.http.legacy - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE); - - // No change is required because the package explicitly requests org.apache.http.legacy - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new); - } -} diff --git a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java deleted file mode 100644 index 7f817d66caf7..000000000000 --- a/core/tests/coretests/src/android/content/pm/AndroidTestRunnerSplitUpdaterTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2018 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 static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; - -import android.content.pm.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Test for {@link AndroidTestRunnerSplitUpdater} - */ -@SmallTest -@RunWith(JUnit4.class) -public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest { - - @Test - public void android_test_runner_in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_RUNNER); - - PackageBuilder after = builder() - .optionalLibraries(ANDROID_TEST_MOCK, ANDROID_TEST_RUNNER); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .requiredLibraries(ANDROID_TEST_RUNNER) - .optionalLibraries(ANDROID_TEST_MOCK); - - PackageBuilder after = builder() - .requiredLibraries(ANDROID_TEST_RUNNER) - .optionalLibraries(ANDROID_TEST_MOCK); - - checkBackwardsCompatibility(before, after); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new); - } -} diff --git a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java deleted file mode 100644 index 834a0bbeab89..000000000000 --- a/core/tests/coretests/src/android/content/pm/OrgApacheHttpLegacyUpdaterTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2018 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 static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; - -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Test for {@link OrgApacheHttpLegacyUpdater} - */ -@SmallTest -@RunWith(OptionalClassRunner.class) -@OptionalClassRunner.OptionalClass("android.content.pm.OrgApacheHttpLegacyUpdater") -public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_O() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - // Should add org.apache.http.legacy. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_O_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(OTHER_LIBRARY); - - // The org.apache.http.legacy jar should be added at the start of the list because it - // is not on the bootclasspath and the package targets pre-P. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_O_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - // No change is required because although org.apache.http.legacy has been removed from - // the bootclasspath the package explicitly requests it. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // No change is required because although org.apache.http.legacy has been removed from - // the bootclasspath the package explicitly requests it. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - // No change is required because the package explicitly requests org.apache.http.legacy - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // No change is required because the package explicitly requests org.apache.http.legacy - // and is targeted at the current version so does not need backwards compatibility. - checkBackwardsCompatibility(before, before); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new); - } -} diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java deleted file mode 100644 index f7544af43461..000000000000 --- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2018 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 static org.junit.Assert.assertEquals; - -import android.os.Build; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Test support for building {@link PackageParser.Package} instances. - */ -class PackageBuilder { - - private int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; - - private int mFlags = 0; - - private ArrayList<String> mRequiredLibraries; - - private ArrayList<String> mOptionalLibraries; - - public static PackageBuilder builder() { - return new PackageBuilder(); - } - - public PackageParser.Package build() { - PackageParser.Package pkg = new PackageParser.Package("org.package.name"); - pkg.applicationInfo.targetSdkVersion = mTargetSdkVersion; - pkg.applicationInfo.flags = mFlags; - pkg.usesLibraries = mRequiredLibraries; - pkg.usesOptionalLibraries = mOptionalLibraries; - return pkg; - } - - PackageBuilder targetSdkVersion(int version) { - this.mTargetSdkVersion = version; - return this; - } - - PackageBuilder asSystemApp() { - this.mFlags |= ApplicationInfo.FLAG_SYSTEM; - return this; - } - - PackageBuilder requiredLibraries(String... names) { - this.mRequiredLibraries = arrayListOrNull(names); - return this; - } - - PackageBuilder requiredLibraries(List<String> names) { - this.mRequiredLibraries = arrayListOrNull(names.toArray(new String[names.size()])); - return this; - } - - PackageBuilder optionalLibraries(String... names) { - this.mOptionalLibraries = arrayListOrNull(names); - return this; - } - - /** - * Check that this matches the supplied {@link PackageParser.Package}. - * - * @param pkg the instance to compare with this. - */ - public void check(PackageParser.Package pkg) { - assertEquals("targetSdkVersion should not be changed", - mTargetSdkVersion, - pkg.applicationInfo.targetSdkVersion); - assertEquals("usesLibraries not updated correctly", - mRequiredLibraries, - pkg.usesLibraries); - assertEquals("usesOptionalLibraries not updated correctly", - mOptionalLibraries, - pkg.usesOptionalLibraries); - } - - private static ArrayList<String> arrayListOrNull(String... strings) { - if (strings == null || strings.length == 0) { - return null; - } - ArrayList<String> list = new ArrayList<>(); - Collections.addAll(list, strings); - return list; - } - -} diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java index 5c7f2af782b9..cb23850798c3 100644 --- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java +++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java @@ -23,26 +23,26 @@ import static org.junit.Assert.assertTrue; import android.apex.ApexInfo; import android.content.Context; -import android.content.pm.PackageParser.Component; -import android.content.pm.PackageParser.Package; -import android.content.pm.PackageParser.Permission; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ParsedPackage; import android.os.Build; import android.os.Bundle; import android.os.FileUtils; -import android.os.SystemProperties; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.coretests.R; +import com.android.internal.util.ArrayUtils; import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; import java.io.InputStream; -import java.util.Arrays; import java.util.function.Function; @SmallTest @@ -59,8 +59,8 @@ public class PackageParserTest { private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint"; private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint"; - private static final String[] CODENAMES_RELEASED = { /* empty */ }; - private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE }; + private static final String[] CODENAMES_RELEASED = { /* empty */}; + private static final String[] CODENAMES_PRE_RELEASE = {PRE_RELEASE}; private static final int OLDER_VERSION = 10; private static final int PLATFORM_VERSION = 20; @@ -300,10 +300,6 @@ public class PackageParserTest { assertEquals(0x0083, finalConfigChanges); // Should be 10000011. } - Package parsePackage(String apkFileName, int apkResourceId) throws Exception { - return parsePackage(apkFileName, apkResourceId, p -> p); - } - /** * Copies a specified {@code resourceId} to a file. Returns a non-null file if the copy * succeeded, or {@code null} otherwise. @@ -331,16 +327,17 @@ public class PackageParserTest { * * APKs are put into coretests/apks/packageparser_*. * - * @param apkFileName temporary file name to store apk extracted from resources + * @param apkFileName temporary file name to store apk extracted from resources * @param apkResourceId identifier of the apk as a resource */ - Package parsePackage(String apkFileName, int apkResourceId, - Function<Package, Package> converter) throws Exception { + ParsedPackage parsePackage(String apkFileName, int apkResourceId, + Function<ParsedPackage, ParsedPackage> converter) throws Exception { // Copy the resource to a file. File outFile = null; try { outFile = copyRawResourceToFile(apkFileName, apkResourceId); - return converter.apply(new PackageParser().parsePackage(outFile, 0 /* flags */)); + return converter.apply( + new PackageParser().parseParsedPackage(outFile, 0 /* flags */, false)); } finally { if (outFile != null) { outFile.delete(); @@ -351,40 +348,40 @@ public class PackageParserTest { /** * Asserts basic properties about a component. */ - private void assertComponent(String className, String packageName, int numIntents, - Component<?> component) { + private void assertComponent(String className, int numIntents, ParsedComponent<?> component) { assertEquals(className, component.className); - assertEquals(packageName, component.owner.packageName); assertEquals(numIntents, component.intents.size()); } /** * Asserts four regularly-named components of each type: one Activity, one Service, one * Provider, and one Receiver. + * * @param template templated string with %s subbed with Activity, Service, Provider, Receiver */ - private void assertOneComponentOfEachType(String template, Package p) { - String packageName = p.packageName; + private void assertOneComponentOfEachType(String template, AndroidPackage p) { + assertEquals(2, p.getActivities().size()); + + // For normal apps, a Activity that forwards to the App Details page is added. + assertEquals("android.app.AppDetailsActivity", p.getActivities().get(1) + .className); - assertEquals(1, p.activities.size()); assertComponent(String.format(template, "Activity"), - packageName, 0 /* intents */, p.activities.get(0)); - assertEquals(1, p.services.size()); + 0 /* intents */, p.getActivities().get(0)); + assertEquals(1, p.getServices().size()); assertComponent(String.format(template, "Service"), - packageName, 0 /* intents */, p.services.get(0)); - assertEquals(1, p.providers.size()); + 0 /* intents */, p.getServices().get(0)); + assertEquals(1, p.getProviders().size()); assertComponent(String.format(template, "Provider"), - packageName, 0 /* intents */, p.providers.get(0)); - assertEquals(1, p.receivers.size()); + 0 /* intents */, p.getProviders().get(0)); + assertEquals(1, p.getReceivers().size()); assertComponent(String.format(template, "Receiver"), - packageName, 0 /* intents */, p.receivers.get(0)); + 0 /* intents */, p.getReceivers().get(0)); } - private void assertPermission(String name, String packageName, int protectionLevel, - Permission permission) { - assertEquals(packageName, permission.owner.packageName); - assertEquals(name, permission.info.name); - assertEquals(protectionLevel, permission.info.protectionLevel); + private void assertPermission(String name, int protectionLevel, ParsedPermission permission) { + assertEquals(name, permission.getName()); + assertEquals(protectionLevel, permission.getProtection()); } private void assertMetadata(Bundle b, String... keysAndValues) { @@ -416,25 +413,25 @@ public class PackageParserTest { } private void checkPackageWithComponents( - Function<Package, Package> converter) throws Exception { - Package p = parsePackage( + Function<ParsedPackage, ParsedPackage> converter) throws Exception { + ParsedPackage p = parsePackage( "install_complete_package_info.apk", R.raw.install_complete_package_info, converter); String packageName = "com.android.frameworks.coretests.install_complete_package_info"; - assertEquals(packageName, p.packageName); - assertEquals(1, p.permissions.size()); + assertEquals(packageName, p.getPackageName()); + assertEquals(1, p.getPermissions().size()); assertPermission( "com.android.frameworks.coretests.install_complete_package_info.test_permission", - packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0)); + PermissionInfo.PROTECTION_NORMAL, p.getPermissions().get(0)); // Hidden "app details" activity is added to every package. boolean foundAppDetailsActivity = false; - for (int i = 0; i < p.activities.size(); i++) { - if (p.activities.get(i).className.equals( + for (int i = 0; i < ArrayUtils.size(p.getActivities()); i++) { + if (p.getActivities().get(i).className.equals( PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME)) { foundAppDetailsActivity = true; - p.activities.remove(i); + p.getActivities().remove(i); break; } } @@ -442,72 +439,23 @@ public class PackageParserTest { assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p); - assertMetadata(p.mAppMetaData, + assertMetadata(p.getAppMetaData(), "key1", "value1", "key2", "this_is_app"); - assertMetadata(p.activities.get(0).metaData, + assertMetadata(p.getActivities().get(0).getMetaData(), "key1", "value1", "key2", "this_is_activity"); - assertMetadata(p.services.get(0).metaData, + assertMetadata(p.getServices().get(0).getMetaData(), "key1", "value1", "key2", "this_is_service"); - assertMetadata(p.receivers.get(0).metaData, + assertMetadata(p.getReceivers().get(0).getMetaData(), "key1", "value1", "key2", "this_is_receiver"); - assertMetadata(p.providers.get(0).metaData, + assertMetadata(p.getProviders().get(0).getMetaData(), "key1", "value1", "key2", "this_is_provider"); } - /** - * Determines if the current device supports multi-package APKs. - */ - private boolean supportsMultiPackageApk() { - return SystemProperties.getBoolean("persist.sys.child_packages_enabled", false); - } - - @Test - public void testMultiPackageComponents() throws Exception { - // TODO(gboyer): Remove once we decide to launch multi-package APKs. - if (!supportsMultiPackageApk()) { - return; - } - String parentName = "com.android.frameworks.coretests.install_multi_package"; - String firstChildName = - "com.android.frameworks.coretests.install_multi_package.first_child"; - String secondChildName = // NOTE: intentionally inconsistent! - "com.android.frameworks.coretests.blah.second_child"; - - Package parent = parsePackage("install_multi_package.apk", R.raw.install_multi_package); - assertEquals(parentName, parent.packageName); - assertEquals(2, parent.childPackages.size()); - assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", parent); - assertEquals(1, parent.permissions.size()); - assertPermission(parentName + ".test_permission", parentName, - PermissionInfo.PROTECTION_NORMAL, parent.permissions.get(0)); - assertEquals(Arrays.asList("android.permission.INTERNET"), - parent.requestedPermissions); - - Package firstChild = parent.childPackages.get(0); - assertEquals(firstChildName, firstChild.packageName); - assertOneComponentOfEachType( - "com.android.frameworks.coretests.FirstChildTest%s", firstChild); - assertEquals(0, firstChild.permissions.size()); // Child APKs cannot declare permissions. - assertEquals(Arrays.asList("android.permission.NFC"), - firstChild.requestedPermissions); - - Package secondChild = parent.childPackages.get(1); - assertEquals(secondChildName, secondChild.packageName); - assertOneComponentOfEachType( - "com.android.frameworks.coretests.SecondChildTest%s", secondChild); - assertEquals(0, secondChild.permissions.size()); // Child APKs cannot declare permissions. - assertEquals( - Arrays.asList( - "android.permission.ACCESS_NETWORK_STATE", - "android.permission.READ_CONTACTS"), - secondChild.requestedPermissions); - } - @Test public void testApexPackageInfoGeneration() throws Exception { String apexModuleName = "com.android.tzdata.apex"; @@ -522,7 +470,7 @@ public class PackageParserTest { int flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES; PackageParser pp = new PackageParser(); - Package p = pp.parsePackage(apexFile, flags, false); + PackageParser.Package p = pp.parsePackage(apexFile, flags, false); PackageParser.collectCertificates(p, false); PackageInfo pi = PackageParser.generatePackageInfo(p, apexInfo, flags); diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java deleted file mode 100644 index 216b0c8950b7..000000000000 --- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryAndroidTestBaseLibraryTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2018 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 static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; - -import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary} - */ -@SmallTest -@RunWith(JUnit4.class) -public class RemoveUnnecessaryAndroidTestBaseLibraryTest - extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_O() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - // No change required. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(OTHER_LIBRARY); - - // No change required. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_O_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .optionalLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_bothLibraries() { - PackageBuilder before = builder() - .requiredLibraries(ANDROID_TEST_BASE) - .optionalLibraries(ANDROID_TEST_BASE); - - // android.test.base should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - // TODO(b/72538146) - Cannot use constructor reference here because it is also used in - // PackageBackwardCompatibility and that seems to create a package-private lambda in - // android.content.pm which this then tries to reuse but fails because it cannot access - // package-private classes/members because the test is loaded by a different ClassLoader - // than the lambda. - checkBackwardsCompatibility(before, after, - () -> new RemoveUnnecessaryAndroidTestBaseLibrary()); - } - -} diff --git a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java deleted file mode 100644 index fc60980bb796..000000000000 --- a/core/tests/coretests/src/android/content/pm/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2018 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 static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; - -import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary; -import android.os.Build; - -import androidx.test.filters.SmallTest; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary} - */ -@SmallTest -@RunWith(JUnit4.class) -public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest - extends PackageSharedLibraryUpdaterTest { - - private static final String OTHER_LIBRARY = "other.library"; - - @Test - public void targeted_at_O() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - // No change required. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_not_empty_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(OTHER_LIBRARY); - - // No change required. - checkBackwardsCompatibility(before, before); - } - - @Test - public void targeted_at_O_in_usesLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void targeted_at_O_in_usesOptionalLibraries() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_usesOptionalLibraries() { - PackageBuilder before = builder().optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - @Test - public void in_bothLibraries() { - PackageBuilder before = builder() - .requiredLibraries(ORG_APACHE_HTTP_LEGACY) - .optionalLibraries(ORG_APACHE_HTTP_LEGACY); - - // org.apache.http.legacy should be removed from the libraries because it is provided - // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); - - checkBackwardsCompatibility(before, after); - } - - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { - // TODO(b/72538146) - Cannot use constructor reference here because it is also used in - // PackageBackwardCompatibility and that seems to create a package-private lambda in - // android.content.pm which this then tries to reuse but fails because it cannot access - // package-private classes/members because the test is loaded by a different ClassLoader - // than the lambda. - checkBackwardsCompatibility(before, after, - () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary()); - } -} diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java index 49849ee72a18..1e0bfb08693f 100644 --- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java +++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java @@ -25,9 +25,9 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; -import android.content.pm.PackageParser.Package; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.parsing.ParsedPackage; import android.os.FileUtils; import androidx.test.InstrumentationRegistry; @@ -36,7 +36,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.coretests.R; -import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -95,13 +94,13 @@ public class DexMetadataHelperTest { public void testParsePackageWithDmFileValid() throws IOException, PackageParserException { copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); createDexMetadataFile("install_split_base.apk"); - Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); assertEquals(1, packageDexMetadata.size()); - String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath); + String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath()); assertNotNull(baseDexMetadata); - assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath)); + assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath())); } @Test @@ -111,17 +110,17 @@ public class DexMetadataHelperTest { copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); createDexMetadataFile("install_split_base.apk"); createDexMetadataFile("install_split_feature_a.apk"); - Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); assertEquals(2, packageDexMetadata.size()); - String baseDexMetadata = packageDexMetadata.get(pkg.baseCodePath); + String baseDexMetadata = packageDexMetadata.get(pkg.getBaseCodePath()); assertNotNull(baseDexMetadata); - assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.baseCodePath)); + assertTrue(isDexMetadataForApk(baseDexMetadata, pkg.getBaseCodePath())); - String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]); + String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]); assertNotNull(splitDexMetadata); - assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0])); + assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0])); } @Test @@ -130,14 +129,14 @@ public class DexMetadataHelperTest { copyApkToToTmpDir("install_split_base.apk", R.raw.install_split_base); copyApkToToTmpDir("install_split_feature_a.apk", R.raw.install_split_feature_a); createDexMetadataFile("install_split_feature_a.apk"); - Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser().parseParsedPackage(mTmpDir, 0 /* flags */, false); Map<String, String> packageDexMetadata = DexMetadataHelper.getPackageDexMetadata(pkg); assertEquals(1, packageDexMetadata.size()); - String splitDexMetadata = packageDexMetadata.get(pkg.splitCodePaths[0]); + String splitDexMetadata = packageDexMetadata.get(pkg.getSplitCodePaths()[0]); assertNotNull(splitDexMetadata); - assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.splitCodePaths[0])); + assertTrue(isDexMetadataForApk(splitDexMetadata, pkg.getSplitCodePaths()[0])); } @Test @@ -146,7 +145,8 @@ public class DexMetadataHelperTest { File invalidDmFile = new File(mTmpDir, "install_split_base.dm"); Files.createFile(invalidDmFile.toPath()); try { - PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser() + .parseParsedPackage(mTmpDir, 0 /* flags */, false); DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA); @@ -163,7 +163,8 @@ public class DexMetadataHelperTest { Files.createFile(invalidDmFile.toPath()); try { - PackageParser.Package pkg = new PackageParser().parsePackage(mTmpDir, 0 /* flags */); + ParsedPackage pkg = new PackageParser() + .parseParsedPackage(mTmpDir, 0 /* flags */, false); DexMetadataHelper.validatePackageDexMetadata(pkg); } catch (PackageParserException e) { assertEquals(e.error, PackageManager.INSTALL_FAILED_BAD_DEX_METADATA); diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java new file mode 100644 index 000000000000..21479c096752 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidHidlUpdaterTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2019 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.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_HIDL_MANAGER; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link AndroidHidlUpdater} + */ +@SmallTest +@RunWith(JUnit4.class) +public class AndroidHidlUpdaterTest extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_P() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .hideAsParsed() + .hideAsFinal(); + + // no change, not system + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_system() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .hideAsParsed() + .setSystem(true); + + // Should add both HIDL libraries + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed() + .setSystem(true) + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + // no change, not system + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_not_empty_usesLibraries_system() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .setSystem(true); + + // The hidl jars should be added at the start of the list because it + // is not on the bootclasspath and the package targets pre-P. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .setSystem(true) + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .hideAsParsed() + .hideAsFinal(); + + // Libraries are removed because they are not available for non-system apps + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_P_in_usesLibraries_system() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed() + .setSystem(true); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.P) + .addUsesLibrary(ANDROID_HIDL_MANAGER) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed() + .setSystem(true) + .hideAsFinal(); + + // No change is required because the package explicitly requests the HIDL libraries + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_HIDL_BASE) + .hideAsParsed(); + + // Dependency is removed, it is not available. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + // Libraries are removed because they are not available for apps targeting Q+ + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_HIDL_BASE) + .hideAsParsed(); + + // Dependency is removed, it is not available. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + // Libraries are removed because they are not available for apps targeting Q+ + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, AndroidHidlUpdater::new); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java new file mode 100644 index 000000000000..65ae219058f4 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestBaseUpdaterTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2019 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.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; + +import android.content.pm.OptionalClassRunner; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test for {@link AndroidTestBaseUpdater} + */ +@SmallTest +@RunWith(OptionalClassRunner.class) +@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.AndroidTestBaseUpdater") +public class AndroidTestBaseUpdaterTest extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_Q() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .hideAsParsed(); + + // Should add org.apache.http.legacy. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_Q_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + // The org.apache.http.legacy jar should be added at the start of the list because it + // is not on the bootclasspath and the package targets pre-Q. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(ANDROID_TEST_BASE) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_Q_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because although org.apache.http.legacy has been removed from + // the bootclasspath the package explicitly requests it. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_Q_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because although org.apache.http.legacy has been removed from + // the bootclasspath the package explicitly requests it. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, AndroidTestBaseUpdater::new); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java new file mode 100644 index 000000000000..38755b9aa965 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 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.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link AndroidTestRunnerSplitUpdater} + */ +@SmallTest +@RunWith(JUnit4.class) +public class AndroidTestRunnerSplitUpdaterTest extends PackageSharedLibraryUpdaterTest { + + @Test + public void android_test_runner_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_RUNNER) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_MOCK) + .addUsesOptionalLibrary(ANDROID_TEST_RUNNER) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void android_test_runner_in_usesLibraries_android_test_mock_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_RUNNER) + .addUsesOptionalLibrary(ANDROID_TEST_MOCK) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_RUNNER) + .addUsesOptionalLibrary(ANDROID_TEST_MOCK) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, AndroidTestRunnerSplitUpdater::new); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java new file mode 100644 index 000000000000..4c7899b47164 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2019 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.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; + +import android.content.pm.OptionalClassRunner; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test for {@link OrgApacheHttpLegacyUpdater} + */ +@SmallTest +@RunWith(OptionalClassRunner.class) +@OptionalClassRunner.OptionalClass("android.content.pm.parsing.library.OrgApacheHttpLegacyUpdater") +public class OrgApacheHttpLegacyUpdaterTest extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_O() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed(); + + // Should add org.apache.http.legacy. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + // The org.apache.http.legacy jar should be added at the start of the list because it + // is not on the bootclasspath and the package targets pre-P. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because although org.apache.http.legacy has been removed from + // the bootclasspath the package explicitly requests it. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because although org.apache.http.legacy has been removed from + // the bootclasspath the package explicitly requests it. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed() + .hideAsFinal(); + + // No change is required because the package explicitly requests org.apache.http.legacy + // and is targeted at the current version so does not need backwards compatibility. + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, OrgApacheHttpLegacyUpdater::new); + } +} diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java index ad9814bd01b1..00d468de4ee4 100644 --- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java +++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageBackwardCompatibilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2019 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. @@ -14,15 +14,18 @@ * limitations under the License. */ -package android.content.pm; +package android.content.pm.parsing.library; -import static android.content.pm.PackageBuilder.builder; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK; -import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; -import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK; +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; -import android.content.pm.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; import android.os.Build; import androidx.test.filters.SmallTest; @@ -32,17 +35,20 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.util.ArrayList; -import java.util.List; - @SmallTest @RunWith(JUnit4.class) public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdaterTest { @Test public void null_usesLibraries_and_usesOptionalLibraries() { - PackageBuilder before = builder(); - PackageBuilder after = builder(); + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); checkBackwardsCompatibility(before, after); } @@ -68,20 +74,21 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate */ @Test public void targeted_at_O() { - PackageBuilder before = builder() - .targetSdkVersion(Build.VERSION_CODES.O); + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed(); + + ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .setTargetSdkVersion(Build.VERSION_CODES.O); - List<String> expected = new ArrayList<>(); if (!PackageBackwardCompatibility.bootClassPathContainsATB()) { - expected.add(ANDROID_TEST_BASE); + after.addUsesLibrary(ANDROID_TEST_BASE); } - expected.add(ORG_APACHE_HTTP_LEGACY); - - PackageBuilder after = builder() - .targetSdkVersion(Build.VERSION_CODES.O) - .requiredLibraries(expected); + after.addUsesLibrary(ORG_APACHE_HTTP_LEGACY); - checkBackwardsCompatibility(before, after); + checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal()); } /** @@ -98,12 +105,17 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate + ANDROID_TEST_BASE + " is on the bootclasspath", PackageBackwardCompatibility.bootClassPathContainsATB()); - PackageBuilder before = builder() - .requiredLibraries(ANDROID_TEST_BASE); + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); // android.test.base should be removed from the libraries because it is provided // on the bootclasspath and providing both increases start up cost unnecessarily. - PackageBuilder after = builder(); + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); checkBackwardsCompatibility(before, after); } @@ -117,22 +129,23 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate */ @Test public void android_test_runner_in_usesLibraries() { - PackageBuilder before = builder().requiredLibraries(ANDROID_TEST_RUNNER); + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_RUNNER) + .hideAsParsed(); - List<String> expected = new ArrayList<>(); + ParsingPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT); if (!PackageBackwardCompatibility.bootClassPathContainsATB()) { - expected.add(ANDROID_TEST_BASE); + after.addUsesLibrary(ANDROID_TEST_BASE); } - expected.add(ANDROID_TEST_MOCK); - expected.add(ANDROID_TEST_RUNNER); - - PackageBuilder after = builder() - .requiredLibraries(expected); + after.addUsesLibrary(ANDROID_TEST_MOCK); + after.addUsesLibrary(ANDROID_TEST_RUNNER); - checkBackwardsCompatibility(before, after); + checkBackwardsCompatibility(before, after.hideAsParsed().hideAsFinal()); } - private void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after) { + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance); } } diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java new file mode 100644 index 000000000000..e7a80e1a7618 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/PackageSharedLibraryUpdaterTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 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.parsing.library; + +import static org.junit.Assert.assertEquals; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; + +import java.util.function.Supplier; + +/** + * Helper for classes that test {@link PackageSharedLibraryUpdater}. + */ +abstract class PackageSharedLibraryUpdaterTest { + + protected static final String PACKAGE_NAME = "org.package.name"; + + static void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after, + Supplier<PackageSharedLibraryUpdater> updaterSupplier) { + updaterSupplier.get().updatePackage(before); + check(before.hideAsFinal(), after); + } + + private static void check(AndroidPackage before, AndroidPackage after) { + assertEquals("targetSdkVersion should not be changed", + after.getTargetSdkVersion(), + before.getTargetSdkVersion()); + assertEquals("usesLibraries not updated correctly", + after.getUsesLibraries(), + before.getUsesLibraries()); + assertEquals("usesOptionalLibraries not updated correctly", + after.getUsesOptionalLibraries(), + before.getUsesOptionalLibraries()); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java new file mode 100644 index 000000000000..fd3ba2bd0c68 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2019 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.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link RemoveUnnecessaryAndroidTestBaseLibrary} + */ +@SmallTest +@RunWith(JUnit4.class) +public class RemoveUnnecessaryAndroidTestBaseLibraryTest + extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_O() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + // No change required. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + // No change required. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .addUsesLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_bothLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ANDROID_TEST_BASE) + .addUsesOptionalLibrary(ANDROID_TEST_BASE) + .hideAsParsed(); + + // android.test.base should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + // TODO(b/72538146) - Cannot use constructor reference here because it is also used in + // PackageBackwardCompatibility and that seems to create a package-private lambda in + // android.content.pm which this then tries to reuse but fails because it cannot access + // package-private classes/members because the test is loaded by a different ClassLoader + // than the lambda. + checkBackwardsCompatibility(before, after, + () -> new RemoveUnnecessaryAndroidTestBaseLibrary()); + } + +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java new file mode 100644 index 000000000000..d3494d93ae52 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2019 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.parsing.library; + +import static android.content.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; + +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Test for {@link RemoveUnnecessaryOrgApacheHttpLegacyLibrary} + */ +@SmallTest +@RunWith(JUnit4.class) +public class RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest + extends PackageSharedLibraryUpdaterTest { + + private static final String OTHER_LIBRARY = "other.library"; + + @Test + public void targeted_at_O() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + // No change required. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_not_empty_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed(); + + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(OTHER_LIBRARY) + .hideAsParsed() + .hideAsFinal(); + + // No change required. + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void targeted_at_O_in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.O) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_usesOptionalLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void in_bothLibraries() { + ParsedPackage before = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .addUsesLibrary(ORG_APACHE_HTTP_LEGACY) + .addUsesOptionalLibrary(ORG_APACHE_HTTP_LEGACY) + .hideAsParsed(); + + // org.apache.http.legacy should be removed from the libraries because it is provided + // on the bootclasspath and providing both increases start up cost unnecessarily. + AndroidPackage after = PackageImpl.forParsing(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT) + .hideAsParsed() + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + // TODO(b/72538146) - Cannot use constructor reference here because it is also used in + // PackageBackwardCompatibility and that seems to create a package-private lambda in + // android.content.pm which this then tries to reuse but fails because it cannot access + // package-private classes/members because the test is loaded by a different ClassLoader + // than the lambda. + checkBackwardsCompatibility(before, after, + () -> new RemoveUnnecessaryOrgApacheHttpLegacyLibrary()); + } +} diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index f32935fa300f..2dfb777592fd 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1,11 +1,11 @@ { "version": "1.0.0", "messages": { - "594230385": { + "676824470": { "message": "Test completed successfully: %b %d %o %x %e %g %f %% %s.", "level": "ERROR", "group": "TEST_GROUP", - "at": "com\/android\/server\/wm\/ProtoLogGroup.java:94" + "at": "com\/android\/server\/wm\/ProtoLogGroup.java" } }, "groups": { diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 072beae8baf7..c6920977f6b9 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -323,14 +323,16 @@ <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font> </family> <family lang="und-Mymr" variant="elegant"> - <font weight="400" style="normal">NotoSansMyanmar-Regular-ZawDecode.ttf</font> - <font weight="700" style="normal">NotoSansMyanmar-Bold-ZawDecode.ttf</font> + <font weight="400" style="normal">NotoSansMyanmar-Regular.otf</font> + <font weight="500" style="normal">NotoSansMyanmar-Medium.otf</font> + <font weight="700" style="normal">NotoSansMyanmar-Bold.otf</font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifMyanmar-Regular.otf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifMyanmar-Bold.otf</font> </family> <family lang="und-Mymr" variant="compact"> - <font weight="400" style="normal">NotoSansMyanmarUI-Regular-ZawDecode.ttf</font> - <font weight="700" style="normal">NotoSansMyanmarUI-Bold-ZawDecode.ttf</font> + <font weight="400" style="normal">NotoSansMyanmarUI-Regular.otf</font> + <font weight="500" style="normal">NotoSansMyanmarUI-Medium.otf</font> + <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font> </family> <family lang="und-Thaa"> <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font> diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 01caf011f644..eec49df79630 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -224,6 +224,62 @@ const std::unordered_map<std::string, std::string>* return &loaded_package->GetOverlayableMap(); } +bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_name, + std::string* out) const { + uint8_t package_id = 0U; + for (const auto& apk_assets : apk_assets_) { + const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc(); + if (loaded_arsc == nullptr) { + continue; + } + + const auto& loaded_packages = loaded_arsc->GetPackages(); + if (loaded_packages.empty()) { + continue; + } + + const auto& loaded_package = loaded_packages[0]; + if (loaded_package->GetPackageName() == package_name) { + package_id = GetAssignedPackageId(loaded_package.get()); + break; + } + } + + if (package_id == 0U) { + ANDROID_LOG(ERROR) << base::StringPrintf("No package with name '%s", package_name.data()); + return false; + } + + const size_t idx = package_ids_[package_id]; + if (idx == 0xff) { + return false; + } + + std::string output; + for (const ConfiguredPackage& package : package_groups_[idx].packages_) { + const LoadedPackage* loaded_package = package.loaded_package_; + for (auto it = loaded_package->begin(); it != loaded_package->end(); it++) { + const OverlayableInfo* info = loaded_package->GetOverlayableInfo(*it); + if (info != nullptr) { + ResourceName res_name; + if (!GetResourceName(*it, &res_name)) { + ANDROID_LOG(ERROR) << base::StringPrintf( + "Unable to retrieve name of overlayable resource 0x%08x", *it); + return false; + } + + const std::string name = ToFormattedResourceString(&res_name); + output.append(base::StringPrintf( + "resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n", + name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags)); + } + } + } + + *out = std::move(output); + return true; +} + void AssetManager2::SetConfiguration(const ResTable_config& configuration) { const int diff = configuration_.diff(configuration); configuration_ = configuration; @@ -1073,7 +1129,7 @@ void AssetManager2::InvalidateCaches(uint32_t diff) { } } -uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) { +uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const { for (auto& package_group : package_groups_) { for (auto& package2 : package_group.packages_) { if (package2.loaded_package_ == package) { diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 1e2b36cb1703..de46081a6aa3 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -124,6 +124,10 @@ class AssetManager2 { // This may be nullptr if the APK represented by `cookie` has no resource table. const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const; + // Returns a string representation of the overlayable API of a package. + bool GetOverlayablesToString(const android::StringPiece& package_name, + std::string* out) const; + const std::unordered_map<std::string, std::string>* GetOverlayableMapForPackage(uint32_t package_id) const; @@ -308,7 +312,7 @@ class AssetManager2 { const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids); // Retrieve the assigned package id of the package if loaded into this AssetManager - uint8_t GetAssignedPackageId(const LoadedPackage* package); + uint8_t GetAssignedPackageId(const LoadedPackage* package) const; // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must // have a longer lifetime. diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index 40c8e46e4d84..15910241518d 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -707,7 +707,7 @@ TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) { EXPECT_EQ("", resultDisabled); } -TEST_F(AssetManager2Test, GetOverlayableMap) { +TEST_F(AssetManager2Test, GetOverlayablesToString) { ResTable_config desired_config; memset(&desired_config, 0, sizeof(desired_config)); @@ -721,6 +721,12 @@ TEST_F(AssetManager2Test, GetOverlayableMap) { ASSERT_EQ(2, map->size()); ASSERT_EQ(map->at("OverlayableResources1"), "overlay://theme"); ASSERT_EQ(map->at("OverlayableResources2"), "overlay://com.android.overlayable"); + + std::string api; + ASSERT_TRUE(assetmanager.GetOverlayablesToString("com.android.overlayable", &api)); + ASSERT_EQ(api.find("not_overlayable"), std::string::npos); + ASSERT_NE(api.find("resource='com.android.overlayable:string/overlayable2' overlayable='OverlayableResources1' actor='overlay://theme' policy='0x0000000a'\n"), + std::string::npos); } } // namespace android diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 16f2917f8df8..6bb896fd7b29 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -20,11 +20,11 @@ cc_library_shared { ], shared_libs: [ + "libandroid_runtime", "libbinder", "libcutils", "liblog", "libutils", - "libhwui", "libgui", "libui", "libinput", diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index abf083789c23..e4348f2a9b21 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -24,12 +24,6 @@ #include <log/log.h> -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColor.h> -#include <SkPaint.h> -#include <SkBlendMode.h> - namespace android { // --- WeakLooperCallback --- diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp index fd386e9f7a8a..804644c230b9 100644 --- a/libs/input/SpriteController.cpp +++ b/libs/input/SpriteController.cpp @@ -23,11 +23,9 @@ #include <utils/String8.h> #include <gui/Surface.h> -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColor.h> -#include <SkPaint.h> - +#include <android/graphics/bitmap.h> +#include <android/graphics/canvas.h> +#include <android/graphics/paint.h> #include <android/native_window.h> namespace android { @@ -132,8 +130,8 @@ void SpriteController::doUpdateSprites() { SpriteUpdate& update = updates.editItemAt(i); if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { - update.state.surfaceWidth = update.state.icon.bitmap.width(); - update.state.surfaceHeight = update.state.icon.bitmap.height(); + update.state.surfaceWidth = update.state.icon.bitmap.getInfo().width; + update.state.surfaceHeight = update.state.icon.bitmap.getInfo().height; update.state.surfaceDrawn = false; update.state.surfaceVisible = false; update.state.surfaceControl = obtainSurface( @@ -154,8 +152,8 @@ void SpriteController::doUpdateSprites() { } if (update.state.wantSurfaceVisible()) { - int32_t desiredWidth = update.state.icon.bitmap.width(); - int32_t desiredHeight = update.state.icon.bitmap.height(); + int32_t desiredWidth = update.state.icon.bitmap.getInfo().width; + int32_t desiredHeight = update.state.icon.bitmap.getInfo().height; if (update.state.surfaceWidth < desiredWidth || update.state.surfaceHeight < desiredHeight) { needApplyTransaction = true; @@ -201,26 +199,22 @@ void SpriteController::doUpdateSprites() { if (status) { ALOGE("Error %d locking sprite surface before drawing.", status); } else { - SkBitmap surfaceBitmap; - ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); - surfaceBitmap.installPixels(SkImageInfo::MakeN32Premul(outBuffer.width, outBuffer.height), - outBuffer.bits, bpr); + graphics::Paint paint; + paint.setBlendMode(ABLEND_MODE_SRC); - SkCanvas surfaceCanvas(surfaceBitmap); + graphics::Canvas canvas(outBuffer, (int32_t) surface->getBuffersDataSpace()); + canvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); - surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); + const int iconWidth = update.state.icon.bitmap.getInfo().width; + const int iconHeight = update.state.icon.bitmap.getInfo().height; - if (outBuffer.width > update.state.icon.bitmap.width()) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRect(SkRect::MakeLTRB(update.state.icon.bitmap.width(), 0, - outBuffer.width, update.state.icon.bitmap.height()), paint); + if (outBuffer.width > iconWidth) { + paint.setBlendMode(ABLEND_MODE_CLEAR); // clear to transparent + canvas.drawRect({iconWidth, 0, outBuffer.width, iconHeight}, paint); } - if (outBuffer.height > update.state.icon.bitmap.height()) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRect(SkRect::MakeLTRB(0, update.state.icon.bitmap.height(), - outBuffer.width, outBuffer.height), paint); + if (outBuffer.height > iconHeight) { + paint.setBlendMode(ABLEND_MODE_CLEAR); // clear to transparent + canvas.drawRect({0, iconHeight, outBuffer.width, outBuffer.height}, paint); } status = surface->unlockAndPost(); @@ -398,12 +392,7 @@ void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { uint32_t dirty; if (icon.isValid()) { - SkBitmap* bitmapCopy = &mLocked.state.icon.bitmap; - if (bitmapCopy->tryAllocPixels(icon.bitmap.info().makeColorType(kN32_SkColorType))) { - icon.bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(), - bitmapCopy->rowBytes(), 0, 0); - } - + mLocked.state.icon.bitmap = icon.bitmap.copy(ANDROID_BITMAP_FORMAT_RGBA_8888); if (!mLocked.state.icon.isValid() || mLocked.state.icon.hotSpotX != icon.hotSpotX || mLocked.state.icon.hotSpotY != icon.hotSpotY) { diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h index 79a904f5fe65..2513544d4bdf 100644 --- a/libs/input/SpriteController.h +++ b/libs/input/SpriteController.h @@ -20,10 +20,9 @@ #include <utils/RefBase.h> #include <utils/Looper.h> +#include <android/graphics/bitmap.h> #include <gui/SurfaceComposerClient.h> -#include <SkBitmap.h> - namespace android { /* @@ -56,21 +55,16 @@ struct SpriteTransformationMatrix { */ struct SpriteIcon { inline SpriteIcon() : style(0), hotSpotX(0), hotSpotY(0) { } - inline SpriteIcon(const SkBitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) : + inline SpriteIcon(const graphics::Bitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) : bitmap(bitmap), style(style), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } - SkBitmap bitmap; + graphics::Bitmap bitmap; int32_t style; float hotSpotX; float hotSpotY; inline SpriteIcon copy() const { - SkBitmap bitmapCopy; - if (bitmapCopy.tryAllocPixels(bitmap.info().makeColorType(kN32_SkColorType))) { - bitmap.readPixels(bitmapCopy.info(), bitmapCopy.getPixels(), bitmapCopy.rowBytes(), - 0, 0); - } - return SpriteIcon(bitmapCopy, style, hotSpotX, hotSpotY); + return SpriteIcon(bitmap.copy(ANDROID_BITMAP_FORMAT_RGBA_8888), style, hotSpotX, hotSpotY); } inline void reset() { @@ -81,7 +75,7 @@ struct SpriteIcon { } inline bool isValid() const { - return !bitmap.isNull() && !bitmap.empty(); + return bitmap.isValid() && !bitmap.isEmpty(); } }; @@ -183,7 +177,7 @@ private: * This structure is designed so that it can be copied during updates so that * surfaces can be resized and redrawn without blocking the client by holding a lock * on the sprites for a long time. - * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */ + * Note that the SpriteIcon holds a reference to a shared (and immutable) bitmap. */ struct SpriteState { inline SpriteState() : dirty(0), visible(false), diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index e83b2a78d180..b1e3d6fe845a 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -18,9 +18,9 @@ cc_test { "PointerController_test.cpp", ], shared_libs: [ + "libandroid_runtime", "libinputservice", "libgui", - "libhwui", "libutils", ], static_libs: [ diff --git a/media/jni/Android.bp b/media/jni/Android.bp index 378064d63af4..6257feb2f894 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -34,6 +34,7 @@ cc_library_shared { "libutils", "libbinder", "libmedia", + "libmedia_codeclist", "libmedia_jni_utils", "libmedia_omx", "libmediametrics", diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java index ca8d5ac52021..cc46514ae96e 100644 --- a/opengl/java/android/opengl/GLUtils.java +++ b/opengl/java/android/opengl/GLUtils.java @@ -44,7 +44,7 @@ public final class GLUtils { if (bitmap.isRecycled()) { throw new IllegalArgumentException("bitmap is recycled"); } - int result = native_getInternalFormat(bitmap.getNativeInstance()); + int result = native_getInternalFormat(bitmap); if (result < 0) { throw new IllegalArgumentException("Unknown internalformat"); } @@ -66,7 +66,7 @@ public final class GLUtils { if (bitmap.isRecycled()) { throw new IllegalArgumentException("bitmap is recycled"); } - int result = native_getType(bitmap.getNativeInstance()); + int result = native_getType(bitmap); if (result < 0) { throw new IllegalArgumentException("Unknown type"); } @@ -103,8 +103,7 @@ public final class GLUtils { if (bitmap.isRecycled()) { throw new IllegalArgumentException("bitmap is recycled"); } - if (native_texImage2D(target, level, internalformat, bitmap.getNativeInstance(), -1, - border) != 0) { + if (native_texImage2D(target, level, internalformat, bitmap, -1, border) != 0) { throw new IllegalArgumentException("invalid Bitmap format"); } } @@ -130,8 +129,7 @@ public final class GLUtils { if (bitmap.isRecycled()) { throw new IllegalArgumentException("bitmap is recycled"); } - if (native_texImage2D(target, level, internalformat, bitmap.getNativeInstance(), type, - border) != 0) { + if (native_texImage2D(target, level, internalformat, bitmap, type, border) != 0) { throw new IllegalArgumentException("invalid Bitmap format"); } } @@ -153,7 +151,7 @@ public final class GLUtils { if (bitmap.isRecycled()) { throw new IllegalArgumentException("bitmap is recycled"); } - if (native_texImage2D(target, level, -1, bitmap.getNativeInstance(), -1, border) != 0) { + if (native_texImage2D(target, level, -1, bitmap, -1, border) != 0) { throw new IllegalArgumentException("invalid Bitmap format"); } } @@ -189,8 +187,7 @@ public final class GLUtils { throw new IllegalArgumentException("bitmap is recycled"); } int type = getType(bitmap); - if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap.getNativeInstance(), -1, - type) != 0) { + if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap, -1, type) != 0) { throw new IllegalArgumentException("invalid Bitmap format"); } } @@ -214,8 +211,7 @@ public final class GLUtils { if (bitmap.isRecycled()) { throw new IllegalArgumentException("bitmap is recycled"); } - if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap.getNativeInstance(), - format, type) != 0) { + if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap, format, type) != 0) { throw new IllegalArgumentException("invalid Bitmap format"); } } @@ -265,10 +261,10 @@ public final class GLUtils { } } - native private static int native_getInternalFormat(long bitmapHandle); - native private static int native_getType(long bitmapHandle); - native private static int native_texImage2D(int target, int level, int internalformat, - long bitmapHandle, int type, int border); - native private static int native_texSubImage2D(int target, int level, int xoffset, int yoffset, - long bitmapHandle, int format, int type); + private static native int native_getInternalFormat(Bitmap bitmap); + private static native int native_getType(Bitmap bitmap); + private static native int native_texImage2D(int target, int level, int internalformat, + Bitmap bitmap, int type, int border); + private static native int native_texSubImage2D(int target, int level, int xoffset, int yoffset, + Bitmap bitmap, int format, int type); } diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/FullBackupDataProcessor.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullBackupDataProcessor.java new file mode 100644 index 000000000000..f3ab2bde086a --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullBackupDataProcessor.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption; + +import android.app.backup.BackupTransport; + +import java.io.IOException; +import java.io.InputStream; + +/** Accepts the full backup data stream and sends it to the server. */ +public interface FullBackupDataProcessor { + /** + * Prepares the upload. + * + * <p>After this, call {@link #start()} to establish the connection. + * + * @param inputStream to read the backup data from, calling {@link #finish} or {@link #cancel} + * will close the stream + * @return {@code true} if the connection was set up successfully, otherwise {@code false} + */ + boolean initiate(InputStream inputStream) throws IOException; + + /** + * Starts the upload, establishing the connection to the server. + * + * <p>After this, call {@link #pushData(int)} to request that the processor reads data from the + * socket, and uploads it to the server. + * + * <p>After this you must call one of {@link #cancel()}, {@link #finish()}, {@link + * #handleCheckSizeRejectionZeroBytes()}, {@link #handleCheckSizeRejectionQuotaExceeded()} or + * {@link #handleSendBytesQuotaExceeded()} to close the upload. + */ + void start(); + + /** + * Requests that the processor read {@code numBytes} from the input stream passed in {@link + * #initiate(InputStream)} and upload them to the server. + * + * @return {@link BackupTransport#TRANSPORT_OK} if the upload succeeds, or {@link + * BackupTransport#TRANSPORT_QUOTA_EXCEEDED} if the upload exceeded the server-side app size + * quota, or {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED} for other errors. + */ + int pushData(int numBytes); + + /** Cancels the upload and tears down the connection. */ + void cancel(); + + /** + * Finish the upload and tear down the connection. + * + * <p>Call this after there is no more data to push with {@link #pushData(int)}. + * + * @return One of {@link BackupTransport#TRANSPORT_OK} if the app upload succeeds, {@link + * BackupTransport#TRANSPORT_QUOTA_EXCEEDED} if the upload exceeded the server-side app size + * quota, {@link BackupTransport#TRANSPORT_ERROR} for server 500s, or {@link + * BackupTransport#TRANSPORT_PACKAGE_REJECTED} for other errors. + */ + int finish(); + + /** + * Notifies the processor that the current upload should be terminated because the estimated + * size is zero. + */ + void handleCheckSizeRejectionZeroBytes(); + + /** + * Notifies the processor that the current upload should be terminated because the estimated + * size exceeds the quota. + */ + void handleCheckSizeRejectionQuotaExceeded(); + + /** + * Notifies this class that the current upload should be terminated because the quota was + * exceeded during upload. + */ + void handleSendBytesQuotaExceeded(); + + /** + * Attaches {@link FullBackupCallbacks} which the processor will notify when the backup + * succeeds. + */ + void attachCallbacks(FullBackupCallbacks fullBackupCallbacks); + + /** + * Implemented by the caller of the processor to receive notification of when the backup + * succeeds. + */ + interface FullBackupCallbacks { + /** The processor calls this to indicate that the current backup has succeeded. */ + void onSuccess(); + + /** The processor calls this if the upload failed for a non-transient reason. */ + void onTransferFailed(); + } +} diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDataProcessor.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDataProcessor.java new file mode 100644 index 000000000000..e4c40491bc2f --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDataProcessor.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption; + +import java.io.IOException; + +/** + * Retrieves the data during a full restore, decrypting it if necessary. + * + * <p>Use {@link FullRestoreDataProcessorFactory} to construct the encrypted or unencrypted + * processor as appropriate during restore. + */ +public interface FullRestoreDataProcessor { + /** Return value of {@link #readNextChunk} when there is no more data to download. */ + int END_OF_STREAM = -1; + + /** + * Reads the next chunk of restore data and writes it to the given buffer. + * + * <p>Where necessary, will open the connection to the server and/or decrypt the backup file. + * + * <p>The implementation may retry various errors. If the retries fail it will throw the + * relevant exception. + * + * @return the number of bytes read, or {@link #END_OF_STREAM} if there is no more data + * @throws IOException when downloading from the network or writing to disk + */ + int readNextChunk(byte[] buffer) throws IOException; + + /** + * Closes the connection to the server, deletes any temporary files and optionally sends a log + * with the given finish type. + * + * @param finishType one of {@link FullRestoreDownloader.FinishType} + */ + void finish(FullRestoreDownloader.FinishType finishType); +} diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDownloader.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDownloader.java new file mode 100644 index 000000000000..afcca79a0027 --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDownloader.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption; + +import java.io.IOException; + +/** Interface for classes which will provide backup data */ +public abstract class FullRestoreDownloader { + /** Enum to provide information on why a download finished */ + public enum FinishType { + UNKNOWN_FINISH(0), + // Finish the downloading and successfully write data to Android OS. + FINISHED(1), + // Download failed with any kind of exception. + TRANSFER_FAILURE(2), + // Download failed due to auth failure on the device. + AUTH_FAILURE(3), + // Aborted by Android Framework. + FRAMEWORK_ABORTED(4); + + private int mValue; + + FinishType(int value) { + mValue = value; + } + } + + /** Get the next data chunk from the backing store */ + public abstract int readNextChunk(byte[] buffer) throws IOException; + + /** Called when we've finished restoring the data */ + public abstract void finish(FinishType finishType); +} diff --git a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java index 71a0e5e51b71..91b292666756 100644 --- a/core/tests/coretests/src/android/content/pm/PackageSharedLibraryUpdaterTest.java +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 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. @@ -14,19 +14,23 @@ * limitations under the License. */ -package android.content.pm; +package com.android.server.backup.encryption; -import java.util.function.Supplier; +import java.io.Closeable; +import java.io.IOException; -/** - * Helper for classes that test {@link PackageSharedLibraryUpdater}. - */ -abstract class PackageSharedLibraryUpdaterTest { - - static void checkBackwardsCompatibility(PackageBuilder before, PackageBuilder after, - Supplier<PackageSharedLibraryUpdater> updaterSupplier) { - PackageParser.Package pkg = before.build(); - updaterSupplier.get().updatePackage(pkg); - after.check(pkg); +/** Utility methods for dealing with Streams */ +public class StreamUtils { + /** + * Close a Closeable and silently ignore any IOExceptions. + * + * @param closeable The closeable to close + */ + public static void closeQuietly(Closeable closeable) { + try { + closeable.close(); + } catch (IOException ioe) { + // Silently ignore + } } } diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTask.java new file mode 100644 index 000000000000..9bf148ddc901 --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTask.java @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +import android.util.Slog; +import android.util.SparseIntArray; + +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunkOrdering; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunksMetadata; + +import com.google.protobuf.nano.InvalidProtocolBufferNanoException; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Locale; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.GCMParameterSpec; + +/** + * A backup file consists of, in order: + * + * <ul> + * <li>A randomly ordered sequence of encrypted chunks + * <li>A plaintext {@link ChunksMetadata} proto, containing the bytes of an encrypted {@link + * ChunkOrdering} proto. + * <li>A 64-bit long denoting the offset of the file at which the ChunkOrdering proto starts. + * </ul> + * + * <p>This task decrypts such a blob and writes the plaintext to another file. + * + * <p>The backup file has two formats to indicate the boundaries of the chunks in the encrypted + * file. In {@link ChunksMetadataProto#EXPLICIT_STARTS} mode the chunk ordering contains the start + * positions of each chunk and the decryptor outputs the chunks in the order they appeared in the + * plaintext file. In {@link ChunksMetadataProto#INLINE_LENGTHS} mode the length of each encrypted + * chunk is prepended to the chunk in the file and the decryptor outputs the chunks in no specific + * order. + * + * <p>{@link ChunksMetadataProto#EXPLICIT_STARTS} is for use with full backup (Currently used for + * all backups as b/77188289 is not implemented yet), {@link ChunksMetadataProto#INLINE_LENGTHS} + * will be used for kv backup (once b/77188289 is implemented) to avoid re-uploading the chunk + * ordering (see b/70782620). + */ +public class BackupFileDecryptorTask { + private static final String TAG = "BackupFileDecryptorTask"; + + private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + private static final int GCM_NONCE_LENGTH_BYTES = 12; + private static final int GCM_TAG_LENGTH_BYTES = 16; + private static final int BITS_PER_BYTE = 8; + private static final String READ_MODE = "r"; + private static final int BYTES_PER_LONG = 64 / BITS_PER_BYTE; + + private final Cipher mCipher; + private final SecretKey mSecretKey; + + /** + * A new instance. + * + * @param secretKey The tertiary key used to encrypt the backup blob. + */ + public BackupFileDecryptorTask(SecretKey secretKey) + throws NoSuchPaddingException, NoSuchAlgorithmException { + this.mCipher = Cipher.getInstance(CIPHER_ALGORITHM); + this.mSecretKey = secretKey; + } + + /** + * Runs the task, reading the encrypted data from {@code input} and writing the plaintext data + * to {@code output}. + * + * @param inputFile The encrypted backup file. + * @param decryptedChunkOutput Unopened output to write the plaintext to, which this class will + * open and close during decryption. + * @throws IOException if an error occurred reading the encrypted file or writing the plaintext, + * or if one of the protos could not be deserialized. + */ + public void decryptFile(File inputFile, DecryptedChunkOutput decryptedChunkOutput) + throws IOException, EncryptedRestoreException, IllegalBlockSizeException, + BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, + ShortBufferException, NoSuchAlgorithmException { + RandomAccessFile input = new RandomAccessFile(inputFile, READ_MODE); + + long metadataOffset = getChunksMetadataOffset(input); + ChunksMetadataProto.ChunksMetadata chunksMetadata = + getChunksMetadata(input, metadataOffset); + ChunkOrdering chunkOrdering = decryptChunkOrdering(chunksMetadata); + + if (chunksMetadata.chunkOrderingType == ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED + || chunksMetadata.chunkOrderingType == ChunksMetadataProto.EXPLICIT_STARTS) { + Slog.d(TAG, "Using explicit starts"); + decryptFileWithExplicitStarts( + input, decryptedChunkOutput, chunkOrdering, metadataOffset); + + } else if (chunksMetadata.chunkOrderingType == ChunksMetadataProto.INLINE_LENGTHS) { + Slog.d(TAG, "Using inline lengths"); + decryptFileWithInlineLengths(input, decryptedChunkOutput, metadataOffset); + + } else { + throw new UnsupportedEncryptedFileException( + "Unknown chunk ordering type:" + chunksMetadata.chunkOrderingType); + } + + if (!Arrays.equals(decryptedChunkOutput.getDigest(), chunkOrdering.checksum)) { + throw new MessageDigestMismatchException("Checksums did not match"); + } + } + + private void decryptFileWithExplicitStarts( + RandomAccessFile input, + DecryptedChunkOutput decryptedChunkOutput, + ChunkOrdering chunkOrdering, + long metadataOffset) + throws IOException, InvalidKeyException, IllegalBlockSizeException, + InvalidAlgorithmParameterException, ShortBufferException, BadPaddingException, + NoSuchAlgorithmException { + SparseIntArray chunkLengthsByPosition = + getChunkLengths(chunkOrdering.starts, (int) metadataOffset); + int largestChunkLength = getLargestChunkLength(chunkLengthsByPosition); + byte[] encryptedChunkBuffer = new byte[largestChunkLength]; + // largestChunkLength is 0 if the backup file contains zero chunks e.g. 0 kv pairs. + int plaintextBufferLength = + Math.max(0, largestChunkLength - GCM_NONCE_LENGTH_BYTES - GCM_TAG_LENGTH_BYTES); + byte[] plaintextChunkBuffer = new byte[plaintextBufferLength]; + + try (DecryptedChunkOutput output = decryptedChunkOutput.open()) { + for (int start : chunkOrdering.starts) { + int length = chunkLengthsByPosition.get(start); + + input.seek(start); + input.readFully(encryptedChunkBuffer, 0, length); + int plaintextLength = + decryptChunk(encryptedChunkBuffer, length, plaintextChunkBuffer); + outputChunk(output, plaintextChunkBuffer, plaintextLength); + } + } + } + + private void decryptFileWithInlineLengths( + RandomAccessFile input, DecryptedChunkOutput decryptedChunkOutput, long metadataOffset) + throws MalformedEncryptedFileException, IOException, IllegalBlockSizeException, + BadPaddingException, InvalidAlgorithmParameterException, ShortBufferException, + InvalidKeyException, NoSuchAlgorithmException { + input.seek(0); + try (DecryptedChunkOutput output = decryptedChunkOutput.open()) { + while (input.getFilePointer() < metadataOffset) { + long start = input.getFilePointer(); + int encryptedChunkLength = input.readInt(); + + if (encryptedChunkLength <= 0) { + // If the length of the encrypted chunk is not positive we will not make + // progress reading the file and so will loop forever. + throw new MalformedEncryptedFileException( + "Encrypted chunk length not positive:" + encryptedChunkLength); + } + + if (start + encryptedChunkLength > metadataOffset) { + throw new MalformedEncryptedFileException( + String.format( + Locale.US, + "Encrypted chunk longer (%d) than file (%d)", + encryptedChunkLength, + metadataOffset)); + } + + byte[] plaintextChunk = new byte[encryptedChunkLength]; + byte[] plaintext = + new byte + [encryptedChunkLength + - GCM_NONCE_LENGTH_BYTES + - GCM_TAG_LENGTH_BYTES]; + + input.readFully(plaintextChunk); + + int plaintextChunkLength = + decryptChunk(plaintextChunk, encryptedChunkLength, plaintext); + outputChunk(output, plaintext, plaintextChunkLength); + } + } + } + + private void outputChunk( + DecryptedChunkOutput output, byte[] plaintextChunkBuffer, int plaintextLength) + throws IOException, InvalidKeyException, NoSuchAlgorithmException { + output.processChunk(plaintextChunkBuffer, plaintextLength); + } + + /** + * Decrypts chunk and returns the length of the plaintext. + * + * @param encryptedChunkBuffer The encrypted data, prefixed by the nonce. + * @param encryptedChunkBufferLength The length of the encrypted chunk (including nonce). + * @param plaintextChunkBuffer The buffer into which to write the plaintext chunk. + * @return The length of the plaintext chunk. + */ + private int decryptChunk( + byte[] encryptedChunkBuffer, + int encryptedChunkBufferLength, + byte[] plaintextChunkBuffer) + throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, + ShortBufferException, IllegalBlockSizeException { + + mCipher.init( + Cipher.DECRYPT_MODE, + mSecretKey, + new GCMParameterSpec( + GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE, + encryptedChunkBuffer, + 0, + GCM_NONCE_LENGTH_BYTES)); + + return mCipher.doFinal( + encryptedChunkBuffer, + GCM_NONCE_LENGTH_BYTES, + encryptedChunkBufferLength - GCM_NONCE_LENGTH_BYTES, + plaintextChunkBuffer); + } + + /** Given all the lengths, returns the largest length. */ + private int getLargestChunkLength(SparseIntArray lengths) { + int maxSeen = 0; + for (int i = 0; i < lengths.size(); i++) { + maxSeen = Math.max(maxSeen, lengths.valueAt(i)); + } + return maxSeen; + } + + /** + * From a list of the starting position of each chunk in the correct order of the backup data, + * calculates a mapping from start position to length of that chunk. + * + * @param starts The start positions of chunks, in order. + * @param chunkOrderingPosition Where the {@link ChunkOrdering} proto starts, used to calculate + * the length of the last chunk. + * @return The mapping. + */ + private SparseIntArray getChunkLengths(int[] starts, int chunkOrderingPosition) { + int[] boundaries = Arrays.copyOf(starts, starts.length + 1); + boundaries[boundaries.length - 1] = chunkOrderingPosition; + Arrays.sort(boundaries); + + SparseIntArray lengths = new SparseIntArray(); + for (int i = 0; i < boundaries.length - 1; i++) { + lengths.put(boundaries[i], boundaries[i + 1] - boundaries[i]); + } + return lengths; + } + + /** + * Reads and decrypts the {@link ChunkOrdering} from the {@link ChunksMetadata}. + * + * @param metadata The metadata. + * @return The ordering. + * @throws InvalidProtocolBufferNanoException if there is an issue deserializing the proto. + */ + private ChunkOrdering decryptChunkOrdering(ChunksMetadata metadata) + throws InvalidProtocolBufferNanoException, InvalidAlgorithmParameterException, + InvalidKeyException, BadPaddingException, IllegalBlockSizeException, + UnsupportedEncryptedFileException { + assertCryptoSupported(metadata); + + mCipher.init( + Cipher.DECRYPT_MODE, + mSecretKey, + new GCMParameterSpec( + GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE, + metadata.chunkOrdering, + 0, + GCM_NONCE_LENGTH_BYTES)); + + byte[] decrypted = + mCipher.doFinal( + metadata.chunkOrdering, + GCM_NONCE_LENGTH_BYTES, + metadata.chunkOrdering.length - GCM_NONCE_LENGTH_BYTES); + + return ChunkOrdering.parseFrom(decrypted); + } + + /** + * Asserts that the Cipher and MessageDigest algorithms in the backup metadata are supported. + * For now we only support SHA-256 for checksum and 256-bit AES/GCM/NoPadding for the Cipher. + * + * @param chunksMetadata The file metadata. + * @throws UnsupportedEncryptedFileException if any algorithm is unsupported. + */ + private void assertCryptoSupported(ChunksMetadata chunksMetadata) + throws UnsupportedEncryptedFileException { + if (chunksMetadata.checksumType != ChunksMetadataProto.SHA_256) { + // For now we only support SHA-256. + throw new UnsupportedEncryptedFileException( + "Unrecognized checksum type for backup (this version of backup only supports" + + " SHA-256): " + + chunksMetadata.checksumType); + } + + if (chunksMetadata.cipherType != ChunksMetadataProto.AES_256_GCM) { + throw new UnsupportedEncryptedFileException( + "Unrecognized cipher type for backup (this version of backup only supports" + + " AES-256-GCM: " + + chunksMetadata.cipherType); + } + } + + /** + * Reads the offset of the {@link ChunksMetadata} proto from the end of the file. + * + * @return The offset. + * @throws IOException if there is an error reading. + */ + private long getChunksMetadataOffset(RandomAccessFile input) throws IOException { + input.seek(input.length() - BYTES_PER_LONG); + return input.readLong(); + } + + /** + * Reads the {@link ChunksMetadata} proto from the given position in the file. + * + * @param input The encrypted file. + * @param position The position where the proto starts. + * @return The proto. + * @throws IOException if there is an issue reading the file or deserializing the proto. + */ + private ChunksMetadata getChunksMetadata(RandomAccessFile input, long position) + throws IOException, MalformedEncryptedFileException { + long length = input.length(); + if (position >= length || position < 0) { + throw new MalformedEncryptedFileException( + String.format( + Locale.US, + "%d is not valid position for chunks metadata in file of %d bytes", + position, + length)); + } + + // Read chunk ordering bytes + input.seek(position); + long chunksMetadataLength = input.length() - BYTES_PER_LONG - position; + byte[] chunksMetadataBytes = new byte[(int) chunksMetadataLength]; + input.readFully(chunksMetadataBytes); + + try { + return ChunksMetadata.parseFrom(chunksMetadataBytes); + } catch (InvalidProtocolBufferNanoException e) { + throw new MalformedEncryptedFileException( + String.format( + Locale.US, + "Could not read chunks metadata at position %d of file of %d bytes", + position, + length)); + } + } +} diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTask.java new file mode 100644 index 000000000000..a938d715a307 --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTask.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +import android.content.Context; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.backup.encryption.StreamUtils; +import com.android.server.backup.encryption.chunking.ProtoStore; +import com.android.server.backup.encryption.chunking.cdc.FingerprintMixer; +import com.android.server.backup.encryption.client.CryptoBackupServer; +import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey; +import com.android.server.backup.encryption.keys.TertiaryKeyManager; +import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunkListing; +import com.android.server.backup.encryption.protos.nano.WrappedKeyProto; + +import java.io.IOException; +import java.io.InputStream; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Optional; +import java.util.concurrent.Callable; + +import javax.crypto.SecretKey; + +/** + * Task which reads a stream of plaintext full backup data, chunks it, encrypts it and uploads it to + * the server. + * + * <p>Once the backup completes or fails, closes the input stream. + */ +public class EncryptedFullBackupTask implements Callable<Void> { + private static final String TAG = "EncryptedFullBackupTask"; + + private static final int MIN_CHUNK_SIZE_BYTES = 2 * 1024; + private static final int MAX_CHUNK_SIZE_BYTES = 64 * 1024; + private static final int AVERAGE_CHUNK_SIZE_BYTES = 4 * 1024; + + // TODO(b/69350270): Remove this hard-coded salt and related logic once we feel confident that + // incremental backup has happened at least once for all existing packages/users since we moved + // to + // using a randomly generated salt. + // + // The hard-coded fingerprint mixer salt was used for a short time period before replaced by one + // that is randomly generated on initial non-incremental backup and stored in ChunkListing to be + // reused for succeeding incremental backups. If an old ChunkListing does not have a + // fingerprint_mixer_salt, we assume that it was last backed up before a randomly generated salt + // is used so we use the hardcoded salt and set ChunkListing#fingerprint_mixer_salt to this + // value. + // Eventually all backup ChunkListings will have this field set and then we can remove the + // default + // value in the code. + static final byte[] DEFAULT_FINGERPRINT_MIXER_SALT = + Arrays.copyOf(new byte[] {20, 23}, FingerprintMixer.SALT_LENGTH_BYTES); + + private final ProtoStore<ChunkListing> mChunkListingStore; + private final TertiaryKeyManager mTertiaryKeyManager; + private final InputStream mInputStream; + private final EncryptedBackupTask mTask; + private final String mPackageName; + private final SecureRandom mSecureRandom; + + /** Creates a new instance with the default min, max and average chunk sizes. */ + public static EncryptedFullBackupTask newInstance( + Context context, + CryptoBackupServer cryptoBackupServer, + SecureRandom secureRandom, + RecoverableKeyStoreSecondaryKey secondaryKey, + String packageName, + InputStream inputStream) + throws IOException { + EncryptedBackupTask encryptedBackupTask = + new EncryptedBackupTask( + cryptoBackupServer, + secureRandom, + packageName, + new BackupStreamEncrypter( + inputStream, + MIN_CHUNK_SIZE_BYTES, + MAX_CHUNK_SIZE_BYTES, + AVERAGE_CHUNK_SIZE_BYTES)); + TertiaryKeyManager tertiaryKeyManager = + new TertiaryKeyManager( + context, + secureRandom, + TertiaryKeyRotationScheduler.getInstance(context), + secondaryKey, + packageName); + + return new EncryptedFullBackupTask( + ProtoStore.createChunkListingStore(context), + tertiaryKeyManager, + encryptedBackupTask, + inputStream, + packageName, + new SecureRandom()); + } + + @VisibleForTesting + EncryptedFullBackupTask( + ProtoStore<ChunkListing> chunkListingStore, + TertiaryKeyManager tertiaryKeyManager, + EncryptedBackupTask task, + InputStream inputStream, + String packageName, + SecureRandom secureRandom) { + mChunkListingStore = chunkListingStore; + mTertiaryKeyManager = tertiaryKeyManager; + mInputStream = inputStream; + mTask = task; + mPackageName = packageName; + mSecureRandom = secureRandom; + } + + @Override + public Void call() throws Exception { + try { + Optional<ChunkListing> maybeOldChunkListing = + mChunkListingStore.loadProto(mPackageName); + + if (maybeOldChunkListing.isPresent()) { + Slog.i(TAG, "Found previous chunk listing for " + mPackageName); + } + + // If the key has been rotated then we must re-encrypt all of the backup data. + if (mTertiaryKeyManager.wasKeyRotated()) { + Slog.i( + TAG, + "Key was rotated or newly generated for " + + mPackageName + + ", so performing a full backup."); + maybeOldChunkListing = Optional.empty(); + mChunkListingStore.deleteProto(mPackageName); + } + + SecretKey tertiaryKey = mTertiaryKeyManager.getKey(); + WrappedKeyProto.WrappedKey wrappedTertiaryKey = mTertiaryKeyManager.getWrappedKey(); + + ChunkListing newChunkListing; + if (!maybeOldChunkListing.isPresent()) { + byte[] fingerprintMixerSalt = new byte[FingerprintMixer.SALT_LENGTH_BYTES]; + mSecureRandom.nextBytes(fingerprintMixerSalt); + newChunkListing = + mTask.performNonIncrementalBackup( + tertiaryKey, wrappedTertiaryKey, fingerprintMixerSalt); + } else { + ChunkListing oldChunkListing = maybeOldChunkListing.get(); + + if (oldChunkListing.fingerprintMixerSalt == null + || oldChunkListing.fingerprintMixerSalt.length == 0) { + oldChunkListing.fingerprintMixerSalt = DEFAULT_FINGERPRINT_MIXER_SALT; + } + + newChunkListing = + mTask.performIncrementalBackup( + tertiaryKey, wrappedTertiaryKey, oldChunkListing); + } + + mChunkListingStore.saveProto(mPackageName, newChunkListing); + Slog.v(TAG, "Saved chunk listing for " + mPackageName); + } catch (IOException e) { + Slog.e(TAG, "Storage exception, wiping state"); + mChunkListingStore.deleteProto(mPackageName); + throw e; + } finally { + StreamUtils.closeQuietly(mInputStream); + } + + return null; + } + + /** + * Signals to the task that the backup has been cancelled. If the upload has not yet started + * then the task will not upload any data to the server or save the new chunk listing. + * + * <p>You must then terminate the input stream. + */ + public void cancel() { + mTask.cancel(); + } +} diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTask.java new file mode 100644 index 000000000000..04381af561b2 --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTask.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +import static com.android.internal.util.Preconditions.checkArgument; + +import android.annotation.Nullable; +import android.content.Context; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.backup.encryption.FullRestoreDataProcessor; +import com.android.server.backup.encryption.FullRestoreDownloader; +import com.android.server.backup.encryption.StreamUtils; +import com.android.server.backup.encryption.chunking.DecryptedChunkFileOutput; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; + +/** Downloads the encrypted backup file, decrypts it and passes the data to backup manager. */ +public class EncryptedFullRestoreTask implements FullRestoreDataProcessor { + private static final String DEFAULT_TEMPORARY_FOLDER = "encrypted_restore_temp"; + private static final String ENCRYPTED_FILE_NAME = "encrypted_restore"; + private static final String DECRYPTED_FILE_NAME = "decrypted_restore"; + + private final FullRestoreToFileTask mFullRestoreToFileTask; + private final BackupFileDecryptorTask mBackupFileDecryptorTask; + private final File mEncryptedFile; + private final File mDecryptedFile; + @Nullable private InputStream mDecryptedFileInputStream; + + /** + * Creates a new task which stores temporary files in the files directory. + * + * @param fullRestoreDownloader which will download the backup file + * @param tertiaryKey which the backup file is encrypted with + */ + public static EncryptedFullRestoreTask newInstance( + Context context, FullRestoreDownloader fullRestoreDownloader, SecretKey tertiaryKey) + throws NoSuchAlgorithmException, NoSuchPaddingException { + File temporaryFolder = new File(context.getFilesDir(), DEFAULT_TEMPORARY_FOLDER); + temporaryFolder.mkdirs(); + return new EncryptedFullRestoreTask( + temporaryFolder, fullRestoreDownloader, new BackupFileDecryptorTask(tertiaryKey)); + } + + @VisibleForTesting + EncryptedFullRestoreTask( + File temporaryFolder, + FullRestoreDownloader fullRestoreDownloader, + BackupFileDecryptorTask backupFileDecryptorTask) { + checkArgument(temporaryFolder.isDirectory(), "Temporary folder must be existing directory"); + + mEncryptedFile = new File(temporaryFolder, ENCRYPTED_FILE_NAME); + mDecryptedFile = new File(temporaryFolder, DECRYPTED_FILE_NAME); + + mFullRestoreToFileTask = new FullRestoreToFileTask(fullRestoreDownloader); + mBackupFileDecryptorTask = backupFileDecryptorTask; + } + + /** + * Reads the next decrypted bytes into the given buffer. + * + * <p>During the first call this method will download the backup file from the server, decrypt + * it and save it to disk. It will then read the bytes from the file on disk. + * + * <p>Once this method has read all the bytes of the file, the caller must call {@link #finish} + * to clean up. + * + * @return the number of bytes read, or {@code -1} on reaching the end of the file + */ + @Override + public int readNextChunk(byte[] buffer) throws IOException { + if (mDecryptedFileInputStream == null) { + try { + mDecryptedFileInputStream = downloadAndDecryptBackup(); + } catch (BadPaddingException + | InvalidKeyException + | NoSuchAlgorithmException + | IllegalBlockSizeException + | ShortBufferException + | EncryptedRestoreException + | InvalidAlgorithmParameterException e) { + throw new IOException("Encryption issue", e); + } + } + + return mDecryptedFileInputStream.read(buffer); + } + + private InputStream downloadAndDecryptBackup() + throws IOException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException, + IllegalBlockSizeException, ShortBufferException, EncryptedRestoreException, + InvalidAlgorithmParameterException { + mFullRestoreToFileTask.restoreToFile(mEncryptedFile); + mBackupFileDecryptorTask.decryptFile( + mEncryptedFile, new DecryptedChunkFileOutput(mDecryptedFile)); + mEncryptedFile.delete(); + return new BufferedInputStream(new FileInputStream(mDecryptedFile)); + } + + /** Cleans up temporary files. */ + @Override + public void finish(FullRestoreDownloader.FinishType unusedFinishType) { + // The download is finished and log sent during RestoreToFileTask#restoreToFile(), so we + // don't need to do either of those things here. + + StreamUtils.closeQuietly(mDecryptedFileInputStream); + mEncryptedFile.delete(); + mDecryptedFile.delete(); + } +} diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTask.java new file mode 100644 index 000000000000..82f83f9b7494 --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTask.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +import static com.android.internal.util.Preconditions.checkArgument; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.backup.encryption.FullRestoreDownloader; +import com.android.server.backup.encryption.FullRestoreDownloader.FinishType; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Reads a stream from a {@link FullRestoreDownloader} and writes it to a file for consumption by + * {@link BackupFileDecryptorTask}. + */ +public class FullRestoreToFileTask { + /** + * Maximum number of bytes which the framework can request from the full restore data stream in + * one call to {@link BackupTransport#getNextFullRestoreDataChunk}. + */ + public static final int MAX_BYTES_FULL_RESTORE_CHUNK = 1024 * 32; + + /** Returned when the end of a backup stream has been reached. */ + private static final int END_OF_STREAM = -1; + + private final FullRestoreDownloader mFullRestoreDownloader; + private final int mBufferSize; + + /** + * Constructs a new instance which reads from the given package wrapper, using a buffer of size + * {@link #MAX_BYTES_FULL_RESTORE_CHUNK}. + */ + public FullRestoreToFileTask(FullRestoreDownloader fullRestoreDownloader) { + this(fullRestoreDownloader, MAX_BYTES_FULL_RESTORE_CHUNK); + } + + @VisibleForTesting + FullRestoreToFileTask(FullRestoreDownloader fullRestoreDownloader, int bufferSize) { + checkArgument(bufferSize > 0, "Buffer must have positive size"); + + this.mFullRestoreDownloader = fullRestoreDownloader; + this.mBufferSize = bufferSize; + } + + /** + * Downloads the backup file from the server and writes it to the given file. + * + * <p>At the end of the download (success or failure), closes the connection and sends a + * Clearcut log. + */ + public void restoreToFile(File targetFile) throws IOException { + try (BufferedOutputStream outputStream = + new BufferedOutputStream(new FileOutputStream(targetFile))) { + byte[] buffer = new byte[mBufferSize]; + int bytesRead = mFullRestoreDownloader.readNextChunk(buffer); + while (bytesRead != END_OF_STREAM) { + outputStream.write(buffer, /* off=*/ 0, bytesRead); + bytesRead = mFullRestoreDownloader.readNextChunk(buffer); + } + + outputStream.flush(); + + mFullRestoreDownloader.finish(FinishType.FINISHED); + } catch (IOException e) { + mFullRestoreDownloader.finish(FinishType.TRANSFER_FAILURE); + throw e; + } + } +} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MalformedEncryptedFileException.java index b330e75308f9..78c370b0d548 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MalformedEncryptedFileException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 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. @@ -12,19 +12,13 @@ * 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 com.android.frameworks.coretests; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -public class TestService extends Service { +package com.android.server.backup.encryption.tasks; - @Override - public IBinder onBind(Intent intent) { - return null; +/** Exception thrown when we cannot parse the encrypted backup file. */ +public class MalformedEncryptedFileException extends EncryptedRestoreException { + public MalformedEncryptedFileException(String message) { + super(message); } } diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MessageDigestMismatchException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MessageDigestMismatchException.java new file mode 100644 index 000000000000..1e4f43b43e26 --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MessageDigestMismatchException.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +/** + * Error thrown if the message digest of the plaintext backup does not match that in the {@link + * com.android.server.backup.encryption.protos.ChunksMetadataProto.ChunkOrdering}. + */ +public class MessageDigestMismatchException extends EncryptedRestoreException { + public MessageDigestMismatchException(String message) { + super(message); + } +} diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/SizeQuotaExceededException.java index 1e721aa8ae5b..515db86b6687 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/SizeQuotaExceededException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 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. @@ -12,19 +12,13 @@ * 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 com.android.frameworks.coretests; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -public class SecondChildTestService extends Service { +package com.android.server.backup.encryption.tasks; - @Override - public IBinder onBind(Intent intent) { - return null; +/** Exception thrown when aa backup has exceeded the space allowed for that user */ +public class SizeQuotaExceededException extends RuntimeException { + public SizeQuotaExceededException() { + super("Backup size quota exceeded."); } } diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/UnsupportedEncryptedFileException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/UnsupportedEncryptedFileException.java new file mode 100644 index 000000000000..9a97e3870d83 --- /dev/null +++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/UnsupportedEncryptedFileException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +/** + * Thrown when the backup file provided by the server uses encryption algorithms this version of + * backup does not support. This could happen if the backup was created with a newer version of the + * code. + */ +public class UnsupportedEncryptedFileException extends EncryptedRestoreException { + public UnsupportedEncryptedFileException(String message) { + super(message); + } +} diff --git a/packages/BackupEncryption/test/robolectric-integration/Android.bp b/packages/BackupEncryption/test/robolectric-integration/Android.bp new file mode 100644 index 000000000000..f696278ab967 --- /dev/null +++ b/packages/BackupEncryption/test/robolectric-integration/Android.bp @@ -0,0 +1,33 @@ +// Copyright (C) 2019 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. + +android_robolectric_test { + name: "BackupEncryptionRoboIntegTests", + srcs: [ + "src/**/*.java", + ], + java_resource_dirs: ["config"], + libs: [ + "backup-encryption-protos", + "platform-test-annotations", + "testng", + "truth-prebuilt", + ], + static_libs: [ + "androidx.test.core", + "androidx.test.runner", + "androidx.test.rules", + ], + instrumentation_for: "BackupEncryption", +} diff --git a/packages/BackupEncryption/test/robolectric-integration/AndroidManifest.xml b/packages/BackupEncryption/test/robolectric-integration/AndroidManifest.xml new file mode 100644 index 000000000000..c3930cc7c4f1 --- /dev/null +++ b/packages/BackupEncryption/test/robolectric-integration/AndroidManifest.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + coreApp="true" + package="com.android.server.backup.encryption.robointeg"> + + <application/> + +</manifest> diff --git a/packages/BackupEncryption/test/robolectric-integration/config/robolectric.properties b/packages/BackupEncryption/test/robolectric-integration/config/robolectric.properties new file mode 100644 index 000000000000..26fceb3f84a4 --- /dev/null +++ b/packages/BackupEncryption/test/robolectric-integration/config/robolectric.properties @@ -0,0 +1,17 @@ +# +# Copyright (C) 2019 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. +# + +sdk=NEWEST_SDK diff --git a/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java b/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java new file mode 100644 index 000000000000..8ec68fdf822d --- /dev/null +++ b/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.server.backup.encryption.client.CryptoBackupServer; +import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey; +import com.android.server.backup.encryption.keys.TertiaryKeyManager; +import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler; +import com.android.server.backup.encryption.protos.nano.WrappedKeyProto; +import com.android.server.backup.encryption.tasks.EncryptedFullBackupTask; +import com.android.server.backup.encryption.tasks.EncryptedFullRestoreTask; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; + +@RunWith(RobolectricTestRunner.class) +public class RoundTripTest { + /** Amount of data we want to round trip in this test */ + private static final int TEST_DATA_SIZE = 1024 * 1024; // 1MB + + /** Buffer size used when reading data from the restore task */ + private static final int READ_BUFFER_SIZE = 1024; // 1024 byte buffer. + + /** Key parameters used for the secondary encryption key */ + private static final String KEY_ALGORITHM = "AES"; + private static final int KEY_SIZE_BITS = 256; + + /** Package name for our test package */ + private static final String TEST_PACKAGE_NAME = "com.android.backup.test"; + + /** The name we use to refer to our secondary key */ + private static final String TEST_KEY_ALIAS = "test/backup/KEY_ALIAS"; + + /** Original data used for comparison after round trip */ + private final byte[] mOriginalData = new byte[TEST_DATA_SIZE]; + + /** App context, used to store the key data and chunk listings */ + private Context mContext; + + /** The secondary key we're using for the test */ + private RecoverableKeyStoreSecondaryKey mSecondaryKey; + + /** Source of random material which is considered non-predictable in its' generation */ + private SecureRandom mSecureRandom = new SecureRandom(); + + @Before + public void setUp() throws NoSuchAlgorithmException { + mContext = ApplicationProvider.getApplicationContext(); + mSecondaryKey = new RecoverableKeyStoreSecondaryKey(TEST_KEY_ALIAS, generateAesKey()); + fillBuffer(mOriginalData); + } + + @Test + public void testRoundTrip() throws Exception { + byte[] backupData = performBackup(mOriginalData); + assertThat(backupData).isNotEqualTo(mOriginalData); + byte[] restoredData = performRestore(backupData); + assertThat(restoredData).isEqualTo(mOriginalData); + } + + /** Perform a backup and return the backed-up representation of the data */ + private byte[] performBackup(byte[] backupData) throws Exception { + DummyServer dummyServer = new DummyServer(); + EncryptedFullBackupTask backupTask = + EncryptedFullBackupTask.newInstance( + mContext, + dummyServer, + mSecureRandom, + mSecondaryKey, + TEST_PACKAGE_NAME, + new ByteArrayInputStream(backupData)); + backupTask.call(); + return dummyServer.mStoredData; + } + + /** Perform a restore and resturn the bytes obtained from the restore process */ + private byte[] performRestore(byte[] backupData) + throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, + InvalidAlgorithmParameterException, InvalidKeyException, + IllegalBlockSizeException { + ByteArrayOutputStream decryptedOutput = new ByteArrayOutputStream(); + + EncryptedFullRestoreTask restoreTask = + EncryptedFullRestoreTask.newInstance( + mContext, new FakeFullRestoreDownloader(backupData), getTertiaryKey()); + + byte[] buffer = new byte[READ_BUFFER_SIZE]; + int bytesRead = restoreTask.readNextChunk(buffer); + while (bytesRead != -1) { + decryptedOutput.write(buffer, 0, bytesRead); + bytesRead = restoreTask.readNextChunk(buffer); + } + + return decryptedOutput.toByteArray(); + } + + /** Get the tertiary key for our test package from the key manager */ + private SecretKey getTertiaryKey() + throws IllegalBlockSizeException, InvalidAlgorithmParameterException, + NoSuchAlgorithmException, IOException, NoSuchPaddingException, + InvalidKeyException { + TertiaryKeyManager tertiaryKeyManager = + new TertiaryKeyManager( + mContext, + mSecureRandom, + TertiaryKeyRotationScheduler.getInstance(mContext), + mSecondaryKey, + TEST_PACKAGE_NAME); + return tertiaryKeyManager.getKey(); + } + + /** Fill a buffer with data in a predictable way */ + private void fillBuffer(byte[] buffer) { + byte loopingCounter = 0; + for (int i = 0; i < buffer.length; i++) { + buffer[i] = loopingCounter; + loopingCounter++; + } + } + + /** Generate a new, random, AES key */ + public static SecretKey generateAesKey() throws NoSuchAlgorithmException { + KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM); + keyGenerator.init(KEY_SIZE_BITS); + return keyGenerator.generateKey(); + } + + /** + * Dummy backup data endpoint. This stores the data so we can use it + * in subsequent test steps. + */ + private static class DummyServer implements CryptoBackupServer { + private static final String DUMMY_DOC_ID = "DummyDoc"; + + byte[] mStoredData = null; + + @Override + public String uploadIncrementalBackup( + String packageName, + String oldDocId, + byte[] diffScript, + WrappedKeyProto.WrappedKey tertiaryKey) { + throw new RuntimeException("Not Implemented"); + } + + @Override + public String uploadNonIncrementalBackup( + String packageName, byte[] data, WrappedKeyProto.WrappedKey tertiaryKey) { + assertThat(packageName).isEqualTo(TEST_PACKAGE_NAME); + mStoredData = data; + return DUMMY_DOC_ID; + } + + @Override + public void setActiveSecondaryKeyAlias( + String keyAlias, Map<String, WrappedKeyProto.WrappedKey> tertiaryKeys) { + throw new RuntimeException("Not Implemented"); + } + } + + /** Fake package wrapper which returns data from a byte array. */ + private static class FakeFullRestoreDownloader extends FullRestoreDownloader { + private final ByteArrayInputStream mData; + + FakeFullRestoreDownloader(byte[] data) { + // We override all methods of the superclass, so it does not require any collaborators. + super(); + mData = new ByteArrayInputStream(data); + } + + @Override + public int readNextChunk(byte[] buffer) throws IOException { + return mData.read(buffer); + } + + @Override + public void finish(FinishType finishType) { + // Do nothing. + } + } +} diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTaskTest.java new file mode 100644 index 000000000000..07a6fd2d5b60 --- /dev/null +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTaskTest.java @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +import static com.android.server.backup.testing.CryptoTestUtils.generateAesKey; +import static com.android.server.backup.testing.CryptoTestUtils.newChunkOrdering; +import static com.android.server.backup.testing.CryptoTestUtils.newChunksMetadata; +import static com.android.server.backup.testing.CryptoTestUtils.newPair; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.expectThrows; + +import android.annotation.Nullable; +import android.app.backup.BackupDataInput; +import android.platform.test.annotations.Presubmit; + +import com.android.server.backup.encryption.chunk.ChunkHash; +import com.android.server.backup.encryption.chunking.ChunkHasher; +import com.android.server.backup.encryption.chunking.DecryptedChunkFileOutput; +import com.android.server.backup.encryption.chunking.EncryptedChunk; +import com.android.server.backup.encryption.chunking.cdc.FingerprintMixer; +import com.android.server.backup.encryption.kv.DecryptedChunkKvOutput; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunkOrdering; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunksMetadata; +import com.android.server.backup.encryption.protos.nano.KeyValuePairProto.KeyValuePair; +import com.android.server.backup.encryption.tasks.BackupEncrypter.Result; +import com.android.server.backup.testing.CryptoTestUtils; +import com.android.server.testing.shadows.ShadowBackupDataInput; + +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.nano.MessageNano; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.RandomAccessFile; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import javax.crypto.AEADBadTagException; +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; + +@Config(shadows = {ShadowBackupDataInput.class}) +@RunWith(RobolectricTestRunner.class) +@Presubmit +public class BackupFileDecryptorTaskTest { + private static final String READ_WRITE_MODE = "rw"; + private static final int BYTES_PER_KILOBYTE = 1024; + private static final int MIN_CHUNK_SIZE_BYTES = 2 * BYTES_PER_KILOBYTE; + private static final int AVERAGE_CHUNK_SIZE_BYTES = 4 * BYTES_PER_KILOBYTE; + private static final int MAX_CHUNK_SIZE_BYTES = 64 * BYTES_PER_KILOBYTE; + private static final int BACKUP_DATA_SIZE_BYTES = 60 * BYTES_PER_KILOBYTE; + private static final int GCM_NONCE_LENGTH_BYTES = 12; + private static final int GCM_TAG_LENGTH_BYTES = 16; + private static final int BITS_PER_BYTE = 8; + private static final int CHECKSUM_LENGTH_BYTES = 256 / BITS_PER_BYTE; + @Nullable private static final FileDescriptor NULL_FILE_DESCRIPTOR = null; + + private static final Set<KeyValuePair> TEST_KV_DATA = new HashSet<>(); + + static { + TEST_KV_DATA.add(newPair("key1", "value1")); + TEST_KV_DATA.add(newPair("key2", "value2")); + } + + @Rule public final TemporaryFolder mTemporaryFolder = new TemporaryFolder(); + + private SecretKey mTertiaryKey; + private SecretKey mChunkEncryptionKey; + private File mInputFile; + private File mOutputFile; + private DecryptedChunkOutput mFileOutput; + private DecryptedChunkKvOutput mKvOutput; + private Random mRandom; + private BackupFileDecryptorTask mTask; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mRandom = new Random(); + mTertiaryKey = generateAesKey(); + // In good situations it's always the same. We allow changing it for testing when somehow it + // has become mismatched that we throw an error. + mChunkEncryptionKey = mTertiaryKey; + mInputFile = mTemporaryFolder.newFile(); + mOutputFile = mTemporaryFolder.newFile(); + mFileOutput = new DecryptedChunkFileOutput(mOutputFile); + mKvOutput = new DecryptedChunkKvOutput(new ChunkHasher(mTertiaryKey)); + mTask = new BackupFileDecryptorTask(mTertiaryKey); + } + + @Test + public void decryptFile_throwsForNonExistentInput() throws Exception { + assertThrows( + FileNotFoundException.class, + () -> + mTask.decryptFile( + new File(mTemporaryFolder.newFolder(), "nonexistent"), + mFileOutput)); + } + + @Test + public void decryptFile_throwsForDirectoryInputFile() throws Exception { + assertThrows( + FileNotFoundException.class, + () -> mTask.decryptFile(mTemporaryFolder.newFolder(), mFileOutput)); + } + + @Test + public void decryptFile_withExplicitStarts_decryptsEncryptedData() throws Exception { + byte[] backupData = randomData(BACKUP_DATA_SIZE_BYTES); + createEncryptedFileUsingExplicitStarts(backupData); + + mTask.decryptFile(mInputFile, mFileOutput); + + assertThat(Files.readAllBytes(Paths.get(mOutputFile.toURI()))).isEqualTo(backupData); + } + + @Test + public void decryptFile_withInlineLengths_decryptsEncryptedData() throws Exception { + createEncryptedFileUsingInlineLengths( + TEST_KV_DATA, chunkOrdering -> chunkOrdering, chunksMetadata -> chunksMetadata); + mTask.decryptFile(mInputFile, mKvOutput); + assertThat(asMap(mKvOutput.getPairs())).containsExactlyEntriesIn(asMap(TEST_KV_DATA)); + } + + @Test + public void decryptFile_withNoChunkOrderingType_decryptsUsingExplicitStarts() throws Exception { + byte[] backupData = randomData(BACKUP_DATA_SIZE_BYTES); + createEncryptedFileUsingExplicitStarts( + backupData, + chunkOrdering -> chunkOrdering, + chunksMetadata -> { + ChunksMetadata metadata = CryptoTestUtils.clone(chunksMetadata); + metadata.chunkOrderingType = + ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED; + return metadata; + }); + + mTask.decryptFile(mInputFile, mFileOutput); + + assertThat(Files.readAllBytes(Paths.get(mOutputFile.toURI()))).isEqualTo(backupData); + } + + @Test + public void decryptFile_withInlineLengths_throwsForZeroLengths() throws Exception { + createEncryptedFileUsingInlineLengths( + TEST_KV_DATA, chunkOrdering -> chunkOrdering, chunksMetadata -> chunksMetadata); + + // Set the length of the first chunk to zero. + RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE); + raf.seek(0); + raf.writeInt(0); + + assertThrows( + MalformedEncryptedFileException.class, + () -> mTask.decryptFile(mInputFile, mKvOutput)); + } + + @Test + public void decryptFile_withInlineLengths_throwsForLongLengths() throws Exception { + createEncryptedFileUsingInlineLengths( + TEST_KV_DATA, chunkOrdering -> chunkOrdering, chunksMetadata -> chunksMetadata); + + // Set the length of the first chunk to zero. + RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE); + raf.seek(0); + raf.writeInt((int) mInputFile.length()); + + assertThrows( + MalformedEncryptedFileException.class, + () -> mTask.decryptFile(mInputFile, mKvOutput)); + } + + @Test + public void decryptFile_throwsForBadKey() throws Exception { + createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES)); + + assertThrows( + AEADBadTagException.class, + () -> + new BackupFileDecryptorTask(generateAesKey()) + .decryptFile(mInputFile, mFileOutput)); + } + + @Test + public void decryptFile_withExplicitStarts_throwsForMangledOrdering() throws Exception { + createEncryptedFileUsingExplicitStarts( + randomData(BACKUP_DATA_SIZE_BYTES), + chunkOrdering -> { + ChunkOrdering ordering = CryptoTestUtils.clone(chunkOrdering); + Arrays.sort(ordering.starts); + return ordering; + }); + + assertThrows( + MessageDigestMismatchException.class, + () -> mTask.decryptFile(mInputFile, mFileOutput)); + } + + @Test + public void decryptFile_withExplicitStarts_noChunks_returnsNoData() throws Exception { + byte[] backupData = randomData(/*length=*/ 0); + createEncryptedFileUsingExplicitStarts( + backupData, + chunkOrdering -> { + ChunkOrdering ordering = CryptoTestUtils.clone(chunkOrdering); + ordering.starts = new int[0]; + return ordering; + }); + + mTask.decryptFile(mInputFile, mFileOutput); + + assertThat(Files.readAllBytes(Paths.get(mOutputFile.toURI()))).isEqualTo(backupData); + } + + @Test + public void decryptFile_throwsForMismatchedChecksum() throws Exception { + createEncryptedFileUsingExplicitStarts( + randomData(BACKUP_DATA_SIZE_BYTES), + chunkOrdering -> { + ChunkOrdering ordering = CryptoTestUtils.clone(chunkOrdering); + ordering.checksum = + Arrays.copyOf(randomData(CHECKSUM_LENGTH_BYTES), CHECKSUM_LENGTH_BYTES); + return ordering; + }); + + assertThrows( + MessageDigestMismatchException.class, + () -> mTask.decryptFile(mInputFile, mFileOutput)); + } + + @Test + public void decryptFile_throwsForBadChunksMetadataOffset() throws Exception { + createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES)); + + // Replace the metadata with all 1s. + RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE); + raf.seek(raf.length() - Long.BYTES); + int metadataOffset = (int) raf.readLong(); + int metadataLength = (int) raf.length() - metadataOffset - Long.BYTES; + + byte[] allOnes = new byte[metadataLength]; + Arrays.fill(allOnes, (byte) 1); + + raf.seek(metadataOffset); + raf.write(allOnes, /*off=*/ 0, metadataLength); + + MalformedEncryptedFileException thrown = + expectThrows( + MalformedEncryptedFileException.class, + () -> mTask.decryptFile(mInputFile, mFileOutput)); + assertThat(thrown) + .hasMessageThat() + .isEqualTo( + "Could not read chunks metadata at position " + + metadataOffset + + " of file of " + + raf.length() + + " bytes"); + } + + @Test + public void decryptFile_throwsForChunksMetadataOffsetBeyondEndOfFile() throws Exception { + createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES)); + + RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE); + raf.seek(raf.length() - Long.BYTES); + raf.writeLong(raf.length()); + + MalformedEncryptedFileException thrown = + expectThrows( + MalformedEncryptedFileException.class, + () -> mTask.decryptFile(mInputFile, mFileOutput)); + assertThat(thrown) + .hasMessageThat() + .isEqualTo( + raf.length() + + " is not valid position for chunks metadata in file of " + + raf.length() + + " bytes"); + } + + @Test + public void decryptFile_throwsForChunksMetadataOffsetBeforeBeginningOfFile() throws Exception { + createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES)); + + RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE); + raf.seek(raf.length() - Long.BYTES); + raf.writeLong(-1); + + MalformedEncryptedFileException thrown = + expectThrows( + MalformedEncryptedFileException.class, + () -> mTask.decryptFile(mInputFile, mFileOutput)); + assertThat(thrown) + .hasMessageThat() + .isEqualTo( + "-1 is not valid position for chunks metadata in file of " + + raf.length() + + " bytes"); + } + + @Test + public void decryptFile_throwsForMangledChunks() throws Exception { + createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES)); + + // Mess up some bits in a random byte + RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE); + raf.seek(50); + byte fiftiethByte = raf.readByte(); + raf.seek(50); + raf.write(~fiftiethByte); + + assertThrows(AEADBadTagException.class, () -> mTask.decryptFile(mInputFile, mFileOutput)); + } + + @Test + public void decryptFile_throwsForBadChunkEncryptionKey() throws Exception { + mChunkEncryptionKey = generateAesKey(); + + createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES)); + + assertThrows(AEADBadTagException.class, () -> mTask.decryptFile(mInputFile, mFileOutput)); + } + + @Test + public void decryptFile_throwsForUnsupportedCipherType() throws Exception { + createEncryptedFileUsingExplicitStarts( + randomData(BACKUP_DATA_SIZE_BYTES), + chunkOrdering -> chunkOrdering, + chunksMetadata -> { + ChunksMetadata metadata = CryptoTestUtils.clone(chunksMetadata); + metadata.cipherType = ChunksMetadataProto.UNKNOWN_CIPHER_TYPE; + return metadata; + }); + + assertThrows( + UnsupportedEncryptedFileException.class, + () -> mTask.decryptFile(mInputFile, mFileOutput)); + } + + @Test + public void decryptFile_throwsForUnsupportedMessageDigestType() throws Exception { + createEncryptedFileUsingExplicitStarts( + randomData(BACKUP_DATA_SIZE_BYTES), + chunkOrdering -> chunkOrdering, + chunksMetadata -> { + ChunksMetadata metadata = CryptoTestUtils.clone(chunksMetadata); + metadata.checksumType = ChunksMetadataProto.UNKNOWN_CHECKSUM_TYPE; + return metadata; + }); + + assertThrows( + UnsupportedEncryptedFileException.class, + () -> mTask.decryptFile(mInputFile, mFileOutput)); + } + + /** + * Creates an encrypted backup file from the given data. + * + * @param data The plaintext content. + */ + private void createEncryptedFileUsingExplicitStarts(byte[] data) throws Exception { + createEncryptedFileUsingExplicitStarts(data, chunkOrdering -> chunkOrdering); + } + + /** + * Creates an encrypted backup file from the given data. + * + * @param data The plaintext content. + * @param chunkOrderingTransformer Transforms the ordering before it's encrypted. + */ + private void createEncryptedFileUsingExplicitStarts( + byte[] data, Transformer<ChunkOrdering> chunkOrderingTransformer) throws Exception { + createEncryptedFileUsingExplicitStarts( + data, chunkOrderingTransformer, chunksMetadata -> chunksMetadata); + } + + /** + * Creates an encrypted backup file from the given data in mode {@link + * ChunksMetadataProto#EXPLICIT_STARTS}. + * + * @param data The plaintext content. + * @param chunkOrderingTransformer Transforms the ordering before it's encrypted. + * @param chunksMetadataTransformer Transforms the metadata before it's written. + */ + private void createEncryptedFileUsingExplicitStarts( + byte[] data, + Transformer<ChunkOrdering> chunkOrderingTransformer, + Transformer<ChunksMetadata> chunksMetadataTransformer) + throws Exception { + Result result = backupFullData(data); + + ArrayList<EncryptedChunk> chunks = new ArrayList<>(result.getNewChunks()); + Collections.shuffle(chunks); + HashMap<ChunkHash, Integer> startPositions = new HashMap<>(); + + try (FileOutputStream fos = new FileOutputStream(mInputFile); + DataOutputStream dos = new DataOutputStream(fos)) { + int position = 0; + + for (EncryptedChunk chunk : chunks) { + startPositions.put(chunk.key(), position); + dos.write(chunk.nonce()); + dos.write(chunk.encryptedBytes()); + position += chunk.nonce().length + chunk.encryptedBytes().length; + } + + int[] starts = new int[chunks.size()]; + List<ChunkHash> chunkListing = result.getAllChunks(); + + for (int i = 0; i < chunks.size(); i++) { + starts[i] = startPositions.get(chunkListing.get(i)); + } + + ChunkOrdering chunkOrdering = newChunkOrdering(starts, result.getDigest()); + chunkOrdering = chunkOrderingTransformer.accept(chunkOrdering); + + ChunksMetadata metadata = + newChunksMetadata( + ChunksMetadataProto.AES_256_GCM, + ChunksMetadataProto.SHA_256, + ChunksMetadataProto.EXPLICIT_STARTS, + encrypt(chunkOrdering)); + metadata = chunksMetadataTransformer.accept(metadata); + + dos.write(MessageNano.toByteArray(metadata)); + dos.writeLong(position); + } + } + + /** + * Creates an encrypted backup file from the given data in mode {@link + * ChunksMetadataProto#INLINE_LENGTHS}. + * + * @param data The plaintext key value pairs to back up. + * @param chunkOrderingTransformer Transforms the ordering before it's encrypted. + * @param chunksMetadataTransformer Transforms the metadata before it's written. + */ + private void createEncryptedFileUsingInlineLengths( + Set<KeyValuePair> data, + Transformer<ChunkOrdering> chunkOrderingTransformer, + Transformer<ChunksMetadata> chunksMetadataTransformer) + throws Exception { + Result result = backupKvData(data); + + List<EncryptedChunk> chunks = new ArrayList<>(result.getNewChunks()); + System.out.println("we have chunk count " + chunks.size()); + Collections.shuffle(chunks); + + try (FileOutputStream fos = new FileOutputStream(mInputFile); + DataOutputStream dos = new DataOutputStream(fos)) { + for (EncryptedChunk chunk : chunks) { + dos.writeInt(chunk.nonce().length + chunk.encryptedBytes().length); + dos.write(chunk.nonce()); + dos.write(chunk.encryptedBytes()); + } + + ChunkOrdering chunkOrdering = newChunkOrdering(null, result.getDigest()); + chunkOrdering = chunkOrderingTransformer.accept(chunkOrdering); + + ChunksMetadata metadata = + newChunksMetadata( + ChunksMetadataProto.AES_256_GCM, + ChunksMetadataProto.SHA_256, + ChunksMetadataProto.INLINE_LENGTHS, + encrypt(chunkOrdering)); + metadata = chunksMetadataTransformer.accept(metadata); + + int metadataStart = dos.size(); + dos.write(MessageNano.toByteArray(metadata)); + dos.writeLong(metadataStart); + } + } + + /** Performs a full backup of the given data, and returns the chunks. */ + private BackupEncrypter.Result backupFullData(byte[] data) throws Exception { + BackupStreamEncrypter encrypter = + new BackupStreamEncrypter( + new ByteArrayInputStream(data), + MIN_CHUNK_SIZE_BYTES, + MAX_CHUNK_SIZE_BYTES, + AVERAGE_CHUNK_SIZE_BYTES); + return encrypter.backup( + mChunkEncryptionKey, + randomData(FingerprintMixer.SALT_LENGTH_BYTES), + new HashSet<>()); + } + + private Result backupKvData(Set<KeyValuePair> data) throws Exception { + ShadowBackupDataInput.reset(); + for (KeyValuePair pair : data) { + ShadowBackupDataInput.addEntity(pair.key, pair.value); + } + KvBackupEncrypter encrypter = + new KvBackupEncrypter(new BackupDataInput(NULL_FILE_DESCRIPTOR)); + return encrypter.backup( + mChunkEncryptionKey, + randomData(FingerprintMixer.SALT_LENGTH_BYTES), + Collections.EMPTY_SET); + } + + /** Encrypts {@code chunkOrdering} using {@link #mTertiaryKey}. */ + private byte[] encrypt(ChunkOrdering chunkOrdering) throws Exception { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + byte[] nonce = randomData(GCM_NONCE_LENGTH_BYTES); + cipher.init( + Cipher.ENCRYPT_MODE, + mTertiaryKey, + new GCMParameterSpec(GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE, nonce)); + byte[] nanoBytes = MessageNano.toByteArray(chunkOrdering); + byte[] encryptedBytes = cipher.doFinal(nanoBytes); + + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + out.write(nonce); + out.write(encryptedBytes); + return out.toByteArray(); + } + } + + /** Returns {@code length} random bytes. */ + private byte[] randomData(int length) { + byte[] data = new byte[length]; + mRandom.nextBytes(data); + return data; + } + + private static ImmutableMap<String, String> asMap(Collection<KeyValuePair> pairs) { + ImmutableMap.Builder<String, String> map = ImmutableMap.builder(); + for (KeyValuePair pair : pairs) { + map.put(pair.key, new String(pair.value, Charset.forName("UTF-8"))); + } + return map.build(); + } + + private interface Transformer<T> { + T accept(T t); + } +} diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java new file mode 100644 index 000000000000..096b2da10c98 --- /dev/null +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertThrows; + +import com.android.server.backup.encryption.chunk.ChunkHash; +import com.android.server.backup.encryption.chunking.ProtoStore; +import com.android.server.backup.encryption.chunking.cdc.FingerprintMixer; +import com.android.server.backup.encryption.keys.TertiaryKeyManager; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto; +import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunkListing; +import com.android.server.backup.encryption.protos.nano.WrappedKeyProto.WrappedKey; +import com.android.server.backup.testing.CryptoTestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Optional; + +import javax.crypto.SecretKey; + +@Config(shadows = {EncryptedBackupTaskTest.ShadowBackupFileBuilder.class}) +@RunWith(RobolectricTestRunner.class) +public class EncryptedFullBackupTaskTest { + private static final String TEST_PACKAGE_NAME = "com.example.package"; + private static final byte[] TEST_EXISTING_FINGERPRINT_MIXER_SALT = + Arrays.copyOf(new byte[] {11}, ChunkHash.HASH_LENGTH_BYTES); + private static final byte[] TEST_GENERATED_FINGERPRINT_MIXER_SALT = + Arrays.copyOf(new byte[] {22}, ChunkHash.HASH_LENGTH_BYTES); + private static final ChunkHash TEST_CHUNK_HASH_1 = + new ChunkHash(Arrays.copyOf(new byte[] {1}, ChunkHash.HASH_LENGTH_BYTES)); + private static final ChunkHash TEST_CHUNK_HASH_2 = + new ChunkHash(Arrays.copyOf(new byte[] {2}, ChunkHash.HASH_LENGTH_BYTES)); + private static final int TEST_CHUNK_LENGTH_1 = 20; + private static final int TEST_CHUNK_LENGTH_2 = 40; + + @Mock private ProtoStore<ChunkListing> mChunkListingStore; + @Mock private TertiaryKeyManager mTertiaryKeyManager; + @Mock private InputStream mInputStream; + @Mock private EncryptedBackupTask mEncryptedBackupTask; + @Mock private SecretKey mTertiaryKey; + @Mock private SecureRandom mSecureRandom; + + private EncryptedFullBackupTask mTask; + private ChunkListing mOldChunkListing; + private ChunkListing mNewChunkListing; + private WrappedKey mWrappedTertiaryKey; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mWrappedTertiaryKey = new WrappedKey(); + when(mTertiaryKeyManager.getKey()).thenReturn(mTertiaryKey); + when(mTertiaryKeyManager.getWrappedKey()).thenReturn(mWrappedTertiaryKey); + + mOldChunkListing = + CryptoTestUtils.newChunkListing( + /* docId */ null, + TEST_EXISTING_FINGERPRINT_MIXER_SALT, + ChunksMetadataProto.AES_256_GCM, + ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED, + CryptoTestUtils.newChunk(TEST_CHUNK_HASH_1.getHash(), TEST_CHUNK_LENGTH_1)); + mNewChunkListing = + CryptoTestUtils.newChunkListing( + /* docId */ null, + /* fingerprintSalt */ null, + ChunksMetadataProto.AES_256_GCM, + ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED, + CryptoTestUtils.newChunk(TEST_CHUNK_HASH_1.getHash(), TEST_CHUNK_LENGTH_1), + CryptoTestUtils.newChunk(TEST_CHUNK_HASH_2.getHash(), TEST_CHUNK_LENGTH_2)); + when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any())) + .thenReturn(mNewChunkListing); + when(mEncryptedBackupTask.performIncrementalBackup(any(), any(), any())) + .thenReturn(mNewChunkListing); + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)).thenReturn(Optional.empty()); + + doAnswer(invocation -> { + byte[] byteArray = (byte[]) invocation.getArguments()[0]; + System.arraycopy( + TEST_GENERATED_FINGERPRINT_MIXER_SALT, + /* srcPos */ 0, + byteArray, + /* destPos */ 0, + FingerprintMixer.SALT_LENGTH_BYTES); + return null; + }) + .when(mSecureRandom) + .nextBytes(any(byte[].class)); + + mTask = + new EncryptedFullBackupTask( + mChunkListingStore, + mTertiaryKeyManager, + mEncryptedBackupTask, + mInputStream, + TEST_PACKAGE_NAME, + mSecureRandom); + } + + @Test + public void call_existingChunkListingButTertiaryKeyRotated_performsNonIncrementalBackup() + throws Exception { + when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(true); + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)) + .thenReturn(Optional.of(mOldChunkListing)); + + mTask.call(); + + verify(mEncryptedBackupTask) + .performNonIncrementalBackup( + eq(mTertiaryKey), + eq(mWrappedTertiaryKey), + eq(TEST_GENERATED_FINGERPRINT_MIXER_SALT)); + } + + @Test + public void call_noExistingChunkListing_performsNonIncrementalBackup() throws Exception { + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)).thenReturn(Optional.empty()); + mTask.call(); + verify(mEncryptedBackupTask) + .performNonIncrementalBackup( + eq(mTertiaryKey), + eq(mWrappedTertiaryKey), + eq(TEST_GENERATED_FINGERPRINT_MIXER_SALT)); + } + + @Test + public void call_existingChunkListing_performsIncrementalBackup() throws Exception { + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)) + .thenReturn(Optional.of(mOldChunkListing)); + mTask.call(); + verify(mEncryptedBackupTask) + .performIncrementalBackup( + eq(mTertiaryKey), eq(mWrappedTertiaryKey), eq(mOldChunkListing)); + } + + @Test + public void + call_existingChunkListingWithNoFingerprintMixerSalt_doesntSetSaltBeforeIncBackup() + throws Exception { + mOldChunkListing.fingerprintMixerSalt = new byte[0]; + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)) + .thenReturn(Optional.of(mOldChunkListing)); + + mTask.call(); + + verify(mEncryptedBackupTask) + .performIncrementalBackup( + eq(mTertiaryKey), eq(mWrappedTertiaryKey), eq(mOldChunkListing)); + } + + @Test + public void call_noExistingChunkListing_storesNewChunkListing() throws Exception { + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)).thenReturn(Optional.empty()); + mTask.call(); + verify(mChunkListingStore).saveProto(TEST_PACKAGE_NAME, mNewChunkListing); + } + + @Test + public void call_existingChunkListing_storesNewChunkListing() throws Exception { + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)) + .thenReturn(Optional.of(mOldChunkListing)); + mTask.call(); + verify(mChunkListingStore).saveProto(TEST_PACKAGE_NAME, mNewChunkListing); + } + + @Test + public void call_exceptionDuringBackup_doesNotSaveNewChunkListing() throws Exception { + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)).thenReturn(Optional.empty()); + when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any())) + .thenThrow(GeneralSecurityException.class); + + assertThrows(Exception.class, () -> mTask.call()); + + assertThat(mChunkListingStore.loadProto(TEST_PACKAGE_NAME).isPresent()).isFalse(); + } + + @Test + public void call_incrementalThrowsPermanentException_clearsState() throws Exception { + when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)) + .thenReturn(Optional.of(mOldChunkListing)); + when(mEncryptedBackupTask.performIncrementalBackup(any(), any(), any())) + .thenThrow(IOException.class); + + assertThrows(IOException.class, () -> mTask.call()); + + verify(mChunkListingStore).deleteProto(TEST_PACKAGE_NAME); + } + + @Test + public void call_closesInputStream() throws Exception { + mTask.call(); + verify(mInputStream).close(); + } + + @Test + public void cancel_cancelsTask() throws Exception { + mTask.cancel(); + verify(mEncryptedBackupTask).cancel(); + } +} diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTaskTest.java new file mode 100644 index 000000000000..0affacd114bf --- /dev/null +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTaskTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; + +import static java.util.stream.Collectors.toList; + +import com.android.server.backup.encryption.FullRestoreDownloader; + +import com.google.common.io.Files; +import com.google.common.primitives.Bytes; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; + +@RunWith(RobolectricTestRunner.class) +public class EncryptedFullRestoreTaskTest { + private static final int TEST_BUFFER_SIZE = 10; + private static final byte[] TEST_ENCRYPTED_DATA = {1, 2, 3, 4, 5, 6}; + private static final byte[] TEST_DECRYPTED_DATA = fakeDecrypt(TEST_ENCRYPTED_DATA); + + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Mock private BackupFileDecryptorTask mDecryptorTask; + + private File mFolder; + private FakeFullRestoreDownloader mFullRestorePackageWrapper; + private EncryptedFullRestoreTask mTask; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mFolder = temporaryFolder.newFolder(); + mFullRestorePackageWrapper = new FakeFullRestoreDownloader(TEST_ENCRYPTED_DATA); + + doAnswer( + invocation -> { + File source = invocation.getArgument(0); + DecryptedChunkOutput target = invocation.getArgument(1); + byte[] decrypted = fakeDecrypt(Files.toByteArray(source)); + target.open(); + target.processChunk(decrypted, decrypted.length); + target.close(); + return null; + }) + .when(mDecryptorTask) + .decryptFile(any(), any()); + + mTask = new EncryptedFullRestoreTask(mFolder, mFullRestorePackageWrapper, mDecryptorTask); + } + + @Test + public void readNextChunk_downloadsAndDecryptsBackup() throws Exception { + ByteArrayOutputStream decryptedOutput = new ByteArrayOutputStream(); + + byte[] buffer = new byte[TEST_BUFFER_SIZE]; + int bytesRead = mTask.readNextChunk(buffer); + while (bytesRead != -1) { + decryptedOutput.write(buffer, 0, bytesRead); + bytesRead = mTask.readNextChunk(buffer); + } + + assertThat(decryptedOutput.toByteArray()).isEqualTo(TEST_DECRYPTED_DATA); + } + + @Test + public void finish_deletesTemporaryFiles() throws Exception { + mTask.readNextChunk(new byte[10]); + mTask.finish(FullRestoreDownloader.FinishType.UNKNOWN_FINISH); + + assertThat(mFolder.listFiles()).isEmpty(); + } + + /** Fake package wrapper which returns data from a byte array. */ + private static class FakeFullRestoreDownloader extends FullRestoreDownloader { + private final ByteArrayInputStream mData; + + FakeFullRestoreDownloader(byte[] data) { + // We override all methods of the superclass, so it does not require any collaborators. + super(); + mData = new ByteArrayInputStream(data); + } + + @Override + public int readNextChunk(byte[] buffer) throws IOException { + return mData.read(buffer); + } + + @Override + public void finish(FinishType finishType) { + // Nothing to do. + } + } + + /** Fake decrypts a byte array by subtracting 1 from each byte. */ + private static byte[] fakeDecrypt(byte[] input) { + return Bytes.toArray(Bytes.asList(input).stream().map(b -> b + 1).collect(toList())); + } +} diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTaskTest.java new file mode 100644 index 000000000000..de8b7340ebce --- /dev/null +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTaskTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2019 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 com.android.server.backup.encryption.tasks; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertThrows; + +import android.platform.test.annotations.Presubmit; + +import com.android.server.backup.encryption.FullRestoreDownloader; +import com.android.server.backup.encryption.FullRestoreDownloader.FinishType; + +import com.google.common.io.Files; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.util.Random; + +@RunWith(RobolectricTestRunner.class) +@Presubmit +public class FullRestoreToFileTaskTest { + private static final int TEST_RANDOM_SEED = 34; + private static final int TEST_MAX_CHUNK_SIZE_BYTES = 5; + private static final int TEST_DATA_LENGTH_BYTES = TEST_MAX_CHUNK_SIZE_BYTES * 20; + + @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); + + private byte[] mTestData; + private File mTargetFile; + private FakeFullRestoreDownloader mFakeFullRestoreDownloader; + @Mock private FullRestoreDownloader mMockFullRestoreDownloader; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mTargetFile = mTemporaryFolder.newFile(); + + mTestData = new byte[TEST_DATA_LENGTH_BYTES]; + new Random(TEST_RANDOM_SEED).nextBytes(mTestData); + mFakeFullRestoreDownloader = new FakeFullRestoreDownloader(mTestData); + } + + private FullRestoreToFileTask createTaskWithFakeDownloader() { + return new FullRestoreToFileTask(mFakeFullRestoreDownloader, TEST_MAX_CHUNK_SIZE_BYTES); + } + + private FullRestoreToFileTask createTaskWithMockDownloader() { + return new FullRestoreToFileTask(mMockFullRestoreDownloader, TEST_MAX_CHUNK_SIZE_BYTES); + } + + @Test + public void restoreToFile_readsDataAndWritesToFile() throws Exception { + FullRestoreToFileTask task = createTaskWithFakeDownloader(); + task.restoreToFile(mTargetFile); + assertThat(Files.toByteArray(mTargetFile)).isEqualTo(mTestData); + } + + @Test + public void restoreToFile_noErrors_closesDownloaderWithFinished() throws Exception { + FullRestoreToFileTask task = createTaskWithMockDownloader(); + when(mMockFullRestoreDownloader.readNextChunk(any())).thenReturn(-1); + + task.restoreToFile(mTargetFile); + + verify(mMockFullRestoreDownloader).finish(FinishType.FINISHED); + } + + @Test + public void restoreToFile_ioException_closesDownloaderWithTransferFailure() throws Exception { + FullRestoreToFileTask task = createTaskWithMockDownloader(); + when(mMockFullRestoreDownloader.readNextChunk(any())).thenThrow(IOException.class); + + assertThrows(IOException.class, () -> task.restoreToFile(mTargetFile)); + + verify(mMockFullRestoreDownloader).finish(FinishType.TRANSFER_FAILURE); + } + + /** Fake package wrapper which returns data from a byte array. */ + private static class FakeFullRestoreDownloader extends FullRestoreDownloader { + + private final ByteArrayInputStream mData; + + FakeFullRestoreDownloader(byte[] data) { + // We override all methods of the superclass, so it does not require any collaborators. + super(); + this.mData = new ByteArrayInputStream(data); + } + + @Override + public int readNextChunk(byte[] buffer) throws IOException { + return mData.read(buffer); + } + + @Override + public void finish(FinishType finishType) { + // Do nothing. + } + } +} diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java index b9055cecd502..5dfd5ee8ad53 100644 --- a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java @@ -18,7 +18,9 @@ package com.android.server.backup.testing; import com.android.server.backup.encryption.chunk.ChunkHash; import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto; +import com.android.server.backup.encryption.protos.nano.KeyValuePairProto; +import java.nio.charset.Charset; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Random; @@ -76,7 +78,10 @@ public class CryptoTestUtils { int orderingType, ChunksMetadataProto.Chunk... chunks) { ChunksMetadataProto.ChunkListing chunkListing = new ChunksMetadataProto.ChunkListing(); - chunkListing.fingerprintMixerSalt = Arrays.copyOf(fingerprintSalt, fingerprintSalt.length); + chunkListing.fingerprintMixerSalt = + fingerprintSalt == null + ? null + : Arrays.copyOf(fingerprintSalt, fingerprintSalt.length); chunkListing.cipherType = cipherType; chunkListing.chunkOrderingType = orderingType; chunkListing.chunks = chunks; @@ -86,11 +91,33 @@ public class CryptoTestUtils { public static ChunksMetadataProto.ChunkOrdering newChunkOrdering( int[] starts, byte[] checksum) { ChunksMetadataProto.ChunkOrdering chunkOrdering = new ChunksMetadataProto.ChunkOrdering(); - chunkOrdering.starts = Arrays.copyOf(starts, starts.length); - chunkOrdering.checksum = Arrays.copyOf(checksum, checksum.length); + chunkOrdering.starts = starts == null ? null : Arrays.copyOf(starts, starts.length); + chunkOrdering.checksum = + checksum == null ? checksum : Arrays.copyOf(checksum, checksum.length); return chunkOrdering; } + public static ChunksMetadataProto.ChunksMetadata newChunksMetadata( + int cipherType, int checksumType, int chunkOrderingType, byte[] chunkOrdering) { + ChunksMetadataProto.ChunksMetadata metadata = new ChunksMetadataProto.ChunksMetadata(); + metadata.cipherType = cipherType; + metadata.checksumType = checksumType; + metadata.chunkOrdering = Arrays.copyOf(chunkOrdering, chunkOrdering.length); + metadata.chunkOrderingType = chunkOrderingType; + return metadata; + } + + public static KeyValuePairProto.KeyValuePair newPair(String key, String value) { + return newPair(key, value.getBytes(Charset.forName("UTF-8"))); + } + + public static KeyValuePairProto.KeyValuePair newPair(String key, byte[] value) { + KeyValuePairProto.KeyValuePair newPair = new KeyValuePairProto.KeyValuePair(); + newPair.key = key; + newPair.value = value; + return newPair; + } + public static ChunksMetadataProto.ChunkListing clone( ChunksMetadataProto.ChunkListing original) { ChunksMetadataProto.Chunk[] clonedChunks; @@ -114,4 +141,25 @@ public class CryptoTestUtils { public static ChunksMetadataProto.Chunk clone(ChunksMetadataProto.Chunk original) { return newChunk(original.hash, original.length); } + + public static ChunksMetadataProto.ChunksMetadata clone( + ChunksMetadataProto.ChunksMetadata original) { + ChunksMetadataProto.ChunksMetadata cloneMetadata = new ChunksMetadataProto.ChunksMetadata(); + cloneMetadata.chunkOrderingType = original.chunkOrderingType; + cloneMetadata.chunkOrdering = + original.chunkOrdering == null + ? null + : Arrays.copyOf(original.chunkOrdering, original.chunkOrdering.length); + cloneMetadata.checksumType = original.checksumType; + cloneMetadata.cipherType = original.cipherType; + return cloneMetadata; + } + + public static ChunksMetadataProto.ChunkOrdering clone( + ChunksMetadataProto.ChunkOrdering original) { + ChunksMetadataProto.ChunkOrdering clone = new ChunksMetadataProto.ChunkOrdering(); + clone.starts = Arrays.copyOf(original.starts, original.starts.length); + clone.checksum = Arrays.copyOf(original.checksum, original.checksum.length); + return clone; + } } diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/TestFileUtils.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/TestFileUtils.java new file mode 100644 index 000000000000..e5d73ba41902 --- /dev/null +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/TestFileUtils.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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. + */ + +import com.google.common.io.ByteStreams; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +/** Utility methods for use in tests */ +public class TestFileUtils { + /** Read the contents of a file into a byte array */ + public static byte[] toByteArray(File file) throws IOException { + try (FileInputStream fis = new FileInputStream(file)) { + return ByteStreams.toByteArray(fis); + } + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java index afd722ba0091..447e579ece42 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java @@ -22,6 +22,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.policy.BatteryController; import javax.inject.Inject; import javax.inject.Singleton; @@ -34,8 +35,9 @@ public class CarNotificationInterruptionStateProvider extends @Inject public CarNotificationInterruptionStateProvider(Context context, NotificationFilter filter, - StatusBarStateController stateController) { - super(context, filter, stateController); + StatusBarStateController stateController, + BatteryController batteryController) { + super(context, filter, stateController, batteryController); } @Override diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java index 58f80a4ed968..d79849ccafc6 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java @@ -257,6 +257,11 @@ public class CarBatteryController extends BroadcastReceiver implements BatteryCo return false; } + @Override + public boolean isAodPowerSave() { + return false; + } + private void notifyBatteryLevelChanged() { for (int i = 0, size = mChangeCallbacks.size(); i < size; i++) { mChangeCallbacks.get(i) diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 8f474704097e..1f923aff0cea 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1004,9 +1004,9 @@ <!-- [CHAR_LIMIT=40] Label for battery level chart when charging --> <string name="power_charging"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="state">%2$s</xliff:g></string> <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging --> - <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until fully charged</string> + <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until charged</string> <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration --> - <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until fully charged</string> + <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until charged</string> <!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed --> <string name="battery_info_status_unknown">Unknown</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 6a906719d3fa..19c666459723 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -865,6 +865,10 @@ public class ApplicationsState { void handleRebuildList() { AppFilter filter; Comparator<AppEntry> comparator; + + if (!mResumed) { + return; + } synchronized (mRebuildSync) { if (!mRebuildRequested) { return; @@ -1069,8 +1073,8 @@ public class ApplicationsState { } } if (rebuildingSessions != null) { - for (int i = 0; i < rebuildingSessions.size(); i++) { - rebuildingSessions.get(i).handleRebuildList(); + for (Session session : rebuildingSessions) { + session.handleRebuildList(); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java index 5c9a06f91e6a..4e052f1aeca4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java @@ -26,7 +26,7 @@ public class ThreadUtils { private static volatile Thread sMainThread; private static volatile Handler sMainThreadHandler; - private static volatile ExecutorService sSingleThreadExecutor; + private static volatile ExecutorService sThreadExecutor; /** * Returns true if the current thread is the UI thread. @@ -64,10 +64,11 @@ public class ThreadUtils { * @Return A future of the task that can be monitored for updates or cancelled. */ public static Future postOnBackgroundThread(Runnable runnable) { - if (sSingleThreadExecutor == null) { - sSingleThreadExecutor = Executors.newSingleThreadExecutor(); + if (sThreadExecutor == null) { + sThreadExecutor = Executors.newFixedThreadPool( + Runtime.getRuntime().availableProcessors()); } - return sSingleThreadExecutor.submit(runnable); + return sThreadExecutor.submit(runnable); } /** diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java index f8697a19c7ab..95a4f69b287c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java @@ -269,7 +269,7 @@ public class ApplicationsStateRoboTest { } @Test - public void testDefaultSessionLoadsAll() { + public void testDefaultSession_isResumed_LoadsAll() { mSession.onResume(); addApp(HOME_PACKAGE_NAME, 1); @@ -296,6 +296,19 @@ public class ApplicationsStateRoboTest { } @Test + public void testDefaultSession_isPaused_NotLoadsAll() { + mSession.onResume(); + + addApp(HOME_PACKAGE_NAME, 1); + addApp(LAUNCHABLE_PACKAGE_NAME, 2); + mSession.mResumed = false; + mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR); + processAllMessages(); + + verify(mCallbacks, never()).onRebuildComplete(mAppEntriesCaptor.capture()); + } + + @Test public void testCustomSessionLoadsIconsOnly() { mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS); mSession.onResume(); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java index 26db124c0041..5114b00d2711 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java @@ -50,7 +50,7 @@ public class ThreadUtilsTest { } @Test - public void testPostOnMainThread_shouldRunOnMainTread() { + public void testPostOnMainThread_shouldRunOnMainThread() { TestRunnable cr = new TestRunnable(); ShadowLooper.pauseMainLooper(); ThreadUtils.postOnMainThread(cr); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 3a7de188f962..86625faab4d6 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -719,7 +719,8 @@ public class SettingsBackupTest { Settings.Secure.BIOMETRIC_DEBUG_ENABLED, Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, - Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED); + Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED, + Settings.Secure.FACE_UNLOCK_RE_ENROLL); @Test public void systemSettingsBackedUpOrBlacklisted() { diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index e767bccc7b4a..e11c063f57fb 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -29,6 +29,7 @@ <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" /> + <uses-permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION" /> <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> @@ -240,7 +241,7 @@ <activity android:name=".BugreportWarningActivity" - android:theme="@android:style/Theme.DeviceDefault.Dialog.Alert" + android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight" android:finishOnCloseSystemDialogs="true" android:excludeFromRecents="true" android:exported="false" /> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 0fe7084bb145..485240a8895b 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -62,7 +62,7 @@ <!-- When the lock screen is showing, the phone is plugged in and the battery is fully charged, say that it is charged. --> - <string name="keyguard_charged">Fully charged</string> + <string name="keyguard_charged">Charged</string> <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's wirelessly charging. [CHAR LIMIT=50] --> <string name="keyguard_plugged_in_wireless"><xliff:g id="percentage" example="20%">%s</xliff:g> • Charging wirelessly</string> diff --git a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml index 4849dfb777ed..7d6ff3b16db6 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml @@ -20,10 +20,10 @@ android:id="@+id/plugin_frame" android:theme="@style/qs_theme" android:layout_width="@dimen/qs_panel_width" - android:layout_height="96dp" + android:layout_height="105dp" android:layout_gravity="center_horizontal" - android:layout_marginTop="@*android:dimen/quick_qs_total_height" + android:layout_marginTop="@dimen/notification_side_paddings" android:layout_marginLeft="@dimen/notification_side_paddings" android:layout_marginRight="@dimen/notification_side_paddings" android:visibility="gone" - android:background="@drawable/qs_background_primary"/>
\ No newline at end of file + android:background="@drawable/qs_background_primary"/> diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java index 4531c892a022..0fa80aca97fb 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java @@ -17,6 +17,7 @@ package com.android.systemui; import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.power.PowerUI; import dagger.Binds; import dagger.Module; @@ -33,4 +34,10 @@ public abstract class SystemUIBinder { @IntoMap @ClassKey(KeyguardViewMediator.class) public abstract SystemUI bindKeyguardViewMediator(KeyguardViewMediator sysui); + + /** Inject into PowerUI. */ + @Binds + @IntoMap + @ClassKey(PowerUI.class) + public abstract SystemUI bindPowerUI(PowerUI sysui); } diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java index bf81e1d3b7f1..9958124a14e4 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java @@ -152,7 +152,8 @@ public class DefaultUiController implements AssistManager.UiController { .setSubtype(Dependency.get(AssistManager.class).toLoggingSubType(type))); } // Logs assistant invocation cancelled. - if (!mInvocationAnimator.isRunning() && invocationWasInProgress && progress == 0f) { + if ((mInvocationAnimator == null || !mInvocationAnimator.isRunning()) + && invocationWasInProgress && progress == 0f) { if (VERBOSE) { Log.v(TAG, "Invocation cancelled: type=" + type); } diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt index f0e8c16e650a..5e977b4684dc 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt @@ -75,7 +75,7 @@ open class BroadcastDispatcher @Inject constructor ( * @param filter A filter to determine what broadcasts should be dispatched to this receiver. * It will only take into account actions and categories for filtering. * @param handler A handler to dispatch [BroadcastReceiver.onReceive]. By default, it is the - * main handler. + * main handler. Pass `null` to use the default. * @param user A user handle to determine which broadcast should be dispatched to this receiver. * By default, it is the current user. */ @@ -83,10 +83,12 @@ open class BroadcastDispatcher @Inject constructor ( fun registerReceiver( receiver: BroadcastReceiver, filter: IntentFilter, - handler: Handler = mainHandler, + handler: Handler? = mainHandler, user: UserHandle = context.user ) { - this.handler.obtainMessage(MSG_ADD_RECEIVER, ReceiverData(receiver, filter, handler, user)) + this.handler + .obtainMessage(MSG_ADD_RECEIVER, + ReceiverData(receiver, filter, handler ?: mainHandler, user)) .sendToTarget() } diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt index d44b63e813e6..54f9950239c2 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt @@ -34,7 +34,7 @@ import java.util.concurrent.atomic.AtomicBoolean private const val MSG_REGISTER_RECEIVER = 0 private const val MSG_UNREGISTER_RECEIVER = 1 -private const val TAG = "UniversalReceiver" +private const val TAG = "UserBroadcastDispatcher" private const val DEBUG = false /** @@ -97,7 +97,7 @@ class UserBroadcastDispatcher( private val receiverToReceiverData = ArrayMap<BroadcastReceiver, MutableSet<ReceiverData>>() override fun onReceive(context: Context, intent: Intent) { - bgHandler.post(HandleBroadcastRunnable(actionsToReceivers, context, intent)) + bgHandler.post(HandleBroadcastRunnable(actionsToReceivers, context, intent, pendingResult)) } /** @@ -160,7 +160,8 @@ class UserBroadcastDispatcher( private class HandleBroadcastRunnable( val actionsToReceivers: Map<String, Set<ReceiverData>>, val context: Context, - val intent: Intent + val intent: Intent, + val pendingResult: PendingResult ) : Runnable { override fun run() { if (DEBUG) Log.w(TAG, "Dispatching $intent") @@ -171,6 +172,7 @@ class UserBroadcastDispatcher( ?.forEach { it.handler.post { if (DEBUG) Log.w(TAG, "Dispatching to ${it.receiver}") + it.receiver.pendingResult = pendingResult it.receiver.onReceive(context, intent) } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java index 1d7e9eacbd2e..419fd622d1df 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java @@ -82,7 +82,7 @@ public class DozeDockHandler implements DozeMachine.Part { private void requestPulse(State dozeState) { if (!mDozeHost.isPulsingBlocked() && dozeState.canPulse()) { - mMachine.requestPulse(DozeLog.PULSE_REASON_DOCKING); + mMachine.requestPulse(DozeEvent.PULSE_REASON_DOCKING); } mPulsePending = false; } @@ -91,7 +91,7 @@ public class DozeDockHandler implements DozeMachine.Part { if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING || dozeState == State.DOZE_PULSING_BRIGHT) { final int pulseReason = mMachine.getPulseReason(); - if (pulseReason == DozeLog.PULSE_REASON_DOCKING) { + if (pulseReason == DozeEvent.PULSE_REASON_DOCKING) { mDozeHost.stopPulsing(); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java new file mode 100644 index 000000000000..ea1def07a309 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2019 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 com.android.systemui.doze; + +import android.annotation.IntDef; + +import com.android.systemui.log.RichEvent; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * An event related to dozing. {@link DozeLog} stores and prints these events for debugging + * and triaging purposes. + */ +public class DozeEvent extends RichEvent { + public static final int TOTAL_EVENT_TYPES = 19; + + public DozeEvent(int logLevel, int type, String reason) { + super(logLevel, type, reason); + } + + /** + * Event labels for each doze event + * Index corresponds to the integer associated with each {@link EventType} + */ + @Override + public String[] getEventLabels() { + final String[] events = new String[]{ + "PickupWakeup", + "PulseStart", + "PulseFinish", + "NotificationPulse", + "Dozing", + "Fling", + "EmergencyCall", + "KeyguardBouncerChanged", + "ScreenOn", + "ScreenOff", + "MissedTick", + "TimeTickScheduled", + "KeyguardVisibilityChanged", + "DozeStateChanged", + "WakeDisplay", + "ProximityResult", + "PulseDropped", + "PulseDisabledByProx", + "SensorTriggered" + }; + + if (events.length != TOTAL_EVENT_TYPES) { + throw new IllegalStateException("DozeEvent events.length should match TOTAL_EVENT_TYPES" + + " events.length=" + events.length + + " TOTAL_EVENT_LENGTH=" + TOTAL_EVENT_TYPES); + } + return events; + } + + /** + * Converts the reason (integer) to a user-readable string + */ + public static String reasonToString(@Reason int pulseReason) { + switch (pulseReason) { + case PULSE_REASON_INTENT: return "intent"; + case PULSE_REASON_NOTIFICATION: return "notification"; + case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion"; + case REASON_SENSOR_PICKUP: return "pickup"; + case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; + case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; + case PULSE_REASON_DOCKING: return "docking"; + case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen"; + case REASON_SENSOR_WAKE_UP: return "wakeup"; + case REASON_SENSOR_TAP: return "tap"; + default: throw new IllegalArgumentException("invalid reason: " + pulseReason); + } + } + + /** + * Builds a DozeEvent. + */ + public static class DozeEventBuilder extends RichEvent.Builder<DozeEventBuilder> { + @Override + public DozeEventBuilder getBuilder() { + return this; + } + + @Override + public RichEvent build() { + return new DozeEvent(mLogLevel, mType, mReason); + } + } + + @IntDef({PICKUP_WAKEUP, PULSE_START, PULSE_FINISH, NOTIFICATION_PULSE, DOZING, FLING, + EMERGENCY_CALL, KEYGUARD_BOUNCER_CHANGED, SCREEN_ON, SCREEN_OFF, MISSED_TICK, + TIME_TICK_SCHEDULED, KEYGUARD_VISIBILITY_CHANGE, DOZE_STATE_CHANGED, WAKE_DISPLAY, + PROXIMITY_RESULT, PULSE_DROPPED, PULSE_DISABLED_BY_PROX, SENSOR_TRIGGERED}) + /** + * Types of DozeEvents + */ + @Retention(RetentionPolicy.SOURCE) + public @interface EventType {} + public static final int PICKUP_WAKEUP = 0; + public static final int PULSE_START = 1; + public static final int PULSE_FINISH = 2; + public static final int NOTIFICATION_PULSE = 3; + public static final int DOZING = 4; + public static final int FLING = 5; + public static final int EMERGENCY_CALL = 6; + public static final int KEYGUARD_BOUNCER_CHANGED = 7; + public static final int SCREEN_ON = 8; + public static final int SCREEN_OFF = 9; + public static final int MISSED_TICK = 10; + public static final int TIME_TICK_SCHEDULED = 11; + public static final int KEYGUARD_VISIBILITY_CHANGE = 12; + public static final int DOZE_STATE_CHANGED = 13; + public static final int WAKE_DISPLAY = 14; + public static final int PROXIMITY_RESULT = 15; + public static final int PULSE_DROPPED = 16; + public static final int PULSE_DISABLED_BY_PROX = 17; + public static final int SENSOR_TRIGGERED = 18; + + public static final int TOTAL_REASONS = 10; + @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, + PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, + PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP, + PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, REASON_SENSOR_TAP}) + @Retention(RetentionPolicy.SOURCE) + public @interface Reason {} + public static final int PULSE_REASON_NONE = -1; + public static final int PULSE_REASON_INTENT = 0; + public static final int PULSE_REASON_NOTIFICATION = 1; + public static final int PULSE_REASON_SENSOR_SIGMOTION = 2; + public static final int REASON_SENSOR_PICKUP = 3; + public static final int REASON_SENSOR_DOUBLE_TAP = 4; + public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; + public static final int PULSE_REASON_DOCKING = 6; + public static final int REASON_SENSOR_WAKE_UP = 7; + public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8; + public static final int REASON_SENSOR_TAP = 9; +} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 4d3dc70f651c..ca4ec6d78a07 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -33,6 +33,7 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.util.sensors.AsyncSensorManager; import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.wakelock.DelayedWakeLock; @@ -44,7 +45,8 @@ public class DozeFactory { } /** Creates a DozeMachine with its parts for {@code dozeService}. */ - public DozeMachine assembleMachine(DozeService dozeService, FalsingManager falsingManager) { + public DozeMachine assembleMachine(DozeService dozeService, FalsingManager falsingManager, + DozeLog dozeLog) { Context context = dozeService; AsyncSensorManager sensorManager = Dependency.get(AsyncSensorManager.class); AlarmManager alarmManager = context.getSystemService(AlarmManager.class); @@ -65,13 +67,14 @@ public class DozeFactory { params); DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock, - wakefulnessLifecycle); + wakefulnessLifecycle, Dependency.get(BatteryController.class), dozeLog); machine.setParts(new DozeMachine.Part[]{ new DozePauser(handler, machine, alarmManager, params.getPolicy()), new DozeFalsingManagerAdapter(falsingManager), createDozeTriggers(context, sensorManager, host, alarmManager, config, params, - handler, wakeLock, machine, dockManager), - createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params), + handler, wakeLock, machine, dockManager, dozeLog), + createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params, + dozeLog), new DozeScreenState(wrappedService, handler, params, wakeLock), createDozeScreenBrightness(context, wrappedService, sensorManager, host, params, handler), @@ -95,18 +98,19 @@ public class DozeFactory { private DozeTriggers createDozeTriggers(Context context, AsyncSensorManager sensorManager, DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config, DozeParameters params, Handler handler, WakeLock wakeLock, DozeMachine machine, - DockManager dockManager) { + DockManager dockManager, DozeLog dozeLog) { boolean allowPulseTriggers = true; return new DozeTriggers(context, machine, host, alarmManager, config, params, sensorManager, handler, wakeLock, allowPulseTriggers, dockManager, - new ProximitySensor(context, sensorManager)); + new ProximitySensor(context, sensorManager), dozeLog); + } private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock, DozeMachine machine, Handler handler, AlarmManager alarmManager, - DozeParameters params) { + DozeParameters params, DozeLog dozeLog) { return new DozeUi(context, alarmManager, machine, wakeLock, host, handler, params, - Dependency.get(KeyguardUpdateMonitor.class)); + Dependency.get(KeyguardUpdateMonitor.class), dozeLog); } public static DozeHost getHost(DozeService service) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 8fe9f929b880..2e4466d47927 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -16,282 +16,284 @@ package com.android.systemui.doze; -import android.content.Context; -import android.os.Build; -import android.util.Log; import android.util.TimeUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; -import com.android.systemui.Dependency; +import com.android.systemui.DumpController; +import com.android.systemui.log.SysuiLog; import java.io.PrintWriter; -import java.text.SimpleDateFormat; import java.util.Date; -public class DozeLog { +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Logs doze events for debugging and triaging purposes. Logs are dumped in bugreports or on demand: + * adb shell dumpsys activity service com.android.systemui/.SystemUIService \ + * dependency DumpController DozeLog + */ +@Singleton +public class DozeLog extends SysuiLog { private static final String TAG = "DozeLog"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final boolean ENABLED = true; - private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50; - static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); - - public static final int REASONS = 10; - - public static final int PULSE_REASON_NONE = -1; - public static final int PULSE_REASON_INTENT = 0; - public static final int PULSE_REASON_NOTIFICATION = 1; - public static final int PULSE_REASON_SENSOR_SIGMOTION = 2; - public static final int REASON_SENSOR_PICKUP = 3; - public static final int REASON_SENSOR_DOUBLE_TAP = 4; - public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; - public static final int PULSE_REASON_DOCKING = 6; - public static final int REASON_SENSOR_WAKE_UP = 7; - public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8; - public static final int REASON_SENSOR_TAP = 9; - - private static boolean sRegisterKeyguardCallback = true; - - private static long[] sTimes; - private static String[] sMessages; - private static int sPosition; - private static int sCount; - private static boolean sPulsing; - - private static long sSince; - private static SummaryStats sPickupPulseNearVibrationStats; - private static SummaryStats sPickupPulseNotNearVibrationStats; - private static SummaryStats sNotificationPulseStats; - private static SummaryStats sScreenOnPulsingStats; - private static SummaryStats sScreenOnNotPulsingStats; - private static SummaryStats sEmergencyCallStats; - private static SummaryStats[][] sProxStats; // [reason][near/far] - - public static void tracePickupWakeUp(Context context, boolean withinVibrationThreshold) { - if (!ENABLED) return; - init(context); - log("pickupWakeUp withinVibrationThreshold=" + withinVibrationThreshold); - (withinVibrationThreshold ? sPickupPulseNearVibrationStats - : sPickupPulseNotNearVibrationStats).append(); + + private boolean mPulsing; + private long mSince; + private SummaryStats mPickupPulseNearVibrationStats; + private SummaryStats mPickupPulseNotNearVibrationStats; + private SummaryStats mNotificationPulseStats; + private SummaryStats mScreenOnPulsingStats; + private SummaryStats mScreenOnNotPulsingStats; + private SummaryStats mEmergencyCallStats; + private SummaryStats[][] mProxStats; // [reason][near/far] + + @Inject + public DozeLog(KeyguardUpdateMonitor keyguardUpdateMonitor, DumpController dumpController) { + super(dumpController, TAG, MAX_DOZE_DEBUG_LOGS, MAX_DOZE_LOGS); + mSince = System.currentTimeMillis(); + mPickupPulseNearVibrationStats = new SummaryStats(); + mPickupPulseNotNearVibrationStats = new SummaryStats(); + mNotificationPulseStats = new SummaryStats(); + mScreenOnPulsingStats = new SummaryStats(); + mScreenOnNotPulsingStats = new SummaryStats(); + mEmergencyCallStats = new SummaryStats(); + mProxStats = new SummaryStats[DozeEvent.TOTAL_REASONS][2]; + for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) { + mProxStats[i][0] = new SummaryStats(); + mProxStats[i][1] = new SummaryStats(); + } + + if (keyguardUpdateMonitor != null) { + keyguardUpdateMonitor.registerCallback(mKeyguardCallback); + } } - public static void tracePulseStart(int reason) { - if (!ENABLED) return; - sPulsing = true; - log("pulseStart reason=" + reasonToString(reason)); + /** + * Appends pickup wakeup event to the logs + */ + public void tracePickupWakeUp(boolean withinVibrationThreshold) { + if (log(DozeEvent.PICKUP_WAKEUP, + "withinVibrationThreshold=" + withinVibrationThreshold)) { + (withinVibrationThreshold ? mPickupPulseNearVibrationStats + : mPickupPulseNotNearVibrationStats).append(); + } } - public static void tracePulseFinish() { - if (!ENABLED) return; - sPulsing = false; - log("pulseFinish"); + /** + * Appends pulse started event to the logs. + * @param reason why the pulse started + */ + public void tracePulseStart(@DozeEvent.Reason int reason) { + if (log(DozeEvent.PULSE_START, DozeEvent.reasonToString(reason))) { + mPulsing = true; + } } - public static void traceNotificationPulse(Context context) { - if (!ENABLED) return; - init(context); - log("notificationPulse"); - sNotificationPulseStats.append(); + /** + * Appends pulse finished event to the logs + */ + public void tracePulseFinish() { + if (log(DozeEvent.PULSE_FINISH)) { + mPulsing = false; + } } - private static void init(Context context) { - synchronized (DozeLog.class) { - if (sMessages == null) { - sTimes = new long[SIZE]; - sMessages = new String[SIZE]; - sSince = System.currentTimeMillis(); - sPickupPulseNearVibrationStats = new SummaryStats(); - sPickupPulseNotNearVibrationStats = new SummaryStats(); - sNotificationPulseStats = new SummaryStats(); - sScreenOnPulsingStats = new SummaryStats(); - sScreenOnNotPulsingStats = new SummaryStats(); - sEmergencyCallStats = new SummaryStats(); - sProxStats = new SummaryStats[REASONS][2]; - for (int i = 0; i < REASONS; i++) { - sProxStats[i][0] = new SummaryStats(); - sProxStats[i][1] = new SummaryStats(); - } - log("init"); - if (sRegisterKeyguardCallback) { - Dependency.get(KeyguardUpdateMonitor.class).registerCallback(sKeyguardCallback); - } - } + /** + * Appends pulse event to the logs + */ + public void traceNotificationPulse() { + if (log(DozeEvent.NOTIFICATION_PULSE)) { + mNotificationPulseStats.append(); } } - public static void traceDozing(Context context, boolean dozing) { - if (!ENABLED) return; - sPulsing = false; - init(context); - log("dozing " + dozing); + /** + * Appends dozing event to the logs + * @param dozing true if dozing, else false + */ + public void traceDozing(boolean dozing) { + if (log(DozeEvent.DOZING, "dozing=" + dozing)) { + mPulsing = false; + } } - public static void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, + /** + * Appends fling event to the logs + */ + public void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, boolean screenOnFromTouch) { - if (!ENABLED) return; - log("fling expand=" + expand + " aboveThreshold=" + aboveThreshold + " thresholdNeeded=" - + thresholdNeeded + " screenOnFromTouch=" + screenOnFromTouch); + log(DozeEvent.FLING, "expand=" + expand + + " aboveThreshold=" + aboveThreshold + + " thresholdNeeded=" + thresholdNeeded + + " screenOnFromTouch=" + screenOnFromTouch); } - public static void traceEmergencyCall() { - if (!ENABLED) return; - log("emergencyCall"); - sEmergencyCallStats.append(); + /** + * Appends emergency call event to the logs + */ + public void traceEmergencyCall() { + if (log(DozeEvent.EMERGENCY_CALL)) { + mEmergencyCallStats.append(); + } } - public static void traceKeyguardBouncerChanged(boolean showing) { - if (!ENABLED) return; - log("bouncer " + showing); + /** + * Appends keyguard bouncer changed event to the logs + * @param showing true if the keyguard bouncer is showing, else false + */ + public void traceKeyguardBouncerChanged(boolean showing) { + log(DozeEvent.KEYGUARD_BOUNCER_CHANGED, "showing=" + showing); } - public static void traceScreenOn() { - if (!ENABLED) return; - log("screenOn pulsing=" + sPulsing); - (sPulsing ? sScreenOnPulsingStats : sScreenOnNotPulsingStats).append(); - sPulsing = false; + /** + * Appends screen-on event to the logs + */ + public void traceScreenOn() { + if (log(DozeEvent.SCREEN_ON, "pulsing=" + mPulsing)) { + (mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append(); + mPulsing = false; + } } - public static void traceScreenOff(int why) { - if (!ENABLED) return; - log("screenOff why=" + why); + /** + * Appends screen-off event to the logs + * @param why reason the screen is off + */ + public void traceScreenOff(int why) { + log(DozeEvent.SCREEN_OFF, "why=" + why); } - public static void traceMissedTick(String delay) { - if (!ENABLED) return; - log("missedTick by=" + delay); + /** + * Appends missed tick event to the logs + * @param delay of the missed tick + */ + public void traceMissedTick(String delay) { + log(DozeEvent.MISSED_TICK, "delay=" + delay); } - public static void traceTimeTickScheduled(long when, long triggerAt) { - if (!ENABLED) return; - log("timeTickScheduled at=" + FORMAT.format(new Date(when)) + " triggerAt=" - + FORMAT.format(new Date(triggerAt))); + /** + * Appends time tick scheduled event to the logs + * @param when time tick scheduled at + * @param triggerAt time tick trigger at + */ + public void traceTimeTickScheduled(long when, long triggerAt) { + log(DozeEvent.TIME_TICK_SCHEDULED, + "scheduledAt=" + DATE_FORMAT.format(new Date(when)) + + " triggerAt=" + DATE_FORMAT.format(new Date(triggerAt))); } - public static void traceKeyguard(boolean showing) { - if (!ENABLED) return; - log("keyguard " + showing); - if (!showing) { - sPulsing = false; + /** + * Appends keyguard visibility change event to the logs + * @param showing whether the keyguard is now showing + */ + public void traceKeyguard(boolean showing) { + if (log(DozeEvent.KEYGUARD_VISIBILITY_CHANGE, "showing=" + showing) + && !showing) { + mPulsing = false; } } - public static void traceState(DozeMachine.State state) { - if (!ENABLED) return; - log("state " + state); + /** + * Appends doze state changed event to the logs + * @param state new DozeMachine state + */ + public void traceState(DozeMachine.State state) { + log(DozeEvent.DOZE_STATE_CHANGED, state.name()); } /** * Appends wake-display event to the logs. * @param wake if we're waking up or sleeping. */ - public static void traceWakeDisplay(boolean wake) { - if (!ENABLED) return; - log("wakeDisplay " + wake); - } - - public static void traceProximityResult(Context context, boolean near, long millis, - int reason) { - if (!ENABLED) return; - init(context); - log("proximityResult reason=" + reasonToString(reason) + " near=" + near - + " millis=" + millis); - sProxStats[reason][near ? 0 : 1].append(); + public void traceWakeDisplay(boolean wake) { + log(DozeEvent.WAKE_DISPLAY, "wake=" + wake); } - public static String reasonToString(int pulseReason) { - switch (pulseReason) { - case PULSE_REASON_INTENT: return "intent"; - case PULSE_REASON_NOTIFICATION: return "notification"; - case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion"; - case REASON_SENSOR_PICKUP: return "pickup"; - case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; - case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; - case PULSE_REASON_DOCKING: return "docking"; - case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen"; - case REASON_SENSOR_WAKE_UP: return "wakeup"; - case REASON_SENSOR_TAP: return "tap"; - default: throw new IllegalArgumentException("bad reason: " + pulseReason); + /** + * Appends proximity result event to the logs + * @param near true if near, else false + * @param millis + * @param reason why proximity result was triggered + */ + public void traceProximityResult(boolean near, long millis, @DozeEvent.Reason int reason) { + if (log(DozeEvent.PROXIMITY_RESULT, + " reason=" + DozeEvent.reasonToString(reason) + + " near=" + near + + " millis=" + millis)) { + mProxStats[reason][near ? 0 : 1].append(); } } - public static void dump(PrintWriter pw) { + /** + * Prints doze log timeline and consolidated stats + * @param pw + */ + public void dump(PrintWriter pw) { synchronized (DozeLog.class) { - if (sMessages == null) return; - pw.println(" Doze log:"); - final int start = (sPosition - sCount + SIZE) % SIZE; - for (int i = 0; i < sCount; i++) { - final int j = (start + i) % SIZE; - pw.print(" "); - pw.print(FORMAT.format(new Date(sTimes[j]))); - pw.print(' '); - pw.println(sMessages[j]); - } + super.dump(null, pw, null); // prints timeline + pw.print(" Doze summary stats (for "); - TimeUtils.formatDuration(System.currentTimeMillis() - sSince, pw); + TimeUtils.formatDuration(System.currentTimeMillis() - mSince, pw); pw.println("):"); - sPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)"); - sPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)"); - sNotificationPulseStats.dump(pw, "Notification pulse"); - sScreenOnPulsingStats.dump(pw, "Screen on (pulsing)"); - sScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)"); - sEmergencyCallStats.dump(pw, "Emergency call"); - for (int i = 0; i < REASONS; i++) { - final String reason = reasonToString(i); - sProxStats[i][0].dump(pw, "Proximity near (" + reason + ")"); - sProxStats[i][1].dump(pw, "Proximity far (" + reason + ")"); + mPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)"); + mPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)"); + mNotificationPulseStats.dump(pw, "Notification pulse"); + mScreenOnPulsingStats.dump(pw, "Screen on (pulsing)"); + mScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)"); + mEmergencyCallStats.dump(pw, "Emergency call"); + for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) { + final String reason = DozeEvent.reasonToString(i); + mProxStats[i][0].dump(pw, "Proximity near (" + reason + ")"); + mProxStats[i][1].dump(pw, "Proximity far (" + reason + ")"); } } } - private static void log(String msg) { - synchronized (DozeLog.class) { - if (sMessages == null) return; - sTimes[sPosition] = System.currentTimeMillis(); - sMessages[sPosition] = msg; - sPosition = (sPosition + 1) % SIZE; - sCount = Math.min(sCount + 1, SIZE); - } - if (DEBUG) Log.d(TAG, msg); + private boolean log(@DozeEvent.EventType int eventType) { + return log(eventType, ""); } - public static void tracePulseDropped(Context context, boolean pulsePending, - DozeMachine.State state, boolean blocked) { - if (!ENABLED) return; - init(context); - log("pulseDropped pulsePending=" + pulsePending + " state=" - + state + " blocked=" + blocked); + private boolean log(@DozeEvent.EventType int eventType, String msg) { + return super.log(new DozeEvent.DozeEventBuilder() + .setType(eventType) + .setReason(msg) + .build()); } - public static void tracePulseDropped(Context context, String why) { - if (!ENABLED) return; - init(context); - log("pulseDropped why=" + why); + /** + * Appends pulse dropped event to logs + */ + public void tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked) { + log(DozeEvent.PULSE_DROPPED, "pulsePending=" + pulsePending + " state=" + + state.name() + " blocked=" + blocked); } - public static void tracePulseTouchDisabledByProx(Context context, boolean disabled) { - if (!ENABLED) return; - init(context); - log("pulseTouchDisabledByProx " + disabled); + /** + * Appends pulse dropped event to logs + * @param reason why the pulse was dropped + */ + public void tracePulseDropped(String reason) { + log(DozeEvent.PULSE_DROPPED, "why=" + reason); } - public static void setRegisterKeyguardCallback(boolean registerKeyguardCallback) { - if (!ENABLED) return; - synchronized (DozeLog.class) { - if (sRegisterKeyguardCallback != registerKeyguardCallback && sMessages != null) { - throw new IllegalStateException("Cannot change setRegisterKeyguardCallback " - + "after init()"); - } - sRegisterKeyguardCallback = registerKeyguardCallback; - } + /** + * Appends pulse touch displayed by prox sensor event to logs + * @param disabled + */ + public void tracePulseTouchDisabledByProx(boolean disabled) { + log(DozeEvent.PULSE_DISABLED_BY_PROX, "disabled=" + disabled); } - public static void traceSensor(Context context, int reason) { - if (!ENABLED) return; - init(context); - log("sensor type=" + reasonToString(reason)); + /** + * Appends sensor triggered event to logs + * @param reason why the sensor was triggered + */ + public void traceSensor(@DozeEvent.Reason int reason) { + log(DozeEvent.SENSOR_TRIGGERED, "type=" + DozeEvent.reasonToString(reason)); } - private static class SummaryStats { + private class SummaryStats { private int mCount; public void append() { @@ -305,7 +307,7 @@ public class DozeLog { pw.print(": n="); pw.print(mCount); pw.print(" ("); - final double perHr = (double) mCount / (System.currentTimeMillis() - sSince) + final double perHr = (double) mCount / (System.currentTimeMillis() - mSince) * 1000 * 60 * 60; pw.print(perHr); pw.print("/hr)"); @@ -313,7 +315,7 @@ public class DozeLog { } } - private static final KeyguardUpdateMonitorCallback sKeyguardCallback = + private final KeyguardUpdateMonitorCallback mKeyguardCallback = new KeyguardUpdateMonitorCallback() { @Override public void onEmergencyCallAction() { @@ -340,4 +342,7 @@ public class DozeLog { traceKeyguard(showing); } }; + + private static final int MAX_DOZE_DEBUG_LOGS = 400; + private static final int MAX_DOZE_LOGS = 50; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 93a51cc20db2..75b1d6c87800 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -27,6 +27,7 @@ import com.android.internal.util.Preconditions; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.util.Assert; import com.android.systemui.util.wakelock.WakeLock; @@ -45,6 +46,7 @@ public class DozeMachine { static final String TAG = "DozeMachine"; static final boolean DEBUG = DozeService.DEBUG; + private final DozeLog mDozeLog; private static final String REASON_CHANGE_STATE = "DozeMachine#requestState"; private static final String REASON_HELD_FOR_STATE = "DozeMachine#heldForState"; @@ -121,6 +123,7 @@ public class DozeMachine { private final WakeLock mWakeLock; private final AmbientDisplayConfiguration mConfig; private final WakefulnessLifecycle mWakefulnessLifecycle; + private final BatteryController mBatteryController; private Part[] mParts; private final ArrayList<State> mQueuedRequests = new ArrayList<>(); @@ -129,11 +132,14 @@ public class DozeMachine { private boolean mWakeLockHeldForCurrentState = false; public DozeMachine(Service service, AmbientDisplayConfiguration config, - WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle) { + WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle, + BatteryController batteryController, DozeLog dozeLog) { mDozeService = service; mConfig = config; mWakefulnessLifecycle = wakefulnessLifecycle; mWakeLock = wakeLock; + mBatteryController = batteryController; + mDozeLog = dozeLog; } /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */ @@ -155,7 +161,7 @@ public class DozeMachine { @MainThread public void requestState(State requestedState) { Preconditions.checkArgument(requestedState != State.DOZE_REQUEST_PULSE); - requestState(requestedState, DozeLog.PULSE_REASON_NONE); + requestState(requestedState, DozeEvent.PULSE_REASON_NONE); } @MainThread @@ -243,7 +249,7 @@ public class DozeMachine { State oldState = mState; mState = newState; - DozeLog.traceState(newState); + mDozeLog.traceState(newState); Trace.traceCounter(Trace.TRACE_TAG_APP, "doze_machine_state", newState.ordinal()); updatePulseReason(newState, oldState, pulseReason); @@ -257,7 +263,7 @@ public class DozeMachine { if (newState == State.DOZE_REQUEST_PULSE) { mPulseReason = pulseReason; } else if (oldState == State.DOZE_PULSE_DONE) { - mPulseReason = DozeLog.PULSE_REASON_NONE; + mPulseReason = DozeEvent.PULSE_REASON_NONE; } } @@ -316,6 +322,9 @@ public class DozeMachine { Log.i(TAG, "Dropping pulse done because current state is already done: " + mState); return mState; } + if (requestedState == State.DOZE_AOD && mBatteryController.isAodPowerSave()) { + return State.DOZE; + } if (requestedState == State.DOZE_REQUEST_PULSE && !mState.canPulse()) { Log.i(TAG, "Dropping pulse request because current state can't pulse: " + mState); return mState; @@ -349,7 +358,7 @@ public class DozeMachine { nextState = State.DOZE; } - transitionTo(nextState, DozeLog.PULSE_REASON_NONE); + transitionTo(nextState, DozeEvent.PULSE_REASON_NONE); break; default: break; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index a2014004fe6c..7d860286e275 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -80,7 +80,8 @@ public class DozeSensors { public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager, DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock, - Callback callback, Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy) { + Callback callback, Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy, + DozeLog dozeLog) { mContext = context; mAlarmManager = alarmManager; mSensorManager = sensorManager; @@ -97,52 +98,59 @@ public class DozeSensors { mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), null /* setting */, dozeParameters.getPulseOnSigMotion(), - DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */, - false /* touchscreen */), + DozeEvent.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */, + false /* touchscreen */, dozeLog), mPickupSensor = new TriggerSensor( mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), Settings.Secure.DOZE_PICK_UP_GESTURE, true /* settingDef */, config.dozePickupSensorAvailable(), - DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */, + DozeEvent.REASON_SENSOR_PICKUP, false /* touchCoords */, false /* touchscreen */, - false /* ignoresSetting */), + false /* ignoresSetting */, + dozeLog), new TriggerSensor( findSensorWithType(config.doubleTapSensorType()), Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, true /* configured */, - DozeLog.REASON_SENSOR_DOUBLE_TAP, + DozeEvent.REASON_SENSOR_DOUBLE_TAP, dozeParameters.doubleTapReportsTouchCoordinates(), - true /* touchscreen */), + true /* touchscreen */, + dozeLog), new TriggerSensor( findSensorWithType(config.tapSensorType()), Settings.Secure.DOZE_TAP_SCREEN_GESTURE, true /* configured */, - DozeLog.REASON_SENSOR_TAP, + DozeEvent.REASON_SENSOR_TAP, false /* reports touch coordinates */, - true /* touchscreen */), + true /* touchscreen */, + dozeLog), new TriggerSensor( findSensorWithType(config.longPressSensorType()), Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, false /* settingDef */, true /* configured */, - DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, + DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, true /* reports touch coordinates */, - true /* touchscreen */), + true /* touchscreen */, + dozeLog), new PluginSensor( new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY), Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, mConfig.wakeScreenGestureAvailable() && alwaysOn, - DozeLog.REASON_SENSOR_WAKE_UP, + DozeEvent.REASON_SENSOR_WAKE_UP, false /* reports touch coordinates */, - false /* touchscreen */), + false /* touchscreen */, + dozeLog), new PluginSensor( new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN), Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, mConfig.wakeScreenGestureAvailable(), - DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, + DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, false /* reports touch coordinates */, - false /* touchscreen */, mConfig.getWakeLockScreenDebounce()), + false /* touchscreen */, + mConfig.getWakeLockScreenDebounce(), + dozeLog), }; mProximitySensor = new ProximitySensor(context, sensorManager); @@ -306,23 +314,24 @@ public class DozeSensors { protected boolean mRegistered; protected boolean mDisabled; protected boolean mIgnoresSetting; + protected final DozeLog mDozeLog; public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason, - boolean reportsTouchCoordinates, boolean requiresTouchscreen) { + boolean reportsTouchCoordinates, boolean requiresTouchscreen, DozeLog dozeLog) { this(sensor, setting, true /* settingDef */, configured, pulseReason, - reportsTouchCoordinates, requiresTouchscreen); + reportsTouchCoordinates, requiresTouchscreen, dozeLog); } public TriggerSensor(Sensor sensor, String setting, boolean settingDef, boolean configured, int pulseReason, boolean reportsTouchCoordinates, - boolean requiresTouchscreen) { + boolean requiresTouchscreen, DozeLog dozeLog) { this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen, false /* ignoresSetting */); + requiresTouchscreen, false /* ignoresSetting */, dozeLog); } private TriggerSensor(Sensor sensor, String setting, boolean settingDef, boolean configured, int pulseReason, boolean reportsTouchCoordinates, - boolean requiresTouchscreen, boolean ignoresSetting) { + boolean requiresTouchscreen, boolean ignoresSetting, DozeLog dozeLog) { mSensor = sensor; mSetting = setting; mSettingDefault = settingDef; @@ -331,6 +340,7 @@ public class DozeSensors { mReportsTouchCoordinates = reportsTouchCoordinates; mRequiresTouchscreen = requiresTouchscreen; mIgnoresSetting = ignoresSetting; + mDozeLog = dozeLog; } public void setListening(boolean listen) { @@ -387,7 +397,7 @@ public class DozeSensors { @Override @AnyThread public void onTrigger(TriggerEvent event) { - DozeLog.traceSensor(mContext, mPulseReason); + mDozeLog.traceSensor(mPulseReason); mHandler.post(mWakeLock.wrap(() -> { if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event)); if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) { @@ -443,16 +453,17 @@ public class DozeSensors { private long mDebounce; PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, - int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) { + int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, + DozeLog dozeLog) { this(sensor, setting, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen, 0L /* debounce */); + requiresTouchscreen, 0L /* debounce */, dozeLog); } PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured, int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen, - long debounce) { + long debounce, DozeLog dozeLog) { super(null, setting, configured, pulseReason, reportsTouchCoordinates, - requiresTouchscreen); + requiresTouchscreen, dozeLog); mPluginSensor = sensor; mDebounce = debounce; } @@ -498,7 +509,7 @@ public class DozeSensors { @Override public void onSensorChanged(SensorManagerPlugin.SensorEvent event) { - DozeLog.traceSensor(mContext, mPulseReason); + mDozeLog.traceSensor(mPulseReason); mHandler.post(mWakeLock.wrap(() -> { final long now = SystemClock.uptimeMillis(); if (now < mDebounceFrom + mDebounce) { @@ -515,7 +526,7 @@ public class DozeSensors { /** * Called when a sensor requests a pulse - * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP} + * @param pulseReason Requesting sensor, e.g. {@link DozeEvent#REASON_SENSOR_PICKUP} * @param screenX the location on the screen where the sensor fired or -1 * if the sensor doesn't support reporting screen locations. * @param screenY the location on the screen where the sensor fired or -1 diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index e92acfc7f219..17559c9b79ee 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -39,15 +39,17 @@ public class DozeService extends DreamService private static final String TAG = "DozeService"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final FalsingManager mFalsingManager; + private final DozeLog mDozeLog; private DozeMachine mDozeMachine; private DozeServicePlugin mDozePlugin; private PluginManager mPluginManager; @Inject - public DozeService(FalsingManager falsingManager) { + public DozeService(FalsingManager falsingManager, DozeLog dozeLog) { setDebug(DEBUG); mFalsingManager = falsingManager; + mDozeLog = dozeLog; } @Override @@ -62,7 +64,7 @@ public class DozeService extends DreamService } mPluginManager = Dependency.get(PluginManager.class); mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */); - mDozeMachine = new DozeFactory().assembleMachine(this, mFalsingManager); + mDozeMachine = new DozeFactory().assembleMachine(this, mFalsingManager, mDozeLog); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 8eed71c21ce4..b212884ebb98 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -67,6 +67,7 @@ public class DozeTriggers implements DozeMachine.Part { private final Context mContext; private final DozeMachine mMachine; + private final DozeLog mDozeLog; private final DozeSensors mDozeSensors; private final DozeHost mDozeHost; private final AmbientDisplayConfiguration mConfig; @@ -89,7 +90,8 @@ public class DozeTriggers implements DozeMachine.Part { AlarmManager alarmManager, AmbientDisplayConfiguration config, DozeParameters dozeParameters, AsyncSensorManager sensorManager, Handler handler, WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager, - ProximitySensor proximitySensor) { + ProximitySensor proximitySensor, + DozeLog dozeLog) { mContext = context; mMachine = machine; mDozeHost = dozeHost; @@ -100,10 +102,11 @@ public class DozeTriggers implements DozeMachine.Part { mAllowPulseTriggers = allowPulseTriggers; mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters, config, wakeLock, this::onSensor, this::onProximityFar, - dozeParameters.getPolicy()); + dozeParameters.getPolicy(), dozeLog); mUiModeManager = mContext.getSystemService(UiModeManager.class); mDockManager = dockManager; mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, handler); + mDozeLog = dozeLog; } private void onNotification(Runnable onPulseSuppressedListener) { @@ -113,18 +116,18 @@ public class DozeTriggers implements DozeMachine.Part { if (!sWakeDisplaySensorState) { Log.d(TAG, "Wake display false. Pulse denied."); runIfNotNull(onPulseSuppressedListener); - DozeLog.tracePulseDropped(mContext, "wakeDisplaySensor"); + mDozeLog.tracePulseDropped("wakeDisplaySensor"); return; } mNotificationPulseTime = SystemClock.elapsedRealtime(); if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) { runIfNotNull(onPulseSuppressedListener); - DozeLog.tracePulseDropped(mContext, "pulseOnNotificationsDisabled"); + mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled"); return; } - requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */, + requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */, onPulseSuppressedListener); - DozeLog.traceNotificationPulse(mContext); + mDozeLog.traceNotificationPulse(); } private static void runIfNotNull(Runnable runnable) { @@ -145,8 +148,7 @@ public class DozeTriggers implements DozeMachine.Part { final long start = SystemClock.uptimeMillis(); mProxCheck.check(PROXIMITY_TIMEOUT_DELAY_MS, near -> { final long end = SystemClock.uptimeMillis(); - DozeLog.traceProximityResult( - mContext, + mDozeLog.traceProximityResult( near == null ? false : near, end - start, reason); @@ -159,12 +161,12 @@ public class DozeTriggers implements DozeMachine.Part { @VisibleForTesting void onSensor(int pulseReason, float screenX, float screenY, float[] rawValues) { - boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP; - boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP; - boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP; - boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; - boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP; - boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; + boolean isDoubleTap = pulseReason == DozeEvent.REASON_SENSOR_DOUBLE_TAP; + boolean isTap = pulseReason == DozeEvent.REASON_SENSOR_TAP; + boolean isPickup = pulseReason == DozeEvent.REASON_SENSOR_PICKUP; + boolean isLongPress = pulseReason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS; + boolean isWakeDisplay = pulseReason == DozeEvent.REASON_SENSOR_WAKE_UP; + boolean isWakeLockScreen = pulseReason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0; if (isWakeDisplay) { @@ -201,7 +203,7 @@ public class DozeTriggers implements DozeMachine.Part { SystemClock.elapsedRealtime() - mNotificationPulseTime; final boolean withinVibrationThreshold = timeSinceNotification < mDozeParameters.getPickupVibrationThreshold(); - DozeLog.tracePickupWakeUp(mContext, withinVibrationThreshold); + mDozeLog.tracePickupWakeUp(withinVibrationThreshold); } } @@ -263,7 +265,7 @@ public class DozeTriggers implements DozeMachine.Part { * transitions. */ private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state) { - DozeLog.traceWakeDisplay(wake); + mDozeLog.traceWakeDisplay(wake); sWakeDisplaySensorState = wake; if (wake) { @@ -277,9 +279,9 @@ public class DozeTriggers implements DozeMachine.Part { // Logs AOD open due to sensor wake up. mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) .setType(MetricsEvent.TYPE_OPEN) - .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP)); + .setSubtype(DozeEvent.REASON_SENSOR_WAKE_UP)); } - }, true /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP); + }, true /* alreadyPerformedProxCheck */, DozeEvent.REASON_SENSOR_WAKE_UP); } else { boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED); boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING); @@ -288,7 +290,7 @@ public class DozeTriggers implements DozeMachine.Part { // Logs AOD close due to sensor wake up. mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) .setType(MetricsEvent.TYPE_CLOSE) - .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP)); + .setSubtype(DozeEvent.REASON_SENSOR_WAKE_UP)); } } } @@ -346,7 +348,6 @@ public class DozeTriggers implements DozeMachine.Part { private void checkTriggersAtInit() { if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR - || mDozeHost.isPowerSaveActive() || mDozeHost.isBlockingDoze() || !mDozeHost.isProvisioned()) { mMachine.requestState(DozeMachine.State.FINISH); @@ -361,14 +362,14 @@ public class DozeTriggers implements DozeMachine.Part { // When already pulsing we're allowed to show the wallpaper directly without // requesting a new pulse. if (mMachine.getState() == DozeMachine.State.DOZE_PULSING - && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + && reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT); return; } if (mPulsePending || !mAllowPulseTriggers || !canPulse()) { if (mAllowPulseTriggers) { - DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(), + mDozeLog.tracePulseDropped(mPulsePending, mMachine.getState(), mDozeHost.isPulsingBlocked()); } runIfNotNull(onPulseSuppressedListener); @@ -379,7 +380,7 @@ public class DozeTriggers implements DozeMachine.Part { proximityCheckThenCall((result) -> { if (result != null && result) { // in pocket, abort pulse - DozeLog.tracePulseDropped(mContext, "inPocket"); + mDozeLog.tracePulseDropped("inPocket"); mPulsePending = false; runIfNotNull(onPulseSuppressedListener); } else { @@ -401,7 +402,7 @@ public class DozeTriggers implements DozeMachine.Part { private void continuePulseRequest(int reason) { mPulsePending = false; if (mDozeHost.isPulsingBlocked() || !canPulse()) { - DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(), + mDozeLog.tracePulseDropped(mPulsePending, mMachine.getState(), mDozeHost.isPulsingBlocked()); return; } @@ -425,7 +426,7 @@ public class DozeTriggers implements DozeMachine.Part { public void onReceive(Context context, Intent intent) { if (PULSE_ACTION.equals(intent.getAction())) { if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent"); - requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */ + requestPulse(DozeEvent.PULSE_REASON_INTENT, false, /* performedProxCheck */ null /* onPulseSupressedListener */); } if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { @@ -482,8 +483,8 @@ public class DozeTriggers implements DozeMachine.Part { @Override public void onPowerSaveChanged(boolean active) { - if (active) { - mMachine.requestState(DozeMachine.State.FINISH); + if (mDozeHost.isPowerSaveActive()) { + mMachine.requestState(DozeMachine.State.DOZE); } } }; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index 1f33af8c3f55..2c0ccd214188 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -49,6 +49,7 @@ public class DozeUi implements DozeMachine.Part { private final AlarmTimeout mTimeTicker; private final boolean mCanAnimateTransition; private final DozeParameters mDozeParameters; + private final DozeLog mDozeLog; private boolean mKeyguardShowing; private final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback = @@ -65,7 +66,8 @@ public class DozeUi implements DozeMachine.Part { public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine, WakeLock wakeLock, DozeHost host, Handler handler, - DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor) { + DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor, + DozeLog dozeLog) { mContext = context; mMachine = machine; mWakeLock = wakeLock; @@ -75,6 +77,7 @@ public class DozeUi implements DozeMachine.Part { mDozeParameters = params; mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler); keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback); + mDozeLog = dozeLog; } /** @@ -83,7 +86,8 @@ public class DozeUi implements DozeMachine.Part { */ private void updateAnimateScreenOff() { if (mCanAnimateTransition) { - final boolean controlScreenOff = mDozeParameters.getAlwaysOn() && mKeyguardShowing; + final boolean controlScreenOff = mDozeParameters.getAlwaysOn() && mKeyguardShowing + && !mHost.isPowerSaveActive(); mDozeParameters.setControlScreenOffAnimation(controlScreenOff); mHost.setAnimateScreenOff(controlScreenOff); } @@ -96,7 +100,7 @@ public class DozeUi implements DozeMachine.Part { public void onPulseStarted() { try { mMachine.requestState( - reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN ? DozeMachine.State.DOZE_PULSING_BRIGHT : DozeMachine.State.DOZE_PULSING); } catch (IllegalStateException e) { @@ -175,7 +179,7 @@ public class DozeUi implements DozeMachine.Part { long delta = roundToNextMinute(time) - System.currentTimeMillis(); boolean scheduled = mTimeTicker.schedule(delta, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED); if (scheduled) { - DozeLog.traceTimeTickScheduled(time, time + delta); + mDozeLog.traceTimeTickScheduled(time, time + delta); } mLastTimeTickElapsed = SystemClock.elapsedRealtime(); } @@ -192,7 +196,7 @@ public class DozeUi implements DozeMachine.Part { long millisSinceLastTick = SystemClock.elapsedRealtime() - mLastTimeTickElapsed; if (millisSinceLastTick > TIME_TICK_DEADLINE_MILLIS) { String delay = Formatter.formatShortElapsedTime(mContext, millisSinceLastTick); - DozeLog.traceMissedTick(delay); + mDozeLog.traceMissedTick(delay); Log.e(DozeMachine.TAG, "Missed AOD time tick by " + delay); } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 57a5ae63511c..22846bc02a38 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -90,6 +90,7 @@ import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.MultiListLayout; import com.android.systemui.MultiListLayout.MultiListAdapter; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; @@ -187,7 +188,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); - context.registerReceiver(mBroadcastReceiver, filter); + Dependency.get(BroadcastDispatcher.class).registerReceiver(mBroadcastReceiver, filter); ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); diff --git a/packages/SystemUI/src/com/android/systemui/log/Event.java b/packages/SystemUI/src/com/android/systemui/log/Event.java new file mode 100644 index 000000000000..92862a2bc74c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/Event.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 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 com.android.systemui.log; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Stores information about an event that occurred in SystemUI to be used for debugging and triage. + * Every event has a time stamp, log level and message. + * Events are stored in {@link SysuiLog} and can be printed in a dumpsys. + */ +public class Event { + public static final int UNINITIALIZED = -1; + + @IntDef({ERROR, WARN, INFO, DEBUG, VERBOSE}) + @Retention(RetentionPolicy.SOURCE) + public @interface Level {} + public static final int VERBOSE = 2; + public static final int DEBUG = 3; + public static final int INFO = 4; + public static final int WARN = 5; + public static final int ERROR = 6; + + private long mTimestamp; + private @Level int mLogLevel = DEBUG; + protected String mMessage; + + public Event(String message) { + mTimestamp = System.currentTimeMillis(); + mMessage = message; + } + + public Event(@Level int logLevel, String message) { + mTimestamp = System.currentTimeMillis(); + mLogLevel = logLevel; + mMessage = message; + } + + public String getMessage() { + return mMessage; + } + + public long getTimestamp() { + return mTimestamp; + } + + public @Level int getLogLevel() { + return mLogLevel; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java new file mode 100644 index 000000000000..89b7a8181c44 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2019 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 com.android.systemui.log; + +/** + * Stores information about an event that occurred in SystemUI to be used for debugging and triage. + * Every rich event has a time stamp, event type, and log level, with the option to provide the + * reason this event was triggered. + * Events are stored in {@link SysuiLog} and can be printed in a dumpsys. + */ +public abstract class RichEvent extends Event { + private final int mType; + private final String mReason; + + /** + * Create a rich event that includes an event type that matches with an index in the array + * getEventLabels(). + */ + public RichEvent(@Event.Level int logLevel, int type, String reason) { + super(logLevel, null); + final int numEvents = getEventLabels().length; + if (type < 0 || type >= numEvents) { + throw new IllegalArgumentException("Unsupported event type. Events only supported" + + " from 0 to " + (numEvents - 1) + ", but given type=" + type); + } + mType = type; + mReason = reason; + mMessage = getEventLabels()[mType] + " " + mReason; + } + + /** + * Returns an array of the event labels. The index represents the event type and the + * corresponding String stored at that index is the user-readable representation of that event. + * @return array of user readable events, where the index represents its event type constant + */ + public abstract String[] getEventLabels(); + + public int getType() { + return mType; + } + + public String getReason() { + return mReason; + } + + /** + * Builder to build a RichEvent. + * @param <B> Log specific builder that is extending this builder + */ + public abstract static class Builder<B extends Builder<B>> { + public static final int UNINITIALIZED = -1; + + private B mBuilder = getBuilder(); + protected int mType = UNINITIALIZED; + protected String mReason; + protected @Level int mLogLevel; + + /** + * Get the log-specific builder. + */ + public abstract B getBuilder(); + + /** + * Build the log-specific event. + */ + public abstract RichEvent build(); + + /** + * Optional - set the log level. Defaults to DEBUG. + */ + public B setLogLevel(@Level int logLevel) { + mLogLevel = logLevel; + return mBuilder; + } + + /** + * Required - set the event type. These events must correspond with the events from + * getEventLabels(). + */ + public B setType(int type) { + mType = type; + return mBuilder; + } + + /** + * Optional - set the reason why this event was triggered. + */ + public B setReason(String reason) { + mReason = reason; + return mBuilder; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java new file mode 100644 index 000000000000..a6e10e6b345b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2019 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 com.android.systemui.log; + +import android.os.Build; +import android.os.SystemProperties; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.DumpController; +import com.android.systemui.Dumpable; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayDeque; +import java.util.Locale; + +/** + * Thread-safe logger in SystemUI which prints logs to logcat and stores logs to be + * printed by the DumpController. This is an alternative to printing directly + * to avoid logs being deleted by chatty. The number of logs retained is varied based on + * whether the build is {@link Build.IS_DEBUGGABLE}. + * + * To manually view the logs via adb: + * adb shell dumpsys activity service com.android.systemui/.SystemUIService \ + * dependency DumpController <SysuiLogId> + */ +public class SysuiLog implements Dumpable { + public static final SimpleDateFormat DATE_FORMAT = + new SimpleDateFormat("MM-dd HH:mm:ss", Locale.US); + + private final Object mDataLock = new Object(); + private final String mId; + private final int mMaxLogs; + private boolean mEnabled; + + @VisibleForTesting protected ArrayDeque<Event> mTimeline; + + /** + * Creates a SysuiLog + * To enable or disable logs, set the system property and then restart the device: + * adb shell setprop sysui.log.enabled.<id> true/false && adb reboot + * @param dumpController where to register this logger's dumpsys + * @param id user-readable tag for this logger + * @param maxDebugLogs maximum number of logs to retain when {@link sDebuggable} is true + * @param maxLogs maximum number of logs to retain when {@link sDebuggable} is false + */ + public SysuiLog(DumpController dumpController, String id, int maxDebugLogs, int maxLogs) { + this(dumpController, id, sDebuggable ? maxDebugLogs : maxLogs, + SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED)); + } + + @VisibleForTesting + protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled) { + mId = id; + mMaxLogs = maxLogs; + mEnabled = enabled; + mTimeline = mEnabled ? new ArrayDeque<>(mMaxLogs) : null; + dumpController.registerDumpable(mId, this); + } + + public SysuiLog(DumpController dumpController, String id) { + this(dumpController, id, DEFAULT_MAX_DEBUG_LOGS, DEFAULT_MAX_LOGS); + } + + /** + * Logs an event to the timeline which can be printed by the dumpsys. + * May also log to logcat if enabled. + * @return true if event was logged, else false + */ + public boolean log(Event event) { + if (!mEnabled) { + return false; + } + + synchronized (mDataLock) { + if (mTimeline.size() >= mMaxLogs) { + mTimeline.removeFirst(); + } + + mTimeline.add(event); + } + + if (LOG_TO_LOGCAT_ENABLED) { + final String strEvent = eventToString(event); + switch (event.getLogLevel()) { + case Event.VERBOSE: + Log.v(mId, strEvent); + break; + case Event.DEBUG: + Log.d(mId, strEvent); + break; + case Event.ERROR: + Log.e(mId, strEvent); + break; + case Event.INFO: + Log.i(mId, strEvent); + break; + case Event.WARN: + Log.w(mId, strEvent); + break; + } + } + return true; + } + + /** + * @return user-readable string of the given event + */ + public String eventToString(Event event) { + StringBuilder sb = new StringBuilder(); + sb.append(SysuiLog.DATE_FORMAT.format(event.getTimestamp())); + sb.append(" "); + sb.append(event.getMessage()); + return sb.toString(); + } + + /** + * only call on this method if you have the mDataLock + */ + private void dumpTimelineLocked(PrintWriter pw) { + pw.println("\tTimeline:"); + + for (Event event : mTimeline) { + pw.println("\t" + eventToString(event)); + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(mId + ":"); + + if (mEnabled) { + synchronized (mDataLock) { + dumpTimelineLocked(pw); + } + } else { + pw.print(" - Logging disabled."); + } + } + + private static boolean sDebuggable = Build.IS_DEBUGGABLE; + private static final String SYSPROP_ENABLED_PREFIX = "sysui.log.enabled."; + private static final boolean LOG_TO_LOGCAT_ENABLED = sDebuggable; + private static final boolean DEFAULT_ENABLED = sDebuggable; + private static final int DEFAULT_MAX_DEBUG_LOGS = 100; + private static final int DEFAULT_MAX_LOGS = 50; +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 4f2a6d82a08e..5723afd4ae95 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -247,6 +247,9 @@ public class PipMenuActivity extends Activity { protected void onStop() { super.onStop(); + // In cases such as device lock, hide and finish it so that it can be recreated on the top + // next time it starts, see also {@link #onUserLeaveHint} + hideMenu(); cancelDelayedFinish(); } diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index 75dc39722bcf..a258f356bf53 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -45,6 +45,7 @@ import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SystemUI; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.phone.StatusBar; import java.io.FileDescriptor; @@ -53,6 +54,8 @@ import java.time.Duration; import java.util.Arrays; import java.util.concurrent.Future; +import javax.inject.Inject; + public class PowerUI extends SystemUI { static final String TAG = "PowerUI"; @@ -97,6 +100,12 @@ public class PowerUI extends SystemUI { private IThermalEventListener mSkinThermalEventListener; private IThermalEventListener mUsbThermalEventListener; + private final BroadcastDispatcher mBroadcastDispatcher; + + @Inject + public PowerUI(BroadcastDispatcher broadcastDispatcher) { + mBroadcastDispatcher = broadcastDispatcher; + } public void start() { mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); @@ -211,7 +220,7 @@ public class PowerUI extends SystemUI { filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_USER_SWITCHED); - mContext.registerReceiver(this, filter, null, mHandler); + mBroadcastDispatcher.registerReceiver(this, filter, mHandler); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index d20b22815805..4013586d4197 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -257,10 +257,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mNextAlarmTextView.setSelected(true); mPermissionsHubEnabled = PrivacyItemControllerKt.isPermissionsHubEnabled(); - // Change the ignored slots when DeviceConfig flag changes - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY, - mContext.getMainExecutor(), mPropertiesListener); - } private List<String> getIgnoredIconSlots() { @@ -489,6 +485,9 @@ public class QuickStatusBarHeader extends RelativeLayout implements super.onAttachedToWindow(); mStatusBarIconController.addIconGroup(mIconManager); requestApplyInsets(); + // Change the ignored slots when DeviceConfig flag changes + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY, + mContext.getMainExecutor(), mPropertiesListener); } @Override @@ -527,6 +526,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements public void onDetachedFromWindow() { setListening(false); mStatusBarIconController.removeIconGroup(mIconManager); + DeviceConfig.removeOnPropertiesChangedListener(mPropertiesListener); super.onDetachedFromWindow(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java index d0c47345a83a..c1ce16337f8d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java @@ -61,8 +61,10 @@ import android.view.animation.DecelerateInterpolator; import android.widget.ImageView; import android.widget.TextView; +import com.android.systemui.Dependency; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; @@ -245,10 +247,15 @@ public class RecentsOnboarding { private final View.OnAttachStateChangeListener mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() { + + private final BroadcastDispatcher mBroadcastDispatcher = Dependency.get( + BroadcastDispatcher.class); + @Override public void onViewAttachedToWindow(View view) { if (view == mLayout) { - mContext.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); + mBroadcastDispatcher.registerReceiver(mReceiver, + new IntentFilter(Intent.ACTION_SCREEN_OFF)); mLayoutAttachedToWindow = true; if (view.getTag().equals(R.string.recents_swipe_up_onboarding)) { mHasDismissedSwipeUpTip = false; @@ -273,7 +280,7 @@ public class RecentsOnboarding { } mOverviewOpenedCountSinceQuickScrubTipDismiss = 0; } - mContext.unregisterReceiver(mReceiver); + mBroadcastDispatcher.unregisterReceiver(mReceiver); } } }; @@ -335,10 +342,11 @@ public class RecentsOnboarding { private void notifyOnTip(int action, int target) { try { IOverviewProxy overviewProxy = mOverviewProxyService.getProxy(); - if(overviewProxy != null) { + if (overviewProxy != null) { overviewProxy.onTip(action, target); } - } catch (RemoteException e) {} + } catch (RemoteException e) { + } } public void onNavigationModeChanged(int mode) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index c3c0d63f66c4..0f277ca8b2c6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -47,6 +47,7 @@ import android.widget.TextView; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.phone.NavigationBarView; @@ -159,6 +160,8 @@ public class ScreenPinningRequest implements View.OnClickListener, private ValueAnimator mColorAnim; private ViewGroup mLayout; private boolean mShowCancel; + private final BroadcastDispatcher mBroadcastDispatcher = + Dependency.get(BroadcastDispatcher.class); public RequestWindowView(Context context, boolean showCancel) { super(context); @@ -212,7 +215,7 @@ public class ScreenPinningRequest implements View.OnClickListener, IntentFilter filter = new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_SCREEN_OFF); - mContext.registerReceiver(mReceiver, filter); + mBroadcastDispatcher.registerReceiver(mReceiver, filter); } private void inflateView(int rotation) { @@ -313,7 +316,7 @@ public class ScreenPinningRequest implements View.OnClickListener, @Override public void onDetachedFromWindow() { - mContext.unregisterReceiver(mReceiver); + mBroadcastDispatcher.unregisterReceiver(mReceiver); } protected void onConfigurationChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java index 9362d2d5e2c9..eadec6a45895 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java @@ -39,6 +39,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.HeadsUpManager; import javax.inject.Inject; @@ -63,6 +64,7 @@ public class NotificationInterruptionStateProvider { private final Context mContext; private final PowerManager mPowerManager; private final IDreamManager mDreamManager; + private final BatteryController mBatteryController; private NotificationPresenter mPresenter; private HeadsUpManager mHeadsUpManager; @@ -75,13 +77,14 @@ public class NotificationInterruptionStateProvider { @Inject public NotificationInterruptionStateProvider(Context context, NotificationFilter filter, - StatusBarStateController stateController) { + StatusBarStateController stateController, BatteryController batteryController) { this(context, (PowerManager) context.getSystemService(Context.POWER_SERVICE), IDreamManager.Stub.asInterface( ServiceManager.checkService(DreamService.DREAM_SERVICE)), new AmbientDisplayConfiguration(context), filter, + batteryController, stateController); } @@ -92,10 +95,12 @@ public class NotificationInterruptionStateProvider { IDreamManager dreamManager, AmbientDisplayConfiguration ambientDisplayConfiguration, NotificationFilter notificationFilter, + BatteryController batteryController, StatusBarStateController statusBarStateController) { mContext = context; mPowerManager = powerManager; mDreamManager = dreamManager; + mBatteryController = batteryController; mAmbientDisplayConfiguration = ambientDisplayConfiguration; mNotificationFilter = notificationFilter; mStatusBarStateController = statusBarStateController; @@ -293,6 +298,13 @@ public class NotificationInterruptionStateProvider { return false; } + if (mBatteryController.isAodPowerSave()) { + if (DEBUG_HEADS_UP) { + Log.d(TAG, "No pulsing: disabled by battery saver: " + sbn.getKey()); + } + return false; + } + if (!canAlertCommon(entry)) { if (DEBUG_HEADS_UP) { Log.d(TAG, "No pulsing: notification shouldn't alert: " + sbn.getKey()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index 60e381a776d2..fe3c04e3cda3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -22,11 +22,14 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; +import com.android.systemui.doze.DozeEvent; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; +import javax.inject.Inject; + /** * Controller which handles all the doze animations of the scrims. */ @@ -34,6 +37,7 @@ public class DozeScrimController implements StateListener { private static final String TAG = "DozeScrimController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private final DozeLog mDozeLog; private final DozeParameters mDozeParameters; private final Handler mHandler = new Handler(); @@ -47,7 +51,7 @@ public class DozeScrimController implements StateListener { public void onDisplayBlanked() { if (DEBUG) { Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason=" - + DozeLog.reasonToString(mPulseReason)); + + DozeEvent.reasonToString(mPulseReason)); } if (!mDozing) { return; @@ -68,8 +72,8 @@ public class DozeScrimController implements StateListener { // Notifications should time out on their own. Pulses due to notifications should // instead be managed externally based off the notification's lifetime. // Dock also controls the time out by self. - if (mPulseReason != DozeLog.PULSE_REASON_NOTIFICATION - && mPulseReason != DozeLog.PULSE_REASON_DOCKING) { + if (mPulseReason != DozeEvent.PULSE_REASON_NOTIFICATION + && mPulseReason != DozeEvent.PULSE_REASON_DOCKING) { mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); mHandler.postDelayed(mPulseOutExtended, mDozeParameters.getPulseVisibleDurationExtended()); @@ -90,14 +94,16 @@ public class DozeScrimController implements StateListener { */ @Override public boolean shouldTimeoutWallpaper() { - return mPulseReason == DozeLog.PULSE_REASON_DOCKING; + return mPulseReason == DozeEvent.PULSE_REASON_DOCKING; } }; - public DozeScrimController(DozeParameters dozeParameters) { + @Inject + public DozeScrimController(DozeParameters dozeParameters, DozeLog dozeLog) { mDozeParameters = dozeParameters; //Never expected to be destroyed Dependency.get(StatusBarStateController.class).addCallback(this); + mDozeLog = dozeLog; } @VisibleForTesting @@ -168,14 +174,14 @@ public class DozeScrimController implements StateListener { } private void pulseStarted() { - DozeLog.tracePulseStart(mPulseReason); + mDozeLog.tracePulseStart(mPulseReason); if (mPulseCallback != null) { mPulseCallback.onPulseStarted(); } } private void pulseFinished() { - DozeLog.tracePulseFinish(); + mDozeLog.tracePulseFinish(); if (mPulseCallback != null) { mPulseCallback.onPulseFinished(); mPulseCallback = null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt index 7dcc2fcfe2b2..53601babfd56 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone import android.content.Context import android.view.View +import android.view.ViewGroup.MarginLayoutParams import android.widget.FrameLayout import com.android.systemui.plugins.NPVPlugin import com.android.systemui.plugins.PluginListener @@ -36,6 +37,7 @@ class NPVPluginManager( private var plugin: NPVPlugin? = null private var animator = createAnimator() + private var yOffset = 0f private fun createAnimator() = TouchAnimator.Builder() .addFloat(parent, "alpha", 1f, 0f) @@ -76,7 +78,7 @@ class NPVPluginManager( } fun setExpansion(expansion: Float, headerTranslation: Float, heightDiff: Float) { - parent.setTranslationY(expansion * heightDiff + headerTranslation) + parent.setTranslationY(expansion * heightDiff + headerTranslation + yOffset) if (!expansion.isNaN()) animator.setPosition(expansion) } @@ -88,5 +90,13 @@ class NPVPluginManager( animator = createAnimator() } - fun getHeight() = if (plugin != null) parent.height else 0 + fun getHeight() = + if (plugin != null) { + parent.height + (parent.getLayoutParams() as MarginLayoutParams).topMargin + } else 0 + + fun setYOffset(y: Float) { + yOffset = y + parent.setTranslationY(yOffset) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index b87140dddec3..6e61d7ceaf6c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -89,6 +89,7 @@ import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.assist.AssistHandleViewController; import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.model.SysUiState; @@ -139,6 +140,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private final MetricsLogger mMetricsLogger; private final DeviceProvisionedController mDeviceProvisionedController; private final StatusBarStateController mStatusBarStateController; + private final NavigationModeController mNavigationModeController; protected NavigationBarView mNavigationBarView = null; @@ -170,6 +172,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private OverviewProxyService mOverviewProxyService; + private final BroadcastDispatcher mBroadcastDispatcher; + @VisibleForTesting public int mDisplayId; private boolean mIsOnDefaultDisplay; @@ -251,7 +255,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback AssistManager assistManager, OverviewProxyService overviewProxyService, NavigationModeController navigationModeController, StatusBarStateController statusBarStateController, - SysUiState sysUiFlagsContainer) { + SysUiState sysUiFlagsContainer, + BroadcastDispatcher broadcastDispatcher) { mAccessibilityManagerWrapper = accessibilityManagerWrapper; mDeviceProvisionedController = deviceProvisionedController; mStatusBarStateController = statusBarStateController; @@ -260,7 +265,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mSysUiFlagsContainer = sysUiFlagsContainer; mAssistantAvailable = mAssistManager.getAssistInfoForUser(UserHandle.USER_CURRENT) != null; mOverviewProxyService = overviewProxyService; + mNavigationModeController = navigationModeController; mNavBarMode = navigationModeController.addListener(this); + mBroadcastDispatcher = broadcastDispatcher; } // ----- Fragment Lifecycle Callbacks ----- @@ -299,6 +306,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback @Override public void onDestroy() { super.onDestroy(); + mNavigationModeController.removeListener(this); mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener); mContentResolver.unregisterContentObserver(mMagnificationObserver); mContentResolver.unregisterContentObserver(mAssistContentObserver); @@ -337,7 +345,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_USER_SWITCHED); - getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); + mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, Handler.getMain(), + UserHandle.ALL); notifyNavigationBarScreenOn(); mOverviewProxyService.addCallback(mOverviewProxyListener); @@ -380,7 +389,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mNavigationBarView.getLightTransitionsController().destroy(getContext()); } mOverviewProxyService.removeCallback(mOverviewProxyListener); - getContext().unregisterReceiver(mBroadcastReceiver); + mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index fa4812dc4876..a1a47e1305f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -829,7 +829,11 @@ public class NavigationBarView extends FrameLayout implements mRecentsOnboarding.onNavigationModeChanged(mNavBarMode); getRotateSuggestionButton().onNavigationModeChanged(mNavBarMode); - mRegionSamplingHelper.start(mSamplingBounds); + if (isGesturalMode(mNavBarMode)) { + mRegionSamplingHelper.start(mSamplingBounds); + } else { + mRegionSamplingHelper.stop(); + } } public void setAccessibilityButtonState(final boolean visible, final boolean longClickable) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 86da10a4b970..cee1d5da42cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -68,6 +68,7 @@ import com.android.systemui.DejankUtils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.plugins.FalsingManager; @@ -459,8 +460,9 @@ public class NotificationPanelView extends PanelView implements DynamicPrivacyController dynamicPrivacyController, KeyguardBypassController bypassController, FalsingManager falsingManager, - PluginManager pluginManager) { - super(context, attrs); + PluginManager pluginManager, + DozeLog dozeLog) { + super(context, attrs, falsingManager, dozeLog); setWillNotDraw(!DEBUG); mInjectionInflationController = injectionInflationController; mFalsingManager = falsingManager; @@ -652,8 +654,7 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.setLayoutParams(lp); } int sideMargin = res.getDimensionPixelOffset(R.dimen.notification_side_paddings); - int topMargin = - res.getDimensionPixelOffset(com.android.internal.R.dimen.quick_qs_total_height); + int topMargin = sideMargin; lp = (FrameLayout.LayoutParams) mPluginFrame.getLayoutParams(); if (lp.width != qsWidth || lp.gravity != panelGravity || lp.leftMargin != sideMargin || lp.rightMargin != sideMargin || lp.topMargin != topMargin) { @@ -796,6 +797,7 @@ public class NotificationPanelView extends PanelView implements int oldMaxHeight = mQsMaxExpansionHeight; if (mQs != null) { mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight(); + mNPVPluginManager.setYOffset(mQsMinExpansionHeight); mQsMinExpansionHeight += mNPVPluginManager.getHeight(); mQsMaxExpansionHeight = mQs.getDesiredHeight(); mNotificationStackScroller.setMaxTopPadding( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index ffaf3d5b83ae..432d63648cfe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -111,6 +111,7 @@ public abstract class PanelView extends FrameLayout { private FlingAnimationUtils mFlingAnimationUtilsClosing; private FlingAnimationUtils mFlingAnimationUtilsDismissing; private final FalsingManager mFalsingManager; + private final DozeLog mDozeLog; private final VibratorHelper mVibratorHelper; /** @@ -204,7 +205,8 @@ public abstract class PanelView extends FrameLayout { mJustPeeked = true; } - public PanelView(Context context, AttributeSet attrs) { + public PanelView(Context context, AttributeSet attrs, FalsingManager falsingManager, + DozeLog dozeLog) { super(context, attrs); mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f /* maxLengthSeconds */, 0.6f /* speedUpFactor */); @@ -214,7 +216,8 @@ public abstract class PanelView extends FrameLayout { 0.5f /* maxLengthSeconds */, 0.2f /* speedUpFactor */, 0.6f /* x2 */, 0.84f /* y2 */); mBounceInterpolator = new BounceInterpolator(); - mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller. + mFalsingManager = falsingManager; + mDozeLog = dozeLog; mNotificationsDragEnabled = getResources().getBoolean(R.bool.config_enableNotificationShadeDrag); mVibratorHelper = Dependency.get(VibratorHelper.class); @@ -477,7 +480,7 @@ public abstract class PanelView extends FrameLayout { boolean expand = flingExpands(vel, vectorVel, x, y) || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel; - DozeLog.traceFling(expand, mTouchAboveFalsingThreshold, + mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold, mStatusBar.isFalsingThresholdNeeded(), mStatusBar.isWakeUpComingFromTouch()); // Log collapse gesture if on lock screen. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java index c1ff572bb210..1a6b415f87db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java @@ -127,6 +127,11 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener, updateSamplingListener(); } + void stopAndDestroy() { + stop(); + mSamplingListener.destroy(); + } + @Override public void onViewAttachedToWindow(View view) { updateSamplingListener(); @@ -134,9 +139,7 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener, @Override public void onViewDetachedFromWindow(View view) { - // isAttachedToWindow is only changed after this call to the listeners, so let's post it - // instead - postUpdateSamplingListener(); + stopAndDestroy(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 377d13860185..81501615ae2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -147,10 +147,12 @@ import com.android.systemui.SystemUIFactory; import com.android.systemui.UiOffloadThread; import com.android.systemui.appops.AppOpsController; import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.charging.WirelessChargingAnimation; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.doze.DozeEvent; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.doze.DozeReceiver; @@ -223,7 +225,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.KeyguardStateControllerImpl; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; @@ -370,6 +371,8 @@ public class StatusBar extends SystemUI implements DemoMode, protected StatusBarIconController mIconController; @Inject + DozeLog mDozeLog; + @Inject InjectionInflationController mInjectionInflater; @Inject PulseExpansionHandler mPulseExpansionHandler; @@ -394,6 +397,9 @@ public class StatusBar extends SystemUI implements DemoMode, @Inject protected NotifPipelineInitializer mNotifPipelineInitializer; + @VisibleForTesting + BroadcastDispatcher mBroadcastDispatcher; + // expanded notifications protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window @@ -668,6 +674,7 @@ public class StatusBar extends SystemUI implements DemoMode, mBubbleController = Dependency.get(BubbleController.class); mBubbleController.setExpandListener(mBubbleExpandListener); mActivityIntentHelper = new ActivityIntentHelper(mContext); + mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class); KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance(); if (sliceProvider != null) { sliceProvider.initDependencies(mMediaManager, mStatusBarStateController, @@ -964,7 +971,8 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardStateController); mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf, mHeadsUpManager, mNotificationIconAreaController, mScrimController); - mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context)); + mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context), + mDozeLog); BackDropView backdrop = mStatusBarWindow.findViewById(R.id.backdrop); mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front), @@ -1049,11 +1057,7 @@ public class StatusBar extends SystemUI implements DemoMode, } // receive broadcasts - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG); - context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); + registerBroadcastReceiver(); IntentFilter demoFilter = new IntentFilter(); if (DEBUG_MEDIA_FAKE_ARTWORK) { @@ -1074,6 +1078,15 @@ public class StatusBar extends SystemUI implements DemoMode, ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f)); } + @VisibleForTesting + protected void registerBroadcastReceiver() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG); + mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, null, UserHandle.ALL); + } + protected QS createDefaultQSFragment() { return FragmentHostManager.get(mStatusBarWindow).create(QSFragment.class); } @@ -2368,7 +2381,7 @@ public class StatusBar extends SystemUI implements DemoMode, final boolean lightWpTheme = mContext.getThemeResId() == R.style.Theme_SystemUI_Light; pw.println(" light wallpaper theme: " + lightWpTheme); - DozeLog.dump(pw); + mDozeLog.dump(pw); if (mBiometricUnlockController != null) { mBiometricUnlockController.dump(pw); @@ -3994,7 +4007,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void startDozing() { if (!mDozingRequested) { mDozingRequested = true; - DozeLog.traceDozing(mContext, mDozing); + mDozeLog.traceDozing(mDozing); updateDozing(); updateIsKeyguard(); } @@ -4002,22 +4015,22 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) { - if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) { + if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) { mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:LONG_PRESS"); startAssist(new Bundle()); return; } - if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { mScrimController.setWakeLockScreenSensorActive(true); } - if (reason == DozeLog.PULSE_REASON_DOCKING && mStatusBarWindow != null) { + if (reason == DozeEvent.PULSE_REASON_DOCKING && mStatusBarWindow != null) { mStatusBarWindow.suppressWakeUpGesture(true); } - boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN && mWakeLockScreenPerformsAuth; // Set the state to pulsing, so ScrimController will know what to do once we ask it to // execute the transition. The pulse callback will then be invoked when the scrims @@ -4068,7 +4081,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void stopDozing() { if (mDozingRequested) { mDozingRequested = false; - DozeLog.traceDozing(mContext, mDozing); + mDozeLog.traceDozing(mDozing); updateDozing(); } } @@ -4076,7 +4089,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onIgnoreTouchWhilePulsing(boolean ignore) { if (ignore != mIgnoreTouchWhilePulsing) { - DozeLog.tracePulseTouchDisabledByProx(mContext, ignore); + mDozeLog.tracePulseTouchDisabledByProx(ignore); } mIgnoreTouchWhilePulsing = ignore; if (isDozing() && ignore) { @@ -4120,7 +4133,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void extendPulse(int reason) { - if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { mScrimController.setWakeLockScreenSensorActive(true); } if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java index 5bda34d64b73..ce929b7c621b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java @@ -28,6 +28,7 @@ import android.view.WindowManager.LayoutParams; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -138,20 +139,21 @@ public class SystemUIDialog extends AlertDialog { private final Dialog mDialog; private boolean mRegistered; + private final BroadcastDispatcher mBroadcastDispatcher; DismissReceiver(Dialog dialog) { mDialog = dialog; + mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class); } void register() { - mDialog.getContext() - .registerReceiverAsUser(this, UserHandle.CURRENT, INTENT_FILTER, null, null); + mBroadcastDispatcher.registerReceiver(this, INTENT_FILTER, null, UserHandle.CURRENT); mRegistered = true; } void unregister() { if (mRegistered) { - mDialog.getContext().unregisterReceiver(this); + mBroadcastDispatcher.unregisterReceiver(this); mRegistered = false; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index 111cdd2cc32a..738d076e13c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -45,9 +45,7 @@ public interface BatteryController extends DemoMode, Dumpable, /** * Returns {@code true} if AOD was disabled by power saving policies. */ - default boolean isAodPowerSave() { - return isPowerSave(); - } + boolean isAodPowerSave(); /** * A listener that will be notified whenever a change in battery level or power save mode has diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index c2c3f81527e8..b331fc3bf0ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.policy; +import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; + import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -44,6 +46,7 @@ import com.android.systemui.Dependency; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.settings.CurrentUserTracker; @@ -60,6 +63,9 @@ import java.util.Calendar; import java.util.Locale; import java.util.TimeZone; +import javax.inject.Inject; +import javax.inject.Named; + /** * Digital clock for the status bar. */ @@ -107,15 +113,20 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C */ private int mNonAdaptedColor; - public Clock(Context context) { - this(context, null); - } + private final BroadcastDispatcher mBroadcastDispatcher; public Clock(Context context, AttributeSet attrs) { - this(context, attrs, 0); + this(context, attrs, null); + } + + @Inject + public Clock(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, + BroadcastDispatcher broadcastDispatcher) { + this(context, attrs, 0, broadcastDispatcher); } - public Clock(Context context, AttributeSet attrs, int defStyle) { + public Clock(Context context, AttributeSet attrs, int defStyle, + BroadcastDispatcher broadcastDispatcher) { super(context, attrs, defStyle); TypedArray a = context.getTheme().obtainStyledAttributes( attrs, @@ -134,6 +145,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C mCurrentUserId = newUserId; } }; + mBroadcastDispatcher = broadcastDispatcher; } @Override @@ -358,11 +370,11 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C } IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); - mContext.registerReceiver(mScreenReceiver, filter); + mBroadcastDispatcher.registerReceiver(mScreenReceiver, filter); } } else { if (mSecondsHandler != null) { - mContext.unregisterReceiver(mScreenReceiver); + mBroadcastDispatcher.unregisterReceiver(mScreenReceiver); mSecondsHandler.removeCallbacks(mSecondTick); mSecondsHandler = null; updateClock(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index f8c7532ec281..cc91bc082871 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -101,7 +101,9 @@ public class KeyguardStateControllerImpl extends KeyguardUpdateMonitorCallback @Override public void addCallback(@NonNull Callback callback) { Preconditions.checkNotNull(callback, "Callback must not be null. b/128895449"); - mCallbacks.add(callback); + if (!mCallbacks.contains(callback)) { + mCallbacks.add(callback); + } if (mCallbacks.size() != 0 && !mListening) { mListening = true; mKeyguardUpdateMonitor.registerCallback(this); diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index e44e58a84dc8..7e801da9cd1b 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -37,6 +37,7 @@ import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.LockIcon; import com.android.systemui.statusbar.phone.NotificationPanelView; +import com.android.systemui.statusbar.policy.Clock; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -178,6 +179,11 @@ public class InjectionInflationController { * Creates the QSCustomizer. */ QSCustomizer createQSCustomizer(); + + /** + * Creates a Clock. + */ + Clock createClock(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index a6b5b38fd728..edea92f5952a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -59,6 +59,7 @@ import com.android.settingslib.volume.MediaSessions; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.qs.tiles.DndTile; @@ -137,9 +138,10 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private UserActivityListener mUserActivityListener; protected final VC mVolumeController = new VC(); + protected final BroadcastDispatcher mBroadcastDispatcher; @Inject - public VolumeDialogControllerImpl(Context context) { + public VolumeDialogControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher) { mContext = context.getApplicationContext(); mNotificationManager = (NotificationManager) mContext.getSystemService( Context.NOTIFICATION_SERVICE); @@ -152,6 +154,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); mObserver = new SettingObserver(mWorker); + mBroadcastDispatcher = broadcastDispatcher; mObserver.init(); mReceiver.init(); mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); @@ -1004,11 +1007,11 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - mContext.registerReceiver(this, filter, null, mWorker); + mBroadcastDispatcher.registerReceiver(this, filter, mWorker); } public void destroy() { - mContext.unregisterReceiver(this); + mBroadcastDispatcher.unregisterReceiver(this); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt index 011c2cd57588..e838d9e94a31 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt @@ -70,6 +70,8 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { private lateinit var mockContext: Context @Mock private lateinit var mockHandler: Handler + @Mock + private lateinit var mPendingResult: BroadcastReceiver.PendingResult @Captor private lateinit var argumentCaptor: ArgumentCaptor<IntentFilter> @@ -88,6 +90,7 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { universalBroadcastReceiver = UserBroadcastDispatcher( mockContext, USER_ID, handler, testableLooper.looper) + universalBroadcastReceiver.pendingResult = mPendingResult } @Test @@ -227,4 +230,19 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { verify(broadcastReceiver).onReceive(mockContext, intent) verify(broadcastReceiverOther).onReceive(mockContext, intent) } + + @Test + fun testPendingResult() { + intentFilter = IntentFilter(ACTION_1) + universalBroadcastReceiver.registerReceiver( + ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) + + val intent = Intent(ACTION_1) + universalBroadcastReceiver.onReceive(mockContext, intent) + + testableLooper.processAllMessages() + + verify(broadcastReceiver).onReceive(mockContext, intent) + verify(broadcastReceiver).pendingResult = mPendingResult + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 448c80ef3c57..2798c6b56771 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -74,6 +74,7 @@ import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBarWindowController; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; @@ -174,7 +175,8 @@ public class BubbleControllerTest extends SysuiTestCase { TestableNotificationInterruptionStateProvider interruptionStateProvider = new TestableNotificationInterruptionStateProvider(mContext, mock(NotificationFilter.class), - mock(StatusBarStateController.class)); + mock(StatusBarStateController.class), + mock(BatteryController.class)); interruptionStateProvider.setUpWithPresenter( mock(NotificationPresenter.class), mock(HeadsUpManager.class), @@ -660,8 +662,9 @@ public class BubbleControllerTest extends SysuiTestCase { NotificationInterruptionStateProvider { TestableNotificationInterruptionStateProvider(Context context, - NotificationFilter filter, StatusBarStateController controller) { - super(context, filter, controller); + NotificationFilter filter, StatusBarStateController controller, + BatteryController batteryController) { + super(context, filter, controller, batteryController); mUseHeadsUp = true; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java index af2de1be1d57..1ce01729f2e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java @@ -43,7 +43,6 @@ import com.android.systemui.dock.DockManagerFake; import com.android.systemui.doze.DozeMachine.State; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -58,12 +57,6 @@ public class DozeDockHandlerTest extends SysuiTestCase { private Instrumentation mInstrumentation; private DockManagerFake mDockManagerFake; - @BeforeClass - public static void setupSuite() { - // We can't use KeyguardUpdateMonitor from tests. - DozeLog.setRegisterKeyguardCallback(false); - } - @Before public void setUp() throws Exception { mInstrumentation = InstrumentationRegistry.getInstrumentation(); @@ -95,7 +88,7 @@ public class DozeDockHandlerTest extends SysuiTestCase { mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED); - verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING)); + verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING)); } @Test @@ -105,14 +98,14 @@ public class DozeDockHandlerTest extends SysuiTestCase { mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED); - verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING)); + verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING)); } @Test public void testOnEvent_dockedHideWhenPulsing_requestPulseOut() { mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED); when(mMachine.getState()).thenReturn(State.DOZE_PULSING); - when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING); + when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING); mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE); @@ -123,7 +116,7 @@ public class DozeDockHandlerTest extends SysuiTestCase { public void testOnEvent_undockedWhenPulsing_requestPulseOut() { mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED); when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING); - when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING); + when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING); mDockManagerFake.setDockEvent(DockManager.STATE_NONE); @@ -161,7 +154,7 @@ public class DozeDockHandlerTest extends SysuiTestCase { TestableLooper.get(this).processAllMessages(); - verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING)); + verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING)); } @Test @@ -174,7 +167,7 @@ public class DozeDockHandlerTest extends SysuiTestCase { TestableLooper.get(this).processAllMessages(); - verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING)); + verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING)); } @Test @@ -186,7 +179,7 @@ public class DozeDockHandlerTest extends SysuiTestCase { mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE); - verify(mMachine, never()).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING)); + verify(mMachine, never()).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING)); } @Test @@ -205,7 +198,7 @@ public class DozeDockHandlerTest extends SysuiTestCase { public void testTransitionToPulsing_whenDockedHide_requestPulseOut() { mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED); when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING); - when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING); + when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING); mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE); mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_PULSING); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index 1e18e51bc079..bbd2ab12099f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -46,6 +46,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.util.wakelock.WakeLockFake; import org.junit.Before; @@ -63,6 +64,8 @@ public class DozeMachineTest extends SysuiTestCase { @Mock private WakefulnessLifecycle mWakefulnessLifecycle; + @Mock + private DozeLog mDozeLog; private DozeServiceFake mServiceFake; private WakeLockFake mWakeLockFake; private AmbientDisplayConfiguration mConfigMock; @@ -76,8 +79,8 @@ public class DozeMachineTest extends SysuiTestCase { mConfigMock = mock(AmbientDisplayConfiguration.class); mPartMock = mock(DozeMachine.Part.class); - mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake, mWakefulnessLifecycle); - + mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake, + mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog); mMachine.setParts(new DozeMachine.Part[]{mPartMock}); } @@ -112,7 +115,7 @@ public class DozeMachineTest extends SysuiTestCase { public void testPulseDone_goesToDoze() { when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); mMachine.requestState(INITIALIZED); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); @@ -125,7 +128,7 @@ public class DozeMachineTest extends SysuiTestCase { public void testPulseDone_goesToAoD() { when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); mMachine.requestState(INITIALIZED); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); @@ -169,7 +172,7 @@ public class DozeMachineTest extends SysuiTestCase { public void testWakeLock_heldInPulseStates() { mMachine.requestState(INITIALIZED); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); assertTrue(mWakeLockFake.isHeld()); mMachine.requestState(DOZE_PULSING); @@ -192,7 +195,7 @@ public class DozeMachineTest extends SysuiTestCase { mMachine.requestState(INITIALIZED); mMachine.requestState(DOZE); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); @@ -204,9 +207,9 @@ public class DozeMachineTest extends SysuiTestCase { mMachine.requestState(INITIALIZED); mMachine.requestState(DOZE); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSE_DONE); } @@ -215,7 +218,7 @@ public class DozeMachineTest extends SysuiTestCase { mMachine.requestState(INITIALIZED); mMachine.requestState(DOZE); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSE_DONE); } @@ -228,7 +231,7 @@ public class DozeMachineTest extends SysuiTestCase { return null; }).when(mPartMock).transitionTo(any(), eq(DOZE_REQUEST_PULSE)); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); assertEquals(DOZE_PULSING, mMachine.getState()); } @@ -237,9 +240,9 @@ public class DozeMachineTest extends SysuiTestCase { public void testPulseReason_getMatchesRequest() { mMachine.requestState(INITIALIZED); mMachine.requestState(DOZE); - mMachine.requestPulse(DozeLog.REASON_SENSOR_DOUBLE_TAP); + mMachine.requestPulse(DozeEvent.REASON_SENSOR_DOUBLE_TAP); - assertEquals(DozeLog.REASON_SENSOR_DOUBLE_TAP, mMachine.getPulseReason()); + assertEquals(DozeEvent.REASON_SENSOR_DOUBLE_TAP, mMachine.getPulseReason()); } @Test @@ -251,7 +254,7 @@ public class DozeMachineTest extends SysuiTestCase { if (newState == DOZE_REQUEST_PULSE || newState == DOZE_PULSING || newState == DOZE_PULSE_DONE) { - assertEquals(DozeLog.PULSE_REASON_NOTIFICATION, mMachine.getPulseReason()); + assertEquals(DozeEvent.PULSE_REASON_NOTIFICATION, mMachine.getPulseReason()); } else { assertTrue("unexpected state " + newState, newState == DOZE || newState == DOZE_AOD); @@ -259,7 +262,7 @@ public class DozeMachineTest extends SysuiTestCase { return null; }).when(mPartMock).transitionTo(any(), any()); - mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index ddd1685bf8bc..f2665ef3c845 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -78,6 +78,8 @@ public class DozeSensorsTest extends SysuiTestCase { private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy; @Mock private TriggerSensor mTriggerSensor; + @Mock + private DozeLog mDozeLog; private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener; private TestableLooper mTestableLooper; private DozeSensors mDozeSensors; @@ -101,14 +103,14 @@ public class DozeSensorsTest extends SysuiTestCase { mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); mTestableLooper.processAllMessages(); - verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + verify(mCallback).onSensorPulse(eq(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), anyFloat(), anyFloat(), eq(null)); mDozeSensors.requestTemporaryDisable(); reset(mCallback); mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); mTestableLooper.processAllMessages(); - verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + verify(mCallback, never()).onSensorPulse(eq(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), anyFloat(), anyFloat(), eq(null)); } @@ -146,7 +148,7 @@ public class DozeSensorsTest extends SysuiTestCase { TestableDozeSensors() { super(getContext(), mAlarmManager, mSensorManager, mDozeParameters, mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback, - mAlwaysOnDisplayPolicy); + mAlwaysOnDisplayPolicy, mDozeLog); for (TriggerSensor sensor : mSensors) { if (sensor instanceof PluginSensor && ((PluginSensor) sensor).mPluginSensor.getType() diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index b0e3969bf8a4..e5ae6d50c3e5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -48,7 +48,6 @@ import com.android.systemui.util.wakelock.WakeLock; import com.android.systemui.util.wakelock.WakeLockFake; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,12 +63,6 @@ public class DozeTriggersTest extends SysuiTestCase { private DockManager mDockManagerFake; private FakeProximitySensor mProximitySensor; - @BeforeClass - public static void setupSuite() { - // We can't use KeyguardUpdateMonitor from tests. - DozeLog.setRegisterKeyguardCallback(false); - } - @Before public void setUp() throws Exception { mMachine = mock(DozeMachine.class); @@ -87,7 +80,7 @@ public class DozeTriggersTest extends SysuiTestCase { mTriggers = new DozeTriggers(mContext, mMachine, mHost, alarmManager, config, parameters, asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true, - mDockManagerFake, mProximitySensor); + mDockManagerFake, mProximitySensor, mock(DozeLog.class)); waitForSensorManager(); } @@ -148,9 +141,10 @@ public class DozeTriggersTest extends SysuiTestCase { @Test public void testProximitySensorNotAvailablel() { mProximitySensor.setSensorAvailable(false); - mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null); - mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, 100, 100, new float[]{1}); - mTriggers.onSensor(DozeLog.REASON_SENSOR_TAP, 100, 100, null); + mTriggers.onSensor(DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null); + mTriggers.onSensor(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, 100, 100, + new float[]{1}); + mTriggers.onSensor(DozeEvent.REASON_SENSOR_TAP, 100, 100, null); } private void waitForSensorManager() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java index 25231bcbc1c4..c5bddc1f096f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java @@ -65,6 +65,8 @@ public class DozeUiTest extends SysuiTestCase { private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock private DozeHost mHost; + @Mock + private DozeLog mDozeLog; private WakeLockFake mWakeLock; private Handler mHandler; private HandlerThread mHandlerThread; @@ -80,7 +82,7 @@ public class DozeUiTest extends SysuiTestCase { mHandler = mHandlerThread.getThreadHandler(); mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler, - mDozeParameters, mKeyguardUpdateMonitor); + mDozeParameters, mKeyguardUpdateMonitor, mDozeLog); } @After @@ -135,7 +137,7 @@ public class DozeUiTest extends SysuiTestCase { reset(mHost); when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true); mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler, - mDozeParameters, mKeyguardUpdateMonitor); + mDozeParameters, mKeyguardUpdateMonitor, mDozeLog); // Never animate if display doesn't support it. mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java new file mode 100644 index 000000000000..2f90641775e8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 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 com.android.systemui.log; + +import static junit.framework.Assert.assertEquals; + +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import junit.framework.Assert; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class RichEventTest extends SysuiTestCase { + + private static final int TOTAL_EVENT_TYPES = 1; + + @Test + public void testCreateRichEvent_invalidType() { + try { + // indexing for events starts at 0, so TOTAL_EVENT_TYPES is an invalid type + new TestableRichEvent(Event.DEBUG, TOTAL_EVENT_TYPES, "msg"); + } catch (IllegalArgumentException e) { + // expected + return; + } + + Assert.fail("Expected an invalidArgumentException since the event type was invalid."); + } + + @Test + public void testCreateRichEvent() { + final int eventType = 0; + RichEvent e = new TestableRichEvent(Event.DEBUG, eventType, "msg"); + assertEquals(e.getType(), eventType); + } + + class TestableRichEvent extends RichEvent { + TestableRichEvent(int logLevel, int type, String reason) { + super(logLevel, type, reason); + } + + @Override + public String[] getEventLabels() { + return new String[]{"ACTION_NAME"}; + } + } + +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java new file mode 100644 index 000000000000..378bba1afda3 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2019 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 com.android.systemui.log; + +import static junit.framework.Assert.assertEquals; + +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.DumpController; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class SysuiLogTest extends SysuiTestCase { + private static final String TEST_ID = "TestLogger"; + private static final int MAX_LOGS = 5; + + @Mock + private DumpController mDumpController; + private SysuiLog mSysuiLog; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testLogDisabled_noLogsWritten() { + mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false); + assertEquals(mSysuiLog.mTimeline, null); + + mSysuiLog.log(new Event("msg")); + assertEquals(mSysuiLog.mTimeline, null); + } + + @Test + public void testLogEnabled_logWritten() { + mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true); + assertEquals(mSysuiLog.mTimeline.size(), 0); + + mSysuiLog.log(new Event("msg")); + assertEquals(mSysuiLog.mTimeline.size(), 1); + } + + @Test + public void testMaxLogs() { + mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true); + assertEquals(mSysuiLog.mTimeline.size(), 0); + + final String msg = "msg"; + for (int i = 0; i < MAX_LOGS + 1; i++) { + mSysuiLog.log(new Event(msg + i)); + } + + assertEquals(mSysuiLog.mTimeline.size(), MAX_LOGS); + + // check the first message (msg0) is deleted: + assertEquals(mSysuiLog.mTimeline.getFirst().getMessage(), msg + "1"); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java index 4d95f3f474b5..4958c649d532 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java @@ -19,6 +19,7 @@ import static android.provider.Settings.Global.SHOW_USB_TEMPERATURE_ALARM; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.anyObject; import static org.mockito.Mockito.mock; @@ -27,8 +28,11 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.IntentFilter; import android.os.BatteryManager; +import android.os.Handler; import android.os.IThermalEventListener; import android.os.IThermalService; import android.os.PowerManager; @@ -43,6 +47,7 @@ import android.testing.TestableResources; import com.android.settingslib.fuelgauge.Estimate; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.power.PowerUI.WarningsUI; import com.android.systemui.statusbar.phone.StatusBar; @@ -80,6 +85,7 @@ public class PowerUITest extends SysuiTestCase { @Mock private IThermalService mThermalServiceMock; private IThermalEventListener mUsbThermalEventListener; private IThermalEventListener mSkinThermalEventListener; + @Mock private BroadcastDispatcher mBroadcastDispatcher; @Before public void setup() { @@ -96,6 +102,15 @@ public class PowerUITest extends SysuiTestCase { } @Test + public void testReceiverIsRegisteredToDispatcherOnStart() { + mPowerUI.start(); + verify(mBroadcastDispatcher).registerReceiver( + any(BroadcastReceiver.class), + any(IntentFilter.class), + any(Handler.class)); //PowerUI does not call with User + } + + @Test public void testSkinWarning_throttlingCritical() throws Exception { mPowerUI.start(); @@ -667,7 +682,7 @@ public class PowerUITest extends SysuiTestCase { } private void createPowerUi() { - mPowerUI = new PowerUI(); + mPowerUI = new PowerUI(mBroadcastDispatcher); mPowerUI.mContext = mContext; mPowerUI.mComponents = mContext.getComponents(); mPowerUI.mThermalService = mThermalServiceMock; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java index 350ab5afdf95..28a7e408e908 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java @@ -52,6 +52,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.HeadsUpManager; import org.junit.Before; @@ -84,6 +85,8 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { HeadsUpManager mHeadsUpManager; @Mock NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor; + @Mock + BatteryController mBatteryController; private NotificationInterruptionStateProvider mNotifInterruptionStateProvider; @@ -97,7 +100,8 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter, - mStatusBarStateController); + mStatusBarStateController, + mBatteryController); mNotifInterruptionStateProvider.setUpWithPresenter( mPresenter, @@ -590,17 +594,17 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { /** * Testable class overriding constructor. */ - public class TestableNotificationInterruptionStateProvider extends + public static class TestableNotificationInterruptionStateProvider extends NotificationInterruptionStateProvider { TestableNotificationInterruptionStateProvider(Context context, PowerManager powerManager, IDreamManager dreamManager, AmbientDisplayConfiguration ambientDisplayConfiguration, NotificationFilter notificationFilter, - StatusBarStateController statusBarStateController) { + StatusBarStateController statusBarStateController, + BatteryController batteryController) { super(context, powerManager, dreamManager, ambientDisplayConfiguration, - notificationFilter, - statusBarStateController); + notificationFilter, batteryController, statusBarStateController); } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java index 20c739ff579e..1ce336e5f37d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java @@ -27,6 +27,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.doze.DozeHost; +import com.android.systemui.doze.DozeLog; import org.junit.Before; import org.junit.Test; @@ -41,12 +42,14 @@ public class DozeScrimControllerTest extends SysuiTestCase { @Mock private DozeParameters mDozeParameters; + @Mock + private DozeLog mDozeLog; private DozeScrimController mDozeScrimController; @Before public void setup() { MockitoAnnotations.initMocks(this); - mDozeScrimController = new DozeScrimController(mDozeParameters); + mDozeScrimController = new DozeScrimController(mDozeParameters, mDozeLog); mDozeScrimController.setDozing(true); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index 33d3ac848f0f..0bff5aa9e991 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -24,9 +24,11 @@ import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.LayoutRes; @@ -34,11 +36,14 @@ import android.annotation.Nullable; import android.app.Fragment; import android.app.FragmentController; import android.app.FragmentHostCallback; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.IntentFilter; import android.hardware.display.DisplayManagerGlobal; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.testing.LeakCheck.Tracker; import android.testing.TestableLooper; @@ -58,6 +63,7 @@ import com.android.systemui.Dependency; import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.SysuiTestableContext; import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; @@ -70,6 +76,8 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @RunWithLooper() @@ -85,6 +93,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { private OverviewProxyService mOverviewProxyService; private CommandQueue mCommandQueue; private SysUiState mMockSysUiState; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; private AccessibilityManagerWrapper mAccessibilityWrapper = new AccessibilityManagerWrapper(mContext) { @@ -112,6 +122,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { @Before public void setupFragment() throws Exception { + MockitoAnnotations.initMocks(this); + setupSysuiDependency(); createRootView(); mOverviewProxyService = @@ -177,6 +189,18 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { } @Test + public void testRegisteredWithDispatcher() { + mFragments.dispatchResume(); + processAllMessages(); + + verify(mBroadcastDispatcher).registerReceiver( + any(BroadcastReceiver.class), + any(IntentFilter.class), + any(Handler.class), + any(UserHandle.class)); + } + + @Test public void testSetImeWindowStatusWhenImeSwitchOnDisplay() { // Create default & external NavBar fragment. NavigationBarFragment defaultNavBar = (NavigationBarFragment) mFragment; @@ -227,7 +251,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { mOverviewProxyService, mock(NavigationModeController.class), mock(StatusBarStateController.class), - mMockSysUiState); + mMockSysUiState, + mBroadcastDispatcher); } private class HostCallbacksForExternalDisplay extends diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 219aef1ec685..b5ef716904df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -40,6 +40,7 @@ import com.android.keyguard.KeyguardStatusView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; +import com.android.systemui.doze.DozeLog; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.plugins.PluginManager; @@ -216,7 +217,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { SystemUIFactory.getInstance().getRootComponent()), coordinator, expansionHandler, mock(DynamicPrivacyController.class), bypassController, - mFalsingManager, mock(PluginManager.class)); + mFalsingManager, mock(PluginManager.class), mock(DozeLog.class)); mNotificationStackScroller = mNotificationStackScrollLayout; mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView; mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 3be71c07009d..32b0f76b2441 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -41,7 +41,9 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.app.StatusBarManager; import android.app.trust.TrustManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.IntentFilter; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.fingerprint.FingerprintManager; import android.metrics.LogMaker; @@ -51,6 +53,7 @@ import android.os.IPowerManager; import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; +import android.os.UserHandle; import android.service.dreams.IDreamManager; import android.support.test.metricshelper.MetricsAsserts; import android.testing.AndroidTestingRunner; @@ -75,9 +78,10 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.UiOffloadThread; import com.android.systemui.appops.AppOpsController; import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.doze.DozeEvent; import com.android.systemui.doze.DozeHost; -import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; @@ -109,6 +113,7 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -155,6 +160,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private NotificationRemoteInputManager mRemoteInputManager; @Mock private RemoteInputController mRemoteInputController; @Mock private StatusBarStateControllerImpl mStatusBarStateController; + @Mock private BatteryController mBatteryController; @Mock private DeviceProvisionedController mDeviceProvisionedController; @Mock private StatusBarNotificationPresenter mNotificationPresenter; @Mock @@ -171,6 +177,8 @@ public class StatusBarTest extends SysuiTestCase { private AmbientDisplayConfiguration mAmbientDisplayConfiguration; @Mock private StatusBarWindowView mStatusBarWindowView; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; private TestableStatusBar mStatusBar; private FakeMetricsLogger mMetricsLogger; @@ -199,6 +207,7 @@ public class StatusBarTest extends SysuiTestCase { mDependency.injectTestDependency(NotificationFilter.class, mNotificationFilter); mDependency.injectTestDependency(NotificationAlertingManager.class, mNotificationAlertingManager); + mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher); IPowerManager powerManagerService = mock(IPowerManager.class); mPowerManager = new PowerManager(mContext, powerManagerService, @@ -207,7 +216,7 @@ public class StatusBarTest extends SysuiTestCase { mNotificationInterruptionStateProvider = new TestableNotificationInterruptionStateProvider(mContext, mPowerManager, mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter, - mStatusBarStateController); + mStatusBarStateController, mBatteryController); mDependency.injectTestDependency(NotificationInterruptionStateProvider.class, mNotificationInterruptionStateProvider); mDependency.injectMockDependency(NavigationBarController.class); @@ -223,7 +232,6 @@ public class StatusBarTest extends SysuiTestCase { mExpansionStateLogger); mNotificationLogger.setVisibilityReporter(mock(Runnable.class)); mDependency.injectTestDependency(NotificationLogger.class, mNotificationLogger); - DozeLog.traceDozing(mContext, false /* dozing */); mCommandQueue = mock(CommandQueue.class); when(mCommandQueue.asBinder()).thenReturn(new Binder()); @@ -263,7 +271,8 @@ public class StatusBarTest extends SysuiTestCase { mDozeScrimController, mock(NotificationShelf.class), mLockscreenUserManager, mCommandQueue, mNotificationPresenter, mock(BubbleController.class), mock(NavigationBarController.class), - mock(AutoHideController.class), mKeyguardUpdateMonitor, mStatusBarWindowView); + mock(AutoHideController.class), mKeyguardUpdateMonitor, mStatusBarWindowView, + mBroadcastDispatcher); mStatusBar.mContext = mContext; mStatusBar.mComponents = mContext.getComponents(); SystemUIFactory.getInstance().getRootComponent() @@ -644,7 +653,7 @@ public class StatusBarTest extends SysuiTestCase { // Starting a pulse should change the scrim controller to the pulsing state mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), - DozeLog.PULSE_REASON_NOTIFICATION); + DozeEvent.PULSE_REASON_NOTIFICATION); verify(mScrimController).transitionTo(eq(ScrimState.PULSING), any()); // Ending a pulse should take it back to keyguard state @@ -655,21 +664,21 @@ public class StatusBarTest extends SysuiTestCase { @Test public void testPulseWhileDozing_notifyAuthInterrupt() { HashSet<Integer> reasonsWantingAuth = new HashSet<>( - Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN)); + Collections.singletonList(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN)); HashSet<Integer> reasonsSkippingAuth = new HashSet<>( - Arrays.asList(DozeLog.PULSE_REASON_INTENT, - DozeLog.PULSE_REASON_NOTIFICATION, - DozeLog.PULSE_REASON_SENSOR_SIGMOTION, - DozeLog.REASON_SENSOR_PICKUP, - DozeLog.REASON_SENSOR_DOUBLE_TAP, - DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, - DozeLog.PULSE_REASON_DOCKING, - DozeLog.REASON_SENSOR_WAKE_UP, - DozeLog.REASON_SENSOR_TAP)); + Arrays.asList(DozeEvent.PULSE_REASON_INTENT, + DozeEvent.PULSE_REASON_NOTIFICATION, + DozeEvent.PULSE_REASON_SENSOR_SIGMOTION, + DozeEvent.REASON_SENSOR_PICKUP, + DozeEvent.REASON_SENSOR_DOUBLE_TAP, + DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, + DozeEvent.PULSE_REASON_DOCKING, + DozeEvent.REASON_SENSOR_WAKE_UP, + DozeEvent.REASON_SENSOR_TAP)); HashSet<Integer> reasonsThatDontPulse = new HashSet<>( - Arrays.asList(DozeLog.REASON_SENSOR_PICKUP, - DozeLog.REASON_SENSOR_DOUBLE_TAP, - DozeLog.REASON_SENSOR_TAP)); + Arrays.asList(DozeEvent.REASON_SENSOR_PICKUP, + DozeEvent.REASON_SENSOR_DOUBLE_TAP, + DozeEvent.REASON_SENSOR_TAP)); doAnswer(invocation -> { DozeHost.PulseCallback callback = invocation.getArgument(0); @@ -678,7 +687,7 @@ public class StatusBarTest extends SysuiTestCase { }).when(mDozeScrimController).pulse(any(), anyInt()); mStatusBar.mDozeServiceHost.mWakeLockScreenPerformsAuth = true; - for (int i = 0; i < DozeLog.REASONS; i++) { + for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) { reset(mKeyguardUpdateMonitor); mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), i); if (reasonsWantingAuth.contains(i)) { @@ -703,7 +712,7 @@ public class StatusBarTest extends SysuiTestCase { // Starting a pulse while docking should suppress wakeup gesture mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), - DozeLog.PULSE_REASON_DOCKING); + DozeEvent.PULSE_REASON_DOCKING); verify(mStatusBarWindowView).suppressWakeUpGesture(eq(true)); // Ending a pulse should restore wakeup gesture @@ -774,6 +783,16 @@ public class StatusBarTest extends SysuiTestCase { verify(mNotificationPanelView, never()).expand(anyBoolean()); } + @Test + public void testRegisterBroadcastsonDispatcher() { + mStatusBar.registerBroadcastReceiver(); + verify(mBroadcastDispatcher).registerReceiver( + any(BroadcastReceiver.class), + any(IntentFilter.class), + eq(null), + any(UserHandle.class)); + } + static class TestableStatusBar extends StatusBar { public TestableStatusBar(StatusBarKeyguardViewManager man, KeyguardIndicationController key, @@ -801,7 +820,8 @@ public class StatusBarTest extends SysuiTestCase { NavigationBarController navBarController, AutoHideController autoHideController, KeyguardUpdateMonitor keyguardUpdateMonitor, - StatusBarWindowView statusBarWindow) { + StatusBarWindowView statusBarWindow, + BroadcastDispatcher broadcastDispatcher) { mStatusBarKeyguardViewManager = man; mKeyguardIndicationController = key; mStackScroller = stack; @@ -835,6 +855,7 @@ public class StatusBarTest extends SysuiTestCase { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mStatusBarWindow = statusBarWindow; mDozeServiceHost.mWakeLockScreenPerformsAuth = false; + mBroadcastDispatcher = broadcastDispatcher; } private WakefulnessLifecycle createAwakeWakefulnessLifecycle() { @@ -887,9 +908,10 @@ public class StatusBarTest extends SysuiTestCase { IDreamManager dreamManager, AmbientDisplayConfiguration ambientDisplayConfiguration, NotificationFilter filter, - StatusBarStateController controller) { + StatusBarStateController controller, + BatteryController batteryController) { super(context, powerManager, dreamManager, ambientDisplayConfiguration, filter, - controller); + batteryController, controller); mUseHeadsUp = true; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java index a9a1392fb80b..589aa0353870 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java @@ -18,11 +18,9 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.content.BroadcastReceiver; -import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.testing.AndroidTestingRunner; @@ -31,11 +29,14 @@ import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -43,13 +44,16 @@ import org.mockito.ArgumentCaptor; public class SystemUIDialogTest extends SysuiTestCase { private SystemUIDialog mDialog; - - Context mContextSpy; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; @Before public void setup() { - mContextSpy = spy(mContext); - mDialog = new SystemUIDialog(mContextSpy); + MockitoAnnotations.initMocks(this); + + mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher); + + mDialog = new SystemUIDialog(mContext); } @Test @@ -60,12 +64,12 @@ public class SystemUIDialogTest extends SysuiTestCase { ArgumentCaptor.forClass(IntentFilter.class); mDialog.show(); - verify(mContextSpy).registerReceiverAsUser(broadcastReceiverCaptor.capture(), any(), - intentFilterCaptor.capture(), any(), any()); + verify(mBroadcastDispatcher).registerReceiver(broadcastReceiverCaptor.capture(), + intentFilterCaptor.capture(), eq(null), any()); assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); mDialog.dismiss(); - verify(mContextSpy).unregisterReceiver(eq(broadcastReceiverCaptor.getValue())); + verify(mBroadcastDispatcher).unregisterReceiver(eq(broadcastReceiverCaptor.getValue())); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java index a843cca498a0..df76f01494f3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBatteryController.java @@ -48,4 +48,9 @@ public class FakeBatteryController extends BaseLeakChecker<BatteryStateChangeCal public boolean isPowerSave() { return false; } + + @Override + public boolean isAodPowerSave() { + return false; + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java index f4d0854b2c9f..2e945f2481d2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java @@ -16,41 +16,64 @@ package com.android.systemui.volume; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.IntentFilter; import android.media.AudioManager; import android.media.session.MediaSession; +import android.os.Handler; +import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.statusbar.phone.StatusBar; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +@RunWith(AndroidTestingRunner.class) @SmallTest public class VolumeDialogControllerImplTest extends SysuiTestCase { TestableVolumeDialogControllerImpl mVolumeController; VolumeDialogControllerImpl.C mCallback; StatusBar mStatusBar; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; @Before public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + mCallback = mock(VolumeDialogControllerImpl.C.class); mStatusBar = mock(StatusBar.class); - mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar); + mVolumeController = new TestableVolumeDialogControllerImpl(mContext, mCallback, mStatusBar, + mBroadcastDispatcher); mVolumeController.setEnableDialogs(true, true); } @Test + public void testRegisteredWithDispatcher() { + verify(mBroadcastDispatcher).registerReceiver( + any(BroadcastReceiver.class), + any(IntentFilter.class), + any(Handler.class)); // VolumeDialogControllerImpl does not call with user + } + + @Test public void testVolumeChangeW_deviceNotInteractiveAOD() { when(mStatusBar.isDeviceInteractive()).thenReturn(false); when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE); @@ -81,7 +104,7 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase { public void testVolumeChangeW_nullStatusBar() { VolumeDialogControllerImpl.C callback = mock(VolumeDialogControllerImpl.C.class); TestableVolumeDialogControllerImpl nullStatusBarTestableDialog = new - TestableVolumeDialogControllerImpl(mContext, callback, null); + TestableVolumeDialogControllerImpl(mContext, callback, null, mBroadcastDispatcher); nullStatusBarTestableDialog.setEnableDialogs(true, true); nullStatusBarTestableDialog.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI); verify(callback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED); @@ -100,8 +123,9 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase { } static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl { - public TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s) { - super(context); + TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s, + BroadcastDispatcher broadcastDispatcher) { + super(context, broadcastDispatcher); mCallbacks = callback; mStatusBar = s; } diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index 8e200196050c..b35300ceb399 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -78,6 +78,8 @@ final class SaveUi { private static final int THEME_ID_DARK = com.android.internal.R.style.Theme_DeviceDefault_Autofill_Save; + private static final int SCROLL_BAR_DEFAULT_DELAY_BEFORE_FADE_MS = 500; + public interface OnSaveListener { void onSave(); void onCancel(IntentSender listener); @@ -252,6 +254,8 @@ final class SaveUi { new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); subtitleContainer.setVisibility(View.VISIBLE); + subtitleContainer.setScrollBarDefaultDelayBeforeFade( + SCROLL_BAR_DEFAULT_DELAY_BEFORE_FADE_MS); } if (sDebug) Slog.d(TAG, "on constructor: title=" + mTitle + ", subTitle=" + mSubTitle); } @@ -429,6 +433,9 @@ final class SaveUi { saveUiView.findViewById(R.id.autofill_save_custom_subtitle); subtitleContainer.addView(customSubtitleView); subtitleContainer.setVisibility(View.VISIBLE); + subtitleContainer.setScrollBarDefaultDelayBeforeFade( + SCROLL_BAR_DEFAULT_DELAY_BEFORE_FADE_MS); + return true; } catch (Exception e) { Slog.e(TAG, "Error applying custom description. ", e); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index f70d511759f0..34111a92b66e 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -197,7 +197,7 @@ class StorageManagerService extends IStorageManager.Stub "persist.sys.zram_enabled"; private static final boolean IS_FUSE_ENABLED = - SystemProperties.getBoolean("persist.sys.fuse", false); + SystemProperties.getBoolean(StorageManager.PROP_FUSE, false); private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage(); @@ -1526,6 +1526,9 @@ class StorageManagerService extends IStorageManager.Stub SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString( SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true))); + SystemProperties.set(StorageManager.PROP_FUSE_SNAPSHOT, Boolean.toString( + SystemProperties.getBoolean(StorageManager.PROP_FUSE, false))); + mContext = context; mResolver = mContext.getContentResolver(); @@ -1858,7 +1861,7 @@ class StorageManagerService extends IStorageManager.Stub // This means the mountUserId on such volumes is USER_NULL. This breaks fuse which // requires a valid user to mount a volume. Create individual volumes per user in vold // and remove this property check - int userId = SystemProperties.getBoolean("persist.sys.fuse", false) + int userId = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false) ? mCurrentUserId : vol.mountUserId; return mVold.mount(vol.id, vol.mountFlags, userId); } catch (Exception e) { diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index c412ebdc9033..ecbbef11b893 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -208,6 +208,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList; + private EmergencyNumber[] mOutgoingSmsEmergencyNumber; + + private EmergencyNumber[] mOutgoingCallEmergencyNumber; + private CallQuality[] mCallQuality; private CallAttributes[] mCallAttributes; @@ -266,6 +270,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { PhoneStateListener.LISTEN_PRECISE_CALL_STATE | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE; + static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK = + PhoneStateListener.LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER + | PhoneStateListener.LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER; + private static final int MSG_USER_SWITCHED = 1; private static final int MSG_UPDATE_DEFAULT_SUB = 2; @@ -406,6 +414,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mImsReasonInfo = new ArrayList<>(); mPhysicalChannelConfigs = new ArrayList<>(); mEmergencyNumberList = new HashMap<>(); + mOutgoingCallEmergencyNumber = new EmergencyNumber[numPhones]; + mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones]; for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -1193,7 +1203,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { public void notifyCarrierNetworkChange(boolean active) { // only CarrierService with carrier privilege rule should have the permission int[] subIds = Arrays.stream(SubscriptionManager.from(mContext) - .getActiveSubscriptionIdList()) + .getActiveSubscriptionIdList(false)) .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray(); if (ArrayUtils.isEmpty(subIds)) { loge("notifyCarrierNetworkChange without carrier privilege"); @@ -1910,6 +1920,56 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override + public void notifyOutgoingEmergencyCall(int phoneId, int subId, + EmergencyNumber emergencyNumber) { + if (!checkNotifyPermission("notifyOutgoingEmergencyCall()")) { + return; + } + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + mOutgoingCallEmergencyNumber[phoneId] = emergencyNumber; + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER) + && idMatch(r.subId, subId, phoneId)) { + try { + r.callback.onOutgoingEmergencyCall(emergencyNumber); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + + @Override + public void notifyOutgoingEmergencySms(int phoneId, int subId, + EmergencyNumber emergencyNumber) { + if (!checkNotifyPermission("notifyOutgoingEmergencySms()")) { + return; + } + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + mOutgoingSmsEmergencyNumber[phoneId] = emergencyNumber; + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER) + && idMatch(r.subId, subId, phoneId)) { + try { + r.callback.onOutgoingEmergencySms(emergencyNumber); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + + @Override public void notifyCallQualityChanged(CallQuality callQuality, int phoneId, int subId, int callNetworkType) { if (!checkNotifyPermission("notifyCallQualityChanged()")) { @@ -1981,6 +2041,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mCallAttributes=" + mCallAttributes[i]); pw.println("mCallNetworkType=" + mCallNetworkType[i]); pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState[i]); + pw.println("mOutgoingCallEmergencyNumber=" + mOutgoingCallEmergencyNumber[i]); + pw.println("mOutgoingSmsEmergencyNumber=" + mOutgoingSmsEmergencyNumber[i]); pw.decreaseIndent(); } pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState); @@ -2250,6 +2312,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { android.Manifest.permission.READ_PRECISE_PHONE_STATE, null); } + if ((events & READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK) != 0) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null); + } + if ((events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null); diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java index fd64df9e86e0..2081b177e2b2 100644 --- a/services/core/java/com/android/server/am/MemoryStatUtil.java +++ b/services/core/java/com/android/server/am/MemoryStatUtil.java @@ -39,8 +39,7 @@ import java.util.regex.Pattern; * Static utility methods related to {@link MemoryStat}. */ public final class MemoryStatUtil { - static final int BYTES_IN_KILOBYTE = 1024; - static final long JIFFY_NANOS = 1_000_000_000 / Os.sysconf(OsConstants._SC_CLK_TCK); + static final int PAGE_SIZE = (int) Os.sysconf(OsConstants._SC_PAGESIZE); private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM; @@ -52,10 +51,6 @@ public final class MemoryStatUtil { private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat"; /** Path to procfs stat file for logging app start memory state */ private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat"; - /** Path to procfs status file for logging app memory state */ - private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status"; - /** Path to procfs cmdline file. Used with pid: /proc/pid/cmdline. */ - private static final String PROC_CMDLINE_FILE_FMT = "/proc/%d/cmdline"; private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)"); private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)"); @@ -63,16 +58,9 @@ public final class MemoryStatUtil { private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)"); private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)"); - private static final Pattern PROCFS_RSS_IN_KILOBYTES = - Pattern.compile("VmRSS:\\s*(\\d+)\\s*kB"); - private static final Pattern PROCFS_ANON_RSS_IN_KILOBYTES = - Pattern.compile("RssAnon:\\s*(\\d+)\\s*kB"); - private static final Pattern PROCFS_SWAP_IN_KILOBYTES = - Pattern.compile("VmSwap:\\s*(\\d+)\\s*kB"); - private static final int PGFAULT_INDEX = 9; private static final int PGMAJFAULT_INDEX = 11; - private static final int START_TIME_INDEX = 21; + private static final int RSS_IN_PAGES_INDEX = 23; private MemoryStatUtil() {} @@ -106,19 +94,7 @@ public final class MemoryStatUtil { @Nullable public static MemoryStat readMemoryStatFromProcfs(int pid) { final String statPath = String.format(Locale.US, PROC_STAT_FILE_FMT, pid); - final String statusPath = String.format(Locale.US, PROC_STATUS_FILE_FMT, pid); - return parseMemoryStatFromProcfs(readFileContents(statPath), readFileContents(statusPath)); - } - - /** - * Reads cmdline of a process from procfs. - * - * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string - * if the file is not available. - */ - public static String readCmdlineFromProcfs(int pid) { - final String path = String.format(Locale.US, PROC_CMDLINE_FILE_FMT, pid); - return parseCmdlineFromProcfs(readFileContents(path)); + return parseMemoryStatFromProcfs(readFileContents(statPath)); } private static String readFileContents(String path) { @@ -160,31 +136,19 @@ public final class MemoryStatUtil { */ @VisibleForTesting @Nullable - static MemoryStat parseMemoryStatFromProcfs( - String procStatContents, String procStatusContents) { + static MemoryStat parseMemoryStatFromProcfs(String procStatContents) { if (procStatContents == null || procStatContents.isEmpty()) { return null; } - if (procStatusContents == null || procStatusContents.isEmpty()) { - return null; - } - final String[] splits = procStatContents.split(" "); if (splits.length < 24) { return null; } - try { final MemoryStat memoryStat = new MemoryStat(); memoryStat.pgfault = Long.parseLong(splits[PGFAULT_INDEX]); memoryStat.pgmajfault = Long.parseLong(splits[PGMAJFAULT_INDEX]); - memoryStat.rssInBytes = - tryParseLong(PROCFS_RSS_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE; - memoryStat.anonRssInBytes = - tryParseLong(PROCFS_ANON_RSS_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE; - memoryStat.swapInBytes = - tryParseLong(PROCFS_SWAP_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE; - memoryStat.startTimeNanos = Long.parseLong(splits[START_TIME_INDEX]) * JIFFY_NANOS; + memoryStat.rssInBytes = Long.parseLong(splits[RSS_IN_PAGES_INDEX]) * PAGE_SIZE; return memoryStat; } catch (NumberFormatException e) { Slog.e(TAG, "Failed to parse value", e); @@ -193,23 +157,6 @@ public final class MemoryStatUtil { } /** - * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs. - * - * Parsing is required to strip anything after first null byte. - */ - @VisibleForTesting - static String parseCmdlineFromProcfs(String cmdline) { - if (cmdline == null) { - return ""; - } - int firstNullByte = cmdline.indexOf("\0"); - if (firstNullByte == -1) { - return cmdline; - } - return cmdline.substring(0, firstNullByte); - } - - /** * Returns whether per-app memcg is available on device. */ static boolean hasMemcg() { @@ -237,13 +184,9 @@ public final class MemoryStatUtil { public long pgmajfault; /** For memcg stats, the anon rss + swap cache size. Otherwise total RSS. */ public long rssInBytes; - /** Number of bytes of the anonymous RSS. Only present for non-memcg stats. */ - public long anonRssInBytes; /** Number of bytes of page cache memory. Only present for memcg stats. */ public long cacheInBytes; /** Number of bytes of swap usage */ public long swapInBytes; - /** Device time when the processes started. */ - public long startTimeNanos; } } diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java index b1c7c7685ddf..9eb0d50dd789 100644 --- a/services/core/java/com/android/server/biometrics/face/FaceService.java +++ b/services/core/java/com/android/server/biometrics/face/FaceService.java @@ -930,7 +930,8 @@ public class FaceService extends BiometricServiceBase { final Face face = new Face("", 0 /* identifier */, deviceId); FaceService.super.handleRemoved(face, 0 /* remaining */); } - + Settings.Secure.putIntForUser(getContext().getContentResolver(), + Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT); }); } diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 33d8dec8b043..8e09d0e5958e 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -41,7 +41,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { public PlatformCompat(Context context) { mContext = context; - mChangeReporter = new ChangeReporter(); + mChangeReporter = new ChangeReporter( + StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER); } @Override @@ -96,10 +97,6 @@ public class PlatformCompat extends IPlatformCompat.Stub { private void reportChange(long changeId, ApplicationInfo appInfo, int state) { int uid = appInfo.uid; - //TODO(b/138374585): Implement rate limiting for the logs. - Slog.d(TAG, ChangeReporter.createLogString(uid, changeId, state)); - mChangeReporter.reportChange(uid, changeId, - state, /* source */ - StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER); + mChangeReporter.reportChange(uid, changeId, state); } } diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java index e8a577938b4c..88a7077ac37a 100644 --- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java +++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java @@ -64,7 +64,13 @@ public class DisplayWhiteBalanceController implements AmbientFilter mColorTemperatureFilter; private DisplayWhiteBalanceThrottler mThrottler; + // In low brightness conditions the ALS readings are more noisy and produce + // high errors. This default is introduced to provide a fixed display color + // temperature when sensor readings become unreliable. private final float mLowLightAmbientColorTemperature; + // In high brightness conditions certain color temperatures can cause peak display + // brightness to drop. This fixed color temperature can be used to compensate for + // this effect. private final float mHighLightAmbientColorTemperature; private float mAmbientColorTemperature; @@ -85,12 +91,14 @@ public class DisplayWhiteBalanceController implements // A piecewise linear relationship between ambient and display color temperatures. private Spline.LinearSpline mAmbientToDisplayColorTemperatureSpline; - // In very low or very high brightness conditions ambient EQ should to set to a default - // instead of using mAmbientToDisplayColorTemperatureSpline. However, setting ambient EQ - // based on thresholds can cause the display to rapidly change color temperature. To solve - // this, mLowLightAmbientBrightnessToBiasSpline and mHighLightAmbientBrightnessToBiasSpline - // are used to smoothly interpolate from ambient color temperature to the defaults. - // A piecewise linear relationship between low light brightness and low light bias. + // In very low or very high brightness conditions Display White Balance should + // be to set to a default instead of using mAmbientToDisplayColorTemperatureSpline. + // However, setting Display White Balance based on thresholds can cause the + // display to rapidly change color temperature. To solve this, + // mLowLightAmbientBrightnessToBiasSpline and + // mHighLightAmbientBrightnessToBiasSpline are used to smoothly interpolate from + // ambient color temperature to the defaults. A piecewise linear relationship + // between low light brightness and low light bias. private Spline.LinearSpline mLowLightAmbientBrightnessToBiasSpline; // A piecewise linear relationship between high light brightness and high light bias. diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 75b9705e1045..8fbad4c5910b 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -220,6 +220,8 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeSetFocusedApplication(long ptr, int displayId, InputApplicationHandle application); private static native void nativeSetFocusedDisplay(long ptr, int displayId); + private static native boolean nativeTransferTouchFocus(long ptr, + InputChannel fromChannel, InputChannel toChannel); private static native void nativeSetPointerSpeed(long ptr, int speed); private static native void nativeSetShowTouches(long ptr, boolean enabled); private static native void nativeSetInteractive(long ptr, boolean interactive); @@ -1533,6 +1535,29 @@ public class InputManagerService extends IInputManager.Stub nativeSetSystemUiVisibility(mPtr, visibility); } + /** + * Atomically transfers touch focus from one window to another as identified by + * their input channels. It is possible for multiple windows to have + * touch focus if they support split touch dispatch + * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this + * method only transfers touch focus of the specified window without affecting + * other windows that may also have touch focus at the same time. + * @param fromChannel The channel of a window that currently has touch focus. + * @param toChannel The channel of the window that should receive touch focus in + * place of the first. + * @return True if the transfer was successful. False if the window with the + * specified channel did not actually have touch focus at the time of the request. + */ + public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) { + if (fromChannel == null) { + throw new IllegalArgumentException("fromChannel must not be null."); + } + if (toChannel == null) { + throw new IllegalArgumentException("toChannel must not be null."); + } + return nativeTransferTouchFocus(mPtr, fromChannel, toChannel); + } + @Override // Binder call public void tryPointerSpeed(int speed) { if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED, diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index b7eca29ac04c..378d9ebdaaa8 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -44,6 +44,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; +import android.app.admin.DeviceStateCache; import android.app.admin.PasswordMetrics; import android.app.backup.BackupManager; import android.app.trust.IStrongAuthTracker; @@ -76,6 +77,7 @@ import android.os.StrictMode; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.provider.Settings; @@ -429,6 +431,10 @@ public class LockSettingsService extends ILockSettings.Stub { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } + public UserManagerInternal getUserManagerInternal() { + return LocalServices.getService(UserManagerInternal.class); + } + /** * Return the {@link DevicePolicyManager} object. * @@ -440,6 +446,10 @@ public class LockSettingsService extends ILockSettings.Stub { return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); } + public DeviceStateCache getDeviceStateCache() { + return DeviceStateCache.getInstance(); + } + public KeyStore getKeyStore() { return KeyStore.getInstance(); } @@ -1023,11 +1033,16 @@ public class LockSettingsService extends ILockSettings.Stub { } private void notifySeparateProfileChallengeChanged(int userId) { - final DevicePolicyManagerInternal dpmi = LocalServices.getService( - DevicePolicyManagerInternal.class); - if (dpmi != null) { - dpmi.reportSeparateProfileChallengeChanged(userId); - } + // LSS cannot call into DPM directly, otherwise it will cause deadlock. + // In this case, calling DPM on a handler thread is OK since DPM doesn't + // expect reportSeparateProfileChallengeChanged() to happen synchronously. + mHandler.post(() -> { + final DevicePolicyManagerInternal dpmi = LocalServices.getService( + DevicePolicyManagerInternal.class); + if (dpmi != null) { + dpmi.reportSeparateProfileChallengeChanged(userId); + } + }); } @Override @@ -2038,7 +2053,6 @@ public class LockSettingsService extends ILockSettings.Stub { * reporting the password changed. */ private void notifyPasswordChanged(@UserIdInt int userId) { - // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering mHandler.post(() -> { mInjector.getDevicePolicyManager().reportPasswordChanged(userId); LocalServices.getService(WindowManagerInternal.class).reportPasswordChanged(userId); @@ -3026,45 +3040,43 @@ public class LockSettingsService extends ILockSettings.Stub { pw.decreaseIndent(); } + /** + * Cryptographically disable escrow token support for the current user, if the user is not + * managed (either user has a profile owner, or if device is managed). Do not disable + * if we are running an automotive build. + */ private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) { - long ident = Binder.clearCallingIdentity(); - try { - // Managed profile should have escrow enabled - if (mUserManager.getUserInfo(userId).isManagedProfile()) { - Slog.i(TAG, "Managed profile can have escrow token"); - return; - } - DevicePolicyManager dpm = mInjector.getDevicePolicyManager(); - // Devices with Device Owner should have escrow enabled on all users. - if (dpm.getDeviceOwnerComponentOnAnyUser() != null) { - Slog.i(TAG, "Corp-owned device can have escrow token"); - return; - } - // We could also have a profile owner on the given (non-managed) user for unicorn cases - if (dpm.getProfileOwnerAsUser(userId) != null) { - Slog.i(TAG, "User with profile owner can have escrow token"); - return; - } - // If the device is yet to be provisioned (still in SUW), there is still - // a chance that Device Owner will be set on the device later, so postpone - // disabling escrow token for now. - if (!dpm.isDeviceProvisioned()) { - Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned"); - return; - } + final UserManagerInternal userManagerInternal = mInjector.getUserManagerInternal(); - // Escrow tokens are enabled on automotive builds. - if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { - return; - } + // Managed profile should have escrow enabled + if (userManagerInternal.isUserManaged(userId)) { + Slog.i(TAG, "Managed profile can have escrow token"); + return; + } - // Disable escrow token permanently on all other device/user types. - Slog.i(TAG, "Disabling escrow token on user " + userId); - if (isSyntheticPasswordBasedCredentialLocked(userId)) { - mSpManager.destroyEscrowData(userId); - } - } finally { - Binder.restoreCallingIdentity(ident); + // Devices with Device Owner should have escrow enabled on all users. + if (userManagerInternal.isDeviceManaged()) { + Slog.i(TAG, "Corp-owned device can have escrow token"); + return; + } + + // If the device is yet to be provisioned (still in SUW), there is still + // a chance that Device Owner will be set on the device later, so postpone + // disabling escrow token for now. + if (!mInjector.getDeviceStateCache().isDeviceProvisioned()) { + Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned"); + return; + } + + // Escrow tokens are enabled on automotive builds. + if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { + return; + } + + // Disable escrow token permanently on all other device/user types. + Slog.i(TAG, "Disabling escrow token on user " + userId); + if (isSyntheticPasswordBasedCredentialLocked(userId)) { + mSpManager.destroyEscrowData(userId); } } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 248351ca3d2f..0aee8507d5af 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -456,6 +456,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { return; } mDestroyed = true; + mPlaybackState = null; mHandler.post(MessageHandler.MSG_DESTROYED); } } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 61ea84f9dc7f..86c709e0d208 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -16,8 +16,6 @@ package com.android.server.pm; -import static android.content.pm.PackageParser.Component; -import static android.content.pm.PackageParser.IntentInfo; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; import android.Manifest; @@ -25,8 +23,11 @@ import android.annotation.Nullable; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.ProviderInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; import android.net.Uri; import android.os.Build; import android.os.Process; @@ -40,14 +41,15 @@ import android.util.SparseArray; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.server.FgThread; import com.android.server.compat.PlatformCompat; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -125,8 +127,7 @@ public class AppsFilter { boolean isGloballyEnabled(); /** @return true if the feature is enabled for the given package. */ - boolean packageIsEnabled(PackageParser.Package pkg); - + boolean packageIsEnabled(AndroidPackage pkg); } private static class FeatureConfigImpl implements FeatureConfig { @@ -159,14 +160,14 @@ public class AppsFilter { } @Override - public boolean packageIsEnabled(PackageParser.Package pkg) { + public boolean packageIsEnabled(AndroidPackage pkg) { final PlatformCompat compatibility = mInjector.getCompatibility(); if (compatibility == null) { Slog.wtf(TAG, "PlatformCompat is null"); return mFeatureEnabled; } - return compatibility.isChangeEnabled( - PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo); + return compatibility.isChangeEnabled(PackageManager.FILTER_APPLICATION_QUERY, + pkg.toAppInfo()); } } @@ -196,14 +197,13 @@ public class AppsFilter { } /** Returns true if the querying package may query for the potential target package */ - private static boolean canQuery(PackageParser.Package querying, - PackageParser.Package potentialTarget) { - if (querying.mQueriesIntents == null) { + private static boolean canQuery(AndroidPackage querying, AndroidPackage potentialTarget) { + if (querying.getQueriesIntents() == null || potentialTarget.getActivities() == null) { return false; } - for (Intent intent : querying.mQueriesIntents) { - if (matches(intent, potentialTarget.providers, potentialTarget.activities, - potentialTarget.services, potentialTarget.receivers)) { + for (Intent intent : querying.getQueriesIntents()) { + if (matches(intent, potentialTarget.getProviders(), potentialTarget.getActivities(), + potentialTarget.getServices(), potentialTarget.getReceivers())) { return true; } } @@ -211,24 +211,24 @@ public class AppsFilter { } private static boolean matches(Intent intent, - ArrayList<PackageParser.Provider> providerList, - ArrayList<? extends Component<? extends IntentInfo>>... componentLists) { - for (int p = providerList.size() - 1; p >= 0; p--) { - PackageParser.Provider provider = providerList.get(p); - final ProviderInfo providerInfo = provider.info; + @Nullable List<ParsedProvider> providerList, + List<? extends ParsedComponent<? extends ParsedIntentInfo>>... componentLists) { + for (int p = ArrayUtils.size(providerList) - 1; p >= 0; p--) { + ParsedProvider provider = providerList.get(p); final Uri data = intent.getData(); if ("content".equalsIgnoreCase(intent.getScheme()) && data != null - && providerInfo.authority.equalsIgnoreCase(data.getAuthority())) { + && provider.getAuthority().equalsIgnoreCase(data.getAuthority())) { return true; } } for (int l = componentLists.length - 1; l >= 0; l--) { - ArrayList<? extends Component<? extends IntentInfo>> components = componentLists[l]; + List<? extends ParsedComponent<? extends ParsedIntentInfo>> components = + componentLists[l]; for (int c = components.size() - 1; c >= 0; c--) { - Component<? extends IntentInfo> component = components.get(c); - ArrayList<? extends IntentInfo> intents = component.intents; + ParsedComponent<? extends ParsedIntentInfo> component = components.get(c); + List<? extends ParsedIntentInfo> intents = component.intents; for (int i = intents.size() - 1; i >= 0; i--) { IntentFilter intentFilter = intents.get(i); if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), @@ -273,44 +273,44 @@ public class AppsFilter { * @param newPkg the new package being added * @param existing all other packages currently on the device. */ - public void addPackage(PackageParser.Package newPkg, - Map<String, PackageParser.Package> existing) { + public void addPackage(AndroidPackage newPkg, Map<String, AndroidPackage> existing) { // let's re-evaluate the ability of already added packages to see this new package - if (newPkg.mForceQueryable + if (newPkg.isForceQueryable() || (mSystemAppsQueryable && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) { - mForceQueryable.add(newPkg.packageName); + mForceQueryable.add(newPkg.getPackageName()); } else { for (String packageName : mQueriesViaIntent.keySet()) { - if (packageName == newPkg.packageName) { + if (Objects.equals(packageName, newPkg.getPackageName())) { continue; } - final PackageParser.Package existingPackage = existing.get(packageName); + final AndroidPackage existingPackage = existing.get(packageName); if (canQuery(existingPackage, newPkg)) { - mQueriesViaIntent.get(packageName).add(newPkg.packageName); + mQueriesViaIntent.get(packageName).add(newPkg.getPackageName()); } } } // if the new package declares them, let's evaluate its ability to see existing packages - mQueriesViaIntent.put(newPkg.packageName, new HashSet<>()); - for (PackageParser.Package existingPackage : existing.values()) { - if (existingPackage.packageName == newPkg.packageName) { + mQueriesViaIntent.put(newPkg.getPackageName(), new HashSet<>()); + for (AndroidPackage existingPackage : existing.values()) { + if (Objects.equals(existingPackage.getPackageName(), newPkg.getPackageName())) { continue; } - if (existingPackage.mForceQueryable + if (existingPackage.isForceQueryable() || (mSystemAppsQueryable && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) { continue; } if (canQuery(newPkg, existingPackage)) { - mQueriesViaIntent.get(newPkg.packageName).add(existingPackage.packageName); + mQueriesViaIntent.get(newPkg.getPackageName()) + .add(existingPackage.getPackageName()); } } final HashSet<String> queriesPackages = new HashSet<>( - newPkg.mQueriesPackages == null ? 0 : newPkg.mQueriesPackages.size()); - if (newPkg.mQueriesPackages != null) { - queriesPackages.addAll(newPkg.mQueriesPackages); + newPkg.getQueriesPackages() == null ? 0 : newPkg.getQueriesPackages().size()); + if (newPkg.getQueriesPackages() != null) { + queriesPackages.addAll(newPkg.getQueriesPackages()); } - mQueriesViaPackage.put(newPkg.packageName, queriesPackages); + mQueriesViaPackage.put(newPkg.getPackageName(), queriesPackages); } /** @@ -405,8 +405,8 @@ public class AppsFilter { private boolean shouldFilterApplicationInternal( PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, int userId) { - final String callingName = callingPkgSetting.pkg.packageName; - final PackageParser.Package targetPkg = targetPkgSetting.pkg; + final String callingName = callingPkgSetting.pkg.getPackageName(); + final AndroidPackage targetPkg = targetPkgSetting.pkg; if (!mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) { if (DEBUG_LOGGING) { @@ -422,8 +422,8 @@ public class AppsFilter { } return true; } - final String targetName = targetPkg.packageName; - if (callingPkgSetting.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) { + final String targetName = targetPkg.getPackageName(); + if (callingPkgSetting.pkg.getTargetSdkVersion() < Build.VERSION_CODES.R) { if (DEBUG_LOGGING) { log(callingPkgSetting, targetPkgSetting, "caller pre-R"); } @@ -435,7 +435,7 @@ public class AppsFilter { } return false; } - if (targetPkg.mForceQueryable) { + if (targetPkg.isForceQueryable()) { if (DEBUG_LOGGING) { log(callingPkgSetting, targetPkgSetting, "manifest forceQueryable"); } @@ -470,9 +470,11 @@ public class AppsFilter { } return false; } - if (callingPkgSetting.pkg.instrumentation.size() > 0) { - for (int i = 0, max = callingPkgSetting.pkg.instrumentation.size(); i < max; i++) { - if (callingPkgSetting.pkg.instrumentation.get(i).info.targetPackage == targetName) { + List<ComponentParseUtils.ParsedInstrumentation> instrumentations = + callingPkgSetting.pkg.getInstrumentations(); + if (ArrayUtils.size(instrumentations) > 0) { + for (int i = 0, max = instrumentations.size(); i < max; i++) { + if (Objects.equals(instrumentations.get(i).getTargetPackage(), targetName)) { if (DEBUG_LOGGING) { log(callingPkgSetting, targetPkgSetting, "instrumentation"); } @@ -504,7 +506,7 @@ public class AppsFilter { private boolean isImplicitlyQueryableSystemApp(PackageSetting targetPkgSetting) { return targetPkgSetting.isSystem() && (mSystemAppsQueryable - || mForceQueryableByDevice.contains(targetPkgSetting.pkg.packageName)); + || mForceQueryableByDevice.contains(targetPkgSetting.pkg.getPackageName())); } public void dumpQueries( diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java index 8facce112b52..333a6e9cbfc2 100644 --- a/services/core/java/com/android/server/pm/ComponentResolver.java +++ b/services/core/java/com/android/server/pm/ComponentResolver.java @@ -21,7 +21,6 @@ import static android.content.pm.PackageManagerInternal.PACKAGE_SETUP_WIZARD; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; -import static com.android.server.pm.PackageManagerService.fixProcessName; import android.content.ComponentName; import android.content.Intent; @@ -32,13 +31,18 @@ import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.InstantAppResolveInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; -import android.content.pm.PackageParser.ActivityIntentInfo; -import android.content.pm.PackageParser.ServiceIntentInfo; import android.content.pm.PackageUserState; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedProviderIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.pm.parsing.ComponentParseUtils.ParsedServiceIntentInfo; +import android.content.pm.parsing.PackageInfoUtils; import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -49,15 +53,19 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ArrayUtils; import com.android.server.IntentResolver; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.function.Function; /** Resolves all Android component types [activities, services, providers and receivers]. */ public class ComponentResolver { @@ -158,7 +166,7 @@ public class ComponentResolver { /** All available receivers, for your resolving pleasure. */ @GuardedBy("mLock") - private final ActivityIntentResolver mReceivers = new ActivityIntentResolver(); + private final ActivityIntentResolver mReceivers = new ReceiverIntentResolver(); /** All available services, for your resolving pleasure. */ @GuardedBy("mLock") @@ -166,7 +174,7 @@ public class ComponentResolver { /** Mapping from provider authority [first directory in content URI codePath) to provider. */ @GuardedBy("mLock") - private final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = new ArrayMap<>(); + private final ArrayMap<String, ParsedProvider> mProvidersByAuthority = new ArrayMap<>(); /** Whether or not processing protected filters should be deferred. */ private boolean mDeferProtectedFilters = true; @@ -181,7 +189,7 @@ public class ComponentResolver { * /system partition in order to know which component is the setup wizard. This can * only ever be non-empty if {@link #mDeferProtectedFilters} is {@code true}. */ - private List<PackageParser.ActivityIntentInfo> mProtectedFilters; + private List<ParsedActivityIntentInfo> mProtectedFilters; ComponentResolver(UserManagerService userManager, PackageManagerInternal packageManagerInternal, @@ -192,28 +200,28 @@ public class ComponentResolver { } /** Returns the given activity */ - PackageParser.Activity getActivity(ComponentName component) { + ParsedActivity getActivity(ComponentName component) { synchronized (mLock) { return mActivities.mActivities.get(component); } } /** Returns the given provider */ - PackageParser.Provider getProvider(ComponentName component) { + ParsedProvider getProvider(ComponentName component) { synchronized (mLock) { return mProviders.mProviders.get(component); } } /** Returns the given receiver */ - PackageParser.Activity getReceiver(ComponentName component) { + ParsedActivity getReceiver(ComponentName component) { synchronized (mLock) { return mReceivers.mActivities.get(component); } } /** Returns the given service */ - PackageParser.Service getService(ComponentName component) { + ParsedService getService(ComponentName component) { synchronized (mLock) { return mServices.mServices.get(component); } @@ -226,7 +234,7 @@ public class ComponentResolver { } List<ResolveInfo> queryActivities(Intent intent, String resolvedType, int flags, - List<PackageParser.Activity> activities, int userId) { + List<ParsedActivity> activities, int userId) { synchronized (mLock) { return mActivities.queryIntentForPackage( intent, resolvedType, flags, activities, userId); @@ -240,7 +248,7 @@ public class ComponentResolver { } List<ResolveInfo> queryProviders(Intent intent, String resolvedType, int flags, - List<PackageParser.Provider> providers, int userId) { + List<ParsedProvider> providers, int userId) { synchronized (mLock) { return mProviders.queryIntentForPackage(intent, resolvedType, flags, providers, userId); } @@ -254,25 +262,34 @@ public class ComponentResolver { List<ProviderInfo> providerList = null; synchronized (mLock) { for (int i = mProviders.mProviders.size() - 1; i >= 0; --i) { - final PackageParser.Provider p = mProviders.mProviders.valueAt(i); - final PackageSetting ps = (PackageSetting) p.owner.mExtras; + final ParsedProvider p = mProviders.mProviders.valueAt(i); + if (p.getAuthority() == null) { + continue; + } + + final PackageSetting ps = + (PackageSetting) sPackageManagerInternal.getPackageSetting( + p.getPackageName()); if (ps == null) { continue; } - if (p.info.authority == null) { + + AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName()); + if (pkg == null) { continue; } - if (processName != null && (!p.info.processName.equals(processName) - || !UserHandle.isSameApp(p.info.applicationInfo.uid, uid))) { + + if (processName != null && (!p.getProcessName().equals(processName) + || !UserHandle.isSameApp(pkg.getUid(), uid))) { continue; } // See PM.queryContentProviders()'s javadoc for why we have the metaData parameter. if (metaDataKey != null - && (p.metaData == null || !p.metaData.containsKey(metaDataKey))) { + && (p.getMetaData() == null || !p.getMetaData().containsKey(metaDataKey))) { continue; } - final ProviderInfo info = PackageParser.generateProviderInfo( - p, flags, ps.readUserState(userId), userId); + final ProviderInfo info = PackageInfoUtils.generateProviderInfo( + pkg, p, flags, ps.readUserState(userId), userId); if (info == null) { continue; } @@ -285,17 +302,23 @@ public class ComponentResolver { return providerList; } - ProviderInfo queryProvider(String authority, int flags, int userId) { + ProviderInfo queryProvider(String authority, int flags, int uid, int userId) { synchronized (mLock) { - final PackageParser.Provider p = mProvidersByAuthority.get(authority); + final ParsedProvider p = mProvidersByAuthority.get(authority); if (p == null) { return null; } - final PackageSetting ps = (PackageSetting) p.owner.mExtras; + final PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + p.getPackageName()); if (ps == null) { return null; } - return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId), userId); + final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName()); + if (pkg == null) { + return null; + } + return PackageInfoUtils.generateProviderInfo(pkg, p, flags, + ps.readUserState(userId), userId); } } @@ -303,20 +326,29 @@ public class ComponentResolver { int userId) { synchronized (mLock) { for (int i = mProvidersByAuthority.size() - 1; i >= 0; --i) { - final PackageParser.Provider p = mProvidersByAuthority.valueAt(i); - final PackageSetting ps = (PackageSetting) p.owner.mExtras; + final ParsedProvider p = mProvidersByAuthority.valueAt(i); + if (!p.isSyncable()) { + continue; + } + + final PackageSetting ps = + (PackageSetting) sPackageManagerInternal.getPackageSetting( + p.getPackageName()); if (ps == null) { continue; } - if (!p.syncable) { + + final AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName()); + if (pkg == null) { continue; } - if (safeMode - && (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + + if (safeMode && (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) == 0) { continue; } final ProviderInfo info = - PackageParser.generateProviderInfo(p, 0, ps.readUserState(userId), userId); + PackageInfoUtils.generateProviderInfo(pkg, p, 0, + ps.readUserState(userId), userId); if (info == null) { continue; } @@ -333,7 +365,7 @@ public class ComponentResolver { } List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, - List<PackageParser.Activity> receivers, int userId) { + List<ParsedActivity> receivers, int userId) { synchronized (mLock) { return mReceivers.queryIntentForPackage(intent, resolvedType, flags, receivers, userId); } @@ -346,7 +378,7 @@ public class ComponentResolver { } List<ResolveInfo> queryServices(Intent intent, String resolvedType, int flags, - List<PackageParser.Service> services, int userId) { + List<ParsedService> services, int userId) { synchronized (mLock) { return mServices.queryIntentForPackage(intent, resolvedType, flags, services, userId); } @@ -360,15 +392,15 @@ public class ComponentResolver { } /** Asserts none of the providers defined in the given package haven't already been defined. */ - void assertProvidersNotDefined(PackageParser.Package pkg) throws PackageManagerException { + void assertProvidersNotDefined(AndroidPackage pkg) throws PackageManagerException { synchronized (mLock) { assertProvidersNotDefinedLocked(pkg); } } /** Add all components defined in the given package to the internal structures. */ - void addAllComponents(PackageParser.Package pkg, boolean chatty) { - final ArrayList<PackageParser.ActivityIntentInfo> newIntents = new ArrayList<>(); + void addAllComponents(AndroidPackage pkg, boolean chatty) { + final ArrayList<ParsedActivityIntentInfo> newIntents = new ArrayList<>(); synchronized (mLock) { addActivitiesLocked(pkg, newIntents, chatty); addReceiversLocked(pkg, chatty); @@ -378,17 +410,19 @@ public class ComponentResolver { final String setupWizardPackage = sPackageManagerInternal.getKnownPackageName( PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM); for (int i = newIntents.size() - 1; i >= 0; --i) { - final PackageParser.ActivityIntentInfo intentInfo = newIntents.get(i); - final PackageParser.Package disabledPkg = sPackageManagerInternal - .getDisabledSystemPackage(intentInfo.activity.info.packageName); - final List<PackageParser.Activity> systemActivities = - disabledPkg != null ? disabledPkg.activities : null; + final ParsedActivityIntentInfo intentInfo = newIntents.get(i); + final PackageSetting disabledPkgSetting = (PackageSetting) sPackageManagerInternal + .getDisabledSystemPackage(intentInfo.getPackageName()); + final AndroidPackage disabledPkg = + disabledPkgSetting == null ? null : disabledPkgSetting.pkg; + final List<ParsedActivity> systemActivities = + disabledPkg != null ? disabledPkg.getActivities() : null; adjustPriority(systemActivities, intentInfo, setupWizardPackage); } } /** Removes all components defined in the given package from the internal structures. */ - void removeAllComponents(PackageParser.Package pkg, boolean chatty) { + void removeAllComponents(AndroidPackage pkg, boolean chatty) { synchronized (mLock) { removeAllComponentsLocked(pkg, chatty); } @@ -407,7 +441,7 @@ public class ComponentResolver { if (mProtectedFilters == null || mProtectedFilters.size() == 0) { return; } - final List<ActivityIntentInfo> protectedFilters = mProtectedFilters; + final List<ParsedActivityIntentInfo> protectedFilters = mProtectedFilters; mProtectedFilters = null; final String setupWizardPackage = sPackageManagerInternal.getKnownPackageName( @@ -417,13 +451,13 @@ public class ComponentResolver { + " All protected intents capped to priority 0"); } for (int i = protectedFilters.size() - 1; i >= 0; --i) { - final ActivityIntentInfo filter = protectedFilters.get(i); - if (filter.activity.info.packageName.equals(setupWizardPackage)) { + final ParsedActivityIntentInfo filter = protectedFilters.get(i); + if (filter.getPackageName().equals(setupWizardPackage)) { if (DEBUG_FILTERS) { Slog.i(TAG, "Found setup wizard;" + " allow priority " + filter.getPriority() + ";" - + " package: " + filter.activity.info.packageName - + " activity: " + filter.activity.className + + " package: " + filter.getPackageName() + + " activity: " + filter.getClassName() + " priority: " + filter.getPriority()); } // skip setup wizard; allow it to keep the high priority filter @@ -431,8 +465,8 @@ public class ComponentResolver { } if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + filter.activity.info.packageName - + " activity: " + filter.activity.className + + " package: " + filter.getPackageName() + + " activity: " + filter.getClassName() + " origPrio: " + filter.getPriority()); } filter.setPriority(0); @@ -473,8 +507,8 @@ public class ComponentResolver { void dumpContentProviders(PrintWriter pw, DumpState dumpState, String packageName) { boolean printedSomething = false; - for (PackageParser.Provider p : mProviders.mProviders.values()) { - if (packageName != null && !packageName.equals(p.info.packageName)) { + for (ParsedProvider p : mProviders.mProviders.values()) { + if (packageName != null && !packageName.equals(p.getPackageName())) { continue; } if (!printedSomething) { @@ -484,14 +518,17 @@ public class ComponentResolver { pw.println("Registered ContentProviders:"); printedSomething = true; } - pw.print(" "); p.printComponentShortName(pw); pw.println(":"); - pw.print(" "); pw.println(p.toString()); + pw.print(" "); + ComponentName.printShortString(pw, p.getPackageName(), p.className); + pw.println(":"); + pw.print(" "); + pw.println(p.toString()); } printedSomething = false; - for (Map.Entry<String, PackageParser.Provider> entry : + for (Map.Entry<String, ParsedProvider> entry : mProvidersByAuthority.entrySet()) { - PackageParser.Provider p = entry.getValue(); - if (packageName != null && !packageName.equals(p.info.packageName)) { + ParsedProvider p = entry.getValue(); + if (packageName != null && !packageName.equals(p.getPackageName())) { continue; } if (!printedSomething) { @@ -503,25 +540,43 @@ public class ComponentResolver { } pw.print(" ["); pw.print(entry.getKey()); pw.println("]:"); pw.print(" "); pw.println(p.toString()); - if (p.info != null && p.info.applicationInfo != null) { - final String appInfo = p.info.applicationInfo.toString(); - pw.print(" applicationInfo="); pw.println(appInfo); + + AndroidPackage pkg = sPackageManagerInternal.getPackage(p.getPackageName()); + + if (pkg != null) { + // TODO(b/135203078): Print AppInfo? + pw.print(" applicationInfo="); pw.println(pkg.toAppInfo()); } } } - void dumpServicePermissions(PrintWriter pw, DumpState dumpState, String packageName) { + void dumpServicePermissions(PrintWriter pw, DumpState dumpState) { if (dumpState.onTitlePrinted()) pw.println(); pw.println("Service permissions:"); - final Iterator<ServiceIntentInfo> filterIterator = mServices.filterIterator(); + final Iterator<ParsedServiceIntentInfo> filterIterator = mServices.filterIterator(); while (filterIterator.hasNext()) { - final ServiceIntentInfo info = filterIterator.next(); - final ServiceInfo serviceInfo = info.service.info; - final String permission = serviceInfo.permission; + final ParsedServiceIntentInfo info = filterIterator.next(); + + ParsedService service = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName()); + if (pkg != null && pkg.getServices() != null) { + for (ParsedService parsedService : pkg.getServices()) { + if (Objects.equals(parsedService.className, info.getClassName())) { + service = parsedService; + } + } + } + + if (service == null) { + continue; + } + + final String permission = service.getPermission(); if (permission != null) { pw.print(" "); - pw.print(serviceInfo.getComponentName().flattenToShortString()); + pw.print(service.getComponentName().flattenToShortString()); pw.print(": "); pw.println(permission); } @@ -529,14 +584,12 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void addActivitiesLocked(PackageParser.Package pkg, - List<PackageParser.ActivityIntentInfo> newIntents, boolean chatty) { - final int activitiesSize = pkg.activities.size(); + private void addActivitiesLocked(AndroidPackage pkg, + List<ParsedActivityIntentInfo> newIntents, boolean chatty) { + final int activitiesSize = ArrayUtils.size(pkg.getActivities()); StringBuilder r = null; for (int i = 0; i < activitiesSize; i++) { - PackageParser.Activity a = pkg.activities.get(i); - a.info.processName = - fixProcessName(pkg.applicationInfo.processName, a.info.processName); + ParsedActivity a = pkg.getActivities().get(i); mActivities.addActivity(a, "activity", newIntents); if (DEBUG_PACKAGE_SCANNING && chatty) { if (r == null) { @@ -544,7 +597,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (DEBUG_PACKAGE_SCANNING && chatty) { @@ -553,20 +606,17 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void addProvidersLocked(PackageParser.Package pkg, boolean chatty) { - final int providersSize = pkg.providers.size(); + private void addProvidersLocked(AndroidPackage pkg, boolean chatty) { + final int providersSize = ArrayUtils.size(pkg.getProviders()); StringBuilder r = null; for (int i = 0; i < providersSize; i++) { - PackageParser.Provider p = pkg.providers.get(i); - p.info.processName = fixProcessName(pkg.applicationInfo.processName, - p.info.processName); + EffectiveProvider p = new EffectiveProvider(pkg.getProviders().get(i)); mProviders.addProvider(p); - p.syncable = p.info.isSyncable; - if (p.info.authority != null) { - String[] names = p.info.authority.split(";"); - p.info.authority = null; + if (p.getAuthority() != null) { + String[] names = p.getAuthority().split(";"); + p.setEffectiveAuthority(null); for (int j = 0; j < names.length; j++) { - if (j == 1 && p.syncable) { + if (j == 1 && p.isSyncable()) { // We only want the first authority for a provider to possibly be // syncable, so if we already added this provider using a different // authority clear the syncable flag. We copy the provider before @@ -574,23 +624,23 @@ public class ComponentResolver { // to a provider that we don't want to change. // Only do this for the second authority since the resulting provider // object can be the same for all future authorities for this provider. - p = new PackageParser.Provider(p); - p.syncable = false; + p = new EffectiveProvider(p); + p.setEffectiveSyncable(false); } if (!mProvidersByAuthority.containsKey(names[j])) { mProvidersByAuthority.put(names[j], p); - if (p.info.authority == null) { - p.info.authority = names[j]; + if (p.getAuthority() == null) { + p.setEffectiveAuthority(names[j]); } else { - p.info.authority = p.info.authority + ";" + names[j]; + p.setEffectiveAuthority(p.getAuthority() + ";" + names[j]); } if (DEBUG_PACKAGE_SCANNING && chatty) { Log.d(TAG, "Registered content provider: " + names[j] - + ", className = " + p.info.name - + ", isSyncable = " + p.info.isSyncable); + + ", className = " + p.getName() + + ", isSyncable = " + p.isSyncable()); } } else { - final PackageParser.Provider other = + final ParsedProvider other = mProvidersByAuthority.get(names[j]); final ComponentName component = (other != null && other.getComponentName() != null) @@ -598,7 +648,7 @@ public class ComponentResolver { final String packageName = component != null ? component.getPackageName() : "?"; Slog.w(TAG, "Skipping provider name " + names[j] - + " (in package " + pkg.applicationInfo.packageName + ")" + + " (in package " + pkg.getAppInfoPackageName() + ")" + ": name already used by " + packageName); } } @@ -609,7 +659,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(p.info.name); + r.append(p.getName()); } } if (DEBUG_PACKAGE_SCANNING && chatty) { @@ -618,13 +668,11 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void addReceiversLocked(PackageParser.Package pkg, boolean chatty) { - final int receiversSize = pkg.receivers.size(); + private void addReceiversLocked(AndroidPackage pkg, boolean chatty) { + final int receiversSize = ArrayUtils.size(pkg.getReceivers()); StringBuilder r = null; for (int i = 0; i < receiversSize; i++) { - PackageParser.Activity a = pkg.receivers.get(i); - a.info.processName = fixProcessName(pkg.applicationInfo.processName, - a.info.processName); + ParsedActivity a = pkg.getReceivers().get(i); mReceivers.addActivity(a, "receiver", null); if (DEBUG_PACKAGE_SCANNING && chatty) { if (r == null) { @@ -632,7 +680,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (DEBUG_PACKAGE_SCANNING && chatty) { @@ -641,13 +689,11 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void addServicesLocked(PackageParser.Package pkg, boolean chatty) { - final int servicesSize = pkg.services.size(); + private void addServicesLocked(AndroidPackage pkg, boolean chatty) { + final int servicesSize = ArrayUtils.size(pkg.getServices()); StringBuilder r = null; for (int i = 0; i < servicesSize; i++) { - PackageParser.Service s = pkg.services.get(i); - s.info.processName = fixProcessName(pkg.applicationInfo.processName, - s.info.processName); + ParsedService s = pkg.getServices().get(i); mServices.addService(s); if (DEBUG_PACKAGE_SCANNING && chatty) { if (r == null) { @@ -655,7 +701,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(s.info.name); + r.append(s.getName()); } } if (DEBUG_PACKAGE_SCANNING && chatty) { @@ -663,13 +709,12 @@ public class ComponentResolver { } } - /** * <em>WARNING</em> for performance reasons, the passed in intentList WILL BE * MODIFIED. Do not pass in a list that should not be changed. */ - private static <T> void getIntentListSubset(List<ActivityIntentInfo> intentList, - IterGenerator<T> generator, Iterator<T> searchIterator) { + private static <T> void getIntentListSubset(List<ParsedActivityIntentInfo> intentList, + Function<ParsedActivityIntentInfo, Iterator<T>> generator, Iterator<T> searchIterator) { // loop through the set of actions; every one must be found in the intent filter while (searchIterator.hasNext()) { // we must have at least one filter in the list to consider a match @@ -680,14 +725,14 @@ public class ComponentResolver { final T searchAction = searchIterator.next(); // loop through the set of intent filters - final Iterator<ActivityIntentInfo> intentIter = intentList.iterator(); + final Iterator<ParsedActivityIntentInfo> intentIter = intentList.iterator(); while (intentIter.hasNext()) { - final ActivityIntentInfo intentInfo = intentIter.next(); + final ParsedActivityIntentInfo intentInfo = intentIter.next(); boolean selectionFound = false; // loop through the intent filter's selection criteria; at least one // of them must match the searched criteria - final Iterator<T> intentSelectionIter = generator.generate(intentInfo); + final Iterator<T> intentSelectionIter = generator.apply(intentInfo); while (intentSelectionIter != null && intentSelectionIter.hasNext()) { final T intentSelection = intentSelectionIter.next(); if (intentSelection != null && intentSelection.equals(searchAction)) { @@ -705,7 +750,7 @@ public class ComponentResolver { } } - private static boolean isProtectedAction(ActivityIntentInfo filter) { + private static boolean isProtectedAction(ParsedActivityIntentInfo filter) { final Iterator<String> actionsIter = filter.actionsIterator(); while (actionsIter != null && actionsIter.hasNext()) { final String filterAction = actionsIter.next(); @@ -719,20 +764,20 @@ public class ComponentResolver { /** * Finds a privileged activity that matches the specified activity names. */ - private static PackageParser.Activity findMatchingActivity( - List<PackageParser.Activity> activityList, ActivityInfo activityInfo) { - for (PackageParser.Activity sysActivity : activityList) { - if (sysActivity.info.name.equals(activityInfo.name)) { + private static ParsedActivity findMatchingActivity( + List<ParsedActivity> activityList, ParsedActivity activityInfo) { + for (ParsedActivity sysActivity : activityList) { + if (sysActivity.getName().equals(activityInfo.getName())) { return sysActivity; } - if (sysActivity.info.name.equals(activityInfo.targetActivity)) { + if (sysActivity.getName().equals(activityInfo.targetActivity)) { return sysActivity; } - if (sysActivity.info.targetActivity != null) { - if (sysActivity.info.targetActivity.equals(activityInfo.name)) { + if (sysActivity.targetActivity != null) { + if (sysActivity.targetActivity.equals(activityInfo.getName())) { return sysActivity; } - if (sysActivity.info.targetActivity.equals(activityInfo.targetActivity)) { + if (sysActivity.targetActivity.equals(activityInfo.targetActivity)) { return sysActivity; } } @@ -753,24 +798,23 @@ public class ComponentResolver { * <em>NOTE:</em> There is one exception. For security reasons, the setup wizard is * allowed to obtain any priority on any action. */ - private void adjustPriority(List<PackageParser.Activity> systemActivities, - ActivityIntentInfo intent, String setupWizardPackage) { + private void adjustPriority(List<ParsedActivity> systemActivities, + ParsedActivityIntentInfo intent, String setupWizardPackage) { // nothing to do; priority is fine as-is if (intent.getPriority() <= 0) { return; } - final ActivityInfo activityInfo = intent.activity.info; - final ApplicationInfo applicationInfo = activityInfo.applicationInfo; + AndroidPackage pkg = sPackageManagerInternal.getPackage(intent.getPackageName()); final boolean privilegedApp = - ((applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0); + ((pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0); if (!privilegedApp) { // non-privileged applications can never define a priority >0 if (DEBUG_FILTERS) { Slog.i(TAG, "Non-privileged app; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -794,8 +838,8 @@ public class ComponentResolver { mProtectedFilters.add(intent); if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; save for later;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } return; @@ -804,12 +848,12 @@ public class ComponentResolver { Slog.i(TAG, "No setup wizard;" + " All protected intents capped to priority 0"); } - if (intent.activity.info.packageName.equals(setupWizardPackage)) { + if (intent.getPackageName().equals(setupWizardPackage)) { if (DEBUG_FILTERS) { Slog.i(TAG, "Found setup wizard;" + " allow priority " + intent.getPriority() + ";" - + " package: " + intent.activity.info.packageName - + " activity: " + intent.activity.className + + " package: " + intent.getPackageName() + + " activity: " + intent.getClassName() + " priority: " + intent.getPriority()); } // setup wizard gets whatever it wants @@ -817,8 +861,8 @@ public class ComponentResolver { } if (DEBUG_FILTERS) { Slog.i(TAG, "Protected action; cap priority to 0;" - + " package: " + intent.activity.info.packageName - + " activity: " + intent.activity.className + + " package: " + intent.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -830,14 +874,28 @@ public class ComponentResolver { } // privileged app unbundled update ... try to find the same activity - final PackageParser.Activity foundActivity = - findMatchingActivity(systemActivities, activityInfo); + + ParsedActivity foundActivity = null; + ParsedActivity activity = null; + + if (pkg.getActivities() != null) { + for (ParsedActivity parsedProvider : pkg.getActivities()) { + if (Objects.equals(parsedProvider.className, intent.getClassName())) { + activity = parsedProvider; + } + } + } + + if (activity != null) { + foundActivity = findMatchingActivity(systemActivities, activity); + } + if (foundActivity == null) { // this is a new activity; it cannot obtain >0 priority if (DEBUG_FILTERS) { Slog.i(TAG, "New activity; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -847,19 +905,19 @@ public class ComponentResolver { // found activity, now check for filter equivalence // a shallow copy is enough; we modify the list, not its contents - final List<ActivityIntentInfo> intentListCopy = new ArrayList<>(foundActivity.intents); - final List<ActivityIntentInfo> foundFilters = mActivities.findFilters(intent); + final List<ParsedActivityIntentInfo> intentListCopy = + new ArrayList<>(foundActivity.intents); // find matching action subsets final Iterator<String> actionsIterator = intent.actionsIterator(); if (actionsIterator != null) { - getIntentListSubset(intentListCopy, new ActionIterGenerator(), actionsIterator); + getIntentListSubset(intentListCopy, IntentFilter::actionsIterator, actionsIterator); if (intentListCopy.size() == 0) { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched action; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -870,13 +928,14 @@ public class ComponentResolver { // find matching category subsets final Iterator<String> categoriesIterator = intent.categoriesIterator(); if (categoriesIterator != null) { - getIntentListSubset(intentListCopy, new CategoriesIterGenerator(), categoriesIterator); + getIntentListSubset(intentListCopy, IntentFilter::categoriesIterator, + categoriesIterator); if (intentListCopy.size() == 0) { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched category; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -887,13 +946,13 @@ public class ComponentResolver { // find matching schemes subsets final Iterator<String> schemesIterator = intent.schemesIterator(); if (schemesIterator != null) { - getIntentListSubset(intentListCopy, new SchemesIterGenerator(), schemesIterator); + getIntentListSubset(intentListCopy, IntentFilter::schemesIterator, schemesIterator); if (intentListCopy.size() == 0) { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched scheme; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -905,14 +964,14 @@ public class ComponentResolver { final Iterator<IntentFilter.AuthorityEntry> authoritiesIterator = intent.authoritiesIterator(); if (authoritiesIterator != null) { - getIntentListSubset(intentListCopy, new AuthoritiesIterGenerator(), + getIntentListSubset(intentListCopy, IntentFilter::authoritiesIterator, authoritiesIterator); if (intentListCopy.size() == 0) { // no more intents to match; we're not equivalent if (DEBUG_FILTERS) { Slog.i(TAG, "Mismatched authority; cap priority to 0;" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(0); @@ -929,8 +988,8 @@ public class ComponentResolver { if (DEBUG_FILTERS) { Slog.i(TAG, "Found matching filter(s);" + " cap priority to " + cappedPriority + ";" - + " package: " + applicationInfo.packageName - + " activity: " + intent.activity.className + + " package: " + pkg.getPackageName() + + " activity: " + intent.getClassName() + " origPrio: " + intent.getPriority()); } intent.setPriority(cappedPriority); @@ -940,15 +999,15 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void removeAllComponentsLocked(PackageParser.Package pkg, boolean chatty) { + private void removeAllComponentsLocked(AndroidPackage pkg, boolean chatty) { int componentSize; StringBuilder r; int i; - componentSize = pkg.activities.size(); + componentSize = ArrayUtils.size(pkg.getActivities()); r = null; for (i = 0; i < componentSize; i++) { - PackageParser.Activity a = pkg.activities.get(i); + ParsedActivity a = pkg.getActivities().get(i); mActivities.removeActivity(a, "activity"); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -956,32 +1015,32 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (DEBUG_REMOVE && chatty) { Log.d(TAG, " Activities: " + (r == null ? "<NONE>" : r)); } - componentSize = pkg.providers.size(); + componentSize = ArrayUtils.size(pkg.getProviders()); r = null; for (i = 0; i < componentSize; i++) { - PackageParser.Provider p = pkg.providers.get(i); + ParsedProvider p = pkg.getProviders().get(i); mProviders.removeProvider(p); - if (p.info.authority == null) { + if (p.getAuthority() == null) { // Another content provider with this authority existed when this app was // installed, so this authority is null. Ignore it as we don't have to // unregister the provider. continue; } - String[] names = p.info.authority.split(";"); + String[] names = p.getAuthority().split(";"); for (int j = 0; j < names.length; j++) { if (mProvidersByAuthority.get(names[j]) == p) { mProvidersByAuthority.remove(names[j]); if (DEBUG_REMOVE && chatty) { Log.d(TAG, "Unregistered content provider: " + names[j] - + ", className = " + p.info.name + ", isSyncable = " - + p.info.isSyncable); + + ", className = " + p.getName() + ", isSyncable = " + + p.isSyncable()); } } } @@ -991,17 +1050,17 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(p.info.name); + r.append(p.getName()); } } if (DEBUG_REMOVE && chatty) { Log.d(TAG, " Providers: " + (r == null ? "<NONE>" : r)); } - componentSize = pkg.receivers.size(); + componentSize = ArrayUtils.size(pkg.getReceivers()); r = null; for (i = 0; i < componentSize; i++) { - PackageParser.Activity a = pkg.receivers.get(i); + ParsedActivity a = pkg.getReceivers().get(i); mReceivers.removeActivity(a, "receiver"); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -1009,17 +1068,17 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (DEBUG_REMOVE && chatty) { Log.d(TAG, " Receivers: " + (r == null ? "<NONE>" : r)); } - componentSize = pkg.services.size(); + componentSize = ArrayUtils.size(pkg.getServices()); r = null; for (i = 0; i < componentSize; i++) { - PackageParser.Service s = pkg.services.get(i); + ParsedService s = pkg.getServices().get(i); mServices.removeService(s); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -1027,7 +1086,7 @@ public class ComponentResolver { } else { r.append(' '); } - r.append(s.info.name); + r.append(s.getName()); } } if (DEBUG_REMOVE && chatty) { @@ -1036,26 +1095,26 @@ public class ComponentResolver { } @GuardedBy("mLock") - private void assertProvidersNotDefinedLocked(PackageParser.Package pkg) + private void assertProvidersNotDefinedLocked(AndroidPackage pkg) throws PackageManagerException { - final int providersSize = pkg.providers.size(); + final int providersSize = ArrayUtils.size(pkg.getProviders()); int i; for (i = 0; i < providersSize; i++) { - PackageParser.Provider p = pkg.providers.get(i); - if (p.info.authority != null) { - final String[] names = p.info.authority.split(";"); + ParsedProvider p = pkg.getProviders().get(i); + if (p.getAuthority() != null) { + final String[] names = p.getAuthority().split(";"); for (int j = 0; j < names.length; j++) { if (mProvidersByAuthority.containsKey(names[j])) { - final PackageParser.Provider other = mProvidersByAuthority.get(names[j]); + final ParsedProvider other = mProvidersByAuthority.get(names[j]); final String otherPackageName = (other != null && other.getComponentName() != null) ? other.getComponentName().getPackageName() : "?"; // if we're installing over the same already-installed package, this is ok - if (!otherPackageName.equals(pkg.packageName)) { + if (!otherPackageName.equals(pkg.getPackageName())) { throw new PackageManagerException( INSTALL_FAILED_CONFLICTING_PROVIDER, "Can't install because provider name " + names[j] - + " (in package " + pkg.applicationInfo.packageName + + " (in package " + pkg.getPackageName() + ") is already used by " + otherPackageName); } } @@ -1064,8 +1123,9 @@ public class ComponentResolver { } } - private static final class ActivityIntentResolver - extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { + private static class ActivityIntentResolver + extends IntentResolver<ParsedActivityIntentInfo, ResolveInfo> { + @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1086,24 +1146,24 @@ public class ComponentResolver { } List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, List<PackageParser.Activity> packageActivities, int userId) { + int flags, List<ParsedActivity> packageActivities, int userId) { if (!sUserManager.exists(userId)) { return null; } if (packageActivities == null) { - return null; + return Collections.emptyList(); } mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int activitiesSize = packageActivities.size(); - ArrayList<PackageParser.ActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize); + ArrayList<ParsedActivityIntentInfo[]> listCut = new ArrayList<>(activitiesSize); - ArrayList<PackageParser.ActivityIntentInfo> intentFilters; + List<ParsedActivityIntentInfo> intentFilters; for (int i = 0; i < activitiesSize; ++i) { intentFilters = packageActivities.get(i).intents; if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ActivityIntentInfo[] array = - new PackageParser.ActivityIntentInfo[intentFilters.size()]; + ParsedActivityIntentInfo[] array = + new ParsedActivityIntentInfo[intentFilters.size()]; intentFilters.toArray(array); listCut.add(array); } @@ -1111,21 +1171,21 @@ public class ComponentResolver { return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } - private void addActivity(PackageParser.Activity a, String type, - List<PackageParser.ActivityIntentInfo> newIntents) { + private void addActivity(ParsedActivity a, String type, + List<ParsedActivityIntentInfo> newIntents) { mActivities.put(a.getComponentName(), a); if (DEBUG_SHOW_INFO) { - final CharSequence label = a.info.nonLocalizedLabel != null - ? a.info.nonLocalizedLabel - : a.info.name; + final CharSequence label = a.nonLocalizedLabel != null + ? a.nonLocalizedLabel + : a.getName(); Log.v(TAG, " " + type + " " + label + ":"); } if (DEBUG_SHOW_INFO) { - Log.v(TAG, " Class=" + a.info.name); + Log.v(TAG, " Class=" + a.getName()); } final int intentsSize = a.intents.size(); for (int j = 0; j < intentsSize; j++) { - PackageParser.ActivityIntentInfo intent = a.intents.get(j); + ParsedActivityIntentInfo intent = a.intents.get(j); if (newIntents != null && "activity".equals(type)) { newIntents.add(intent); } @@ -1134,23 +1194,23 @@ public class ComponentResolver { intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } if (!intent.debugCheck()) { - Log.w(TAG, "==> For Activity " + a.info.name); + Log.w(TAG, "==> For Activity " + a.getName()); } addFilter(intent); } } - private void removeActivity(PackageParser.Activity a, String type) { + private void removeActivity(ParsedActivity a, String type) { mActivities.remove(a.getComponentName()); if (DEBUG_SHOW_INFO) { Log.v(TAG, " " + type + " " - + (a.info.nonLocalizedLabel != null ? a.info.nonLocalizedLabel - : a.info.name) + ":"); - Log.v(TAG, " Class=" + a.info.name); + + (a.nonLocalizedLabel != null ? a.nonLocalizedLabel + : a.getName()) + ":"); + Log.v(TAG, " Class=" + a.getName()); } final int intentsSize = a.intents.size(); for (int j = 0; j < intentsSize; j++) { - PackageParser.ActivityIntentInfo intent = a.intents.get(j); + ParsedActivityIntentInfo intent = a.intents.get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); @@ -1161,11 +1221,11 @@ public class ComponentResolver { @Override protected boolean allowFilterResult( - PackageParser.ActivityIntentInfo filter, List<ResolveInfo> dest) { - ActivityInfo filterAi = filter.activity.info; + ParsedActivityIntentInfo filter, List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; --i) { ActivityInfo destAi = dest.get(i).activityInfo; - if (destAi.name == filterAi.name && destAi.packageName == filterAi.packageName) { + if (Objects.equals(destAi.name, filter.getClassName()) + && Objects.equals(destAi.packageName, filter.getPackageName())) { return false; } } @@ -1173,34 +1233,39 @@ public class ComponentResolver { } @Override - protected ActivityIntentInfo[] newArray(int size) { - return new ActivityIntentInfo[size]; + protected ParsedActivityIntentInfo[] newArray(int size) { + return new ParsedActivityIntentInfo[size]; } @Override - protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) { + protected boolean isFilterStopped(ParsedActivityIntentInfo filter, int userId) { if (!sUserManager.exists(userId)) return true; - PackageParser.Package p = filter.activity.owner; - if (p != null) { - PackageSetting ps = (PackageSetting) p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg == null) { + return false; } - return false; + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); + if (ps == null) { + return false; + } + + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); } @Override protected boolean isPackageForFilter(String packageName, - PackageParser.ActivityIntentInfo info) { - return packageName.equals(info.activity.owner.packageName); + ParsedActivityIntentInfo info) { + return packageName.equals(info.getPackageName()); } - private void log(String reason, ActivityIntentInfo info, int match, + private void log(String reason, ParsedActivityIntentInfo info, int match, int userId) { Slog.w(TAG, reason + "; match: " @@ -1210,7 +1275,7 @@ public class ComponentResolver { } @Override - protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, + protected ResolveInfo newResult(ParsedActivityIntentInfo info, int match, int userId) { if (!sUserManager.exists(userId)) { if (DEBUG) { @@ -1218,7 +1283,29 @@ public class ComponentResolver { } return null; } - if (!sPackageManagerInternal.isEnabledAndMatches(info.activity.info, mFlags, userId)) { + + ParsedActivity activity = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(info.getPackageName()); + if (pkg == null) { + return null; + } + + // TODO(b/135203078): Consider more efficient ways of doing this. + List<ParsedActivity> activities = getResolveList(pkg); + if (activities != null) { + for (ParsedActivity parsedActivity : activities) { + if (Objects.equals(parsedActivity.className, info.getClassName())) { + activity = parsedActivity; + } + } + } + + if (activity == null) { + return null; + } + + if (!sPackageManagerInternal.isEnabledAndMatches(activity, mFlags, userId)) { if (DEBUG) { log("!PackageManagerInternal.isEnabledAndMatches; mFlags=" + DebugUtils.flagsToString(PackageManager.class, "MATCH_", mFlags), @@ -1226,8 +1313,8 @@ public class ComponentResolver { } return null; } - final PackageParser.Activity activity = info.activity; - PackageSetting ps = (PackageSetting) activity.owner.mExtras; + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + info.getPackageName()); if (ps == null) { if (DEBUG) { log("info.activity.owner.mExtras == null", info, match, userId); @@ -1236,10 +1323,10 @@ public class ComponentResolver { } final PackageUserState userState = ps.readUserState(userId); ActivityInfo ai = - PackageParser.generateActivityInfo(activity, mFlags, userState, userId); + PackageInfoUtils.generateActivityInfo(pkg, activity, mFlags, userState, userId); if (ai == null) { if (DEBUG) { - log("Failed to create ActivityInfo based on " + info.activity, info, match, + log("Failed to create ActivityInfo based on " + activity, info, match, userId); } return null; @@ -1289,7 +1376,7 @@ public class ComponentResolver { } res.handleAllWebDataURI = info.handleAllWebDataURI(); res.priority = info.getPriority(); - res.preferredOrder = activity.owner.mPreferredOrder; + res.preferredOrder = pkg.getPreferredOrder(); //System.out.println("Result: " + res.activityInfo.className + // " = " + res.priority); res.match = match; @@ -1314,40 +1401,64 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ActivityIntentInfo filter) { + ParsedActivityIntentInfo filter) { + ParsedActivity activity = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getActivities() != null) { + for (ParsedActivity parsedActivity : pkg.getActivities()) { + if (Objects.equals(parsedActivity.className, filter.getClassName())) { + activity = parsedActivity; + } + } + } + out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(filter.activity))); + out.print(Integer.toHexString(System.identityHashCode(activity))); out.print(' '); - filter.activity.printComponentShortName(out); + ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); out.print(" filter "); out.println(Integer.toHexString(System.identityHashCode(filter))); } @Override - protected Object filterToLabel(PackageParser.ActivityIntentInfo filter) { - return filter.activity; + protected Object filterToLabel(ParsedActivityIntentInfo filter) { + return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - PackageParser.Activity activity = (PackageParser.Activity) label; + ParsedActivityIntentInfo activity = (ParsedActivityIntentInfo) label; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(activity))); out.print(' '); - activity.printComponentShortName(out); + ComponentName.printShortString(out, activity.getPackageName(), activity.getClassName()); if (count > 1) { out.print(" ("); out.print(count); out.print(" filters)"); } out.println(); } + protected List<ParsedActivity> getResolveList(AndroidPackage pkg) { + return pkg.getActivities(); + } + // Keys are String (activity class name), values are Activity. - private final ArrayMap<ComponentName, PackageParser.Activity> mActivities = + private final ArrayMap<ComponentName, ParsedActivity> mActivities = new ArrayMap<>(); private int mFlags; } + // Both receivers and activities share a class, but point to different get methods + private static final class ReceiverIntentResolver extends ActivityIntentResolver { + + @Override + protected List<ParsedActivity> getResolveList(AndroidPackage pkg) { + return pkg.getReceivers(); + } + } + private static final class ProviderIntentResolver - extends IntentResolver<PackageParser.ProviderIntentInfo, ResolveInfo> { + extends IntentResolver<ParsedProviderIntentInfo, ResolveInfo> { @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1367,24 +1478,24 @@ public class ComponentResolver { } List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, List<PackageParser.Provider> packageProviders, int userId) { + int flags, List<ParsedProvider> packageProviders, int userId) { if (!sUserManager.exists(userId)) { return null; } if (packageProviders == null) { - return null; + return Collections.emptyList(); } mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int providersSize = packageProviders.size(); - ArrayList<PackageParser.ProviderIntentInfo[]> listCut = new ArrayList<>(providersSize); + ArrayList<ParsedProviderIntentInfo[]> listCut = new ArrayList<>(providersSize); - ArrayList<PackageParser.ProviderIntentInfo> intentFilters; + List<ParsedProviderIntentInfo> intentFilters; for (int i = 0; i < providersSize; ++i) { - intentFilters = packageProviders.get(i).intents; + intentFilters = packageProviders.get(i).getIntents(); if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ProviderIntentInfo[] array = - new PackageParser.ProviderIntentInfo[intentFilters.size()]; + ParsedProviderIntentInfo[] array = + new ParsedProviderIntentInfo[intentFilters.size()]; intentFilters.toArray(array); listCut.add(array); } @@ -1392,7 +1503,7 @@ public class ComponentResolver { return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } - void addProvider(PackageParser.Provider p) { + void addProvider(ParsedProvider p) { if (mProviders.containsKey(p.getComponentName())) { Slog.w(TAG, "Provider " + p.getComponentName() + " already defined; ignoring"); return; @@ -1401,39 +1512,39 @@ public class ComponentResolver { mProviders.put(p.getComponentName(), p); if (DEBUG_SHOW_INFO) { Log.v(TAG, " " - + (p.info.nonLocalizedLabel != null - ? p.info.nonLocalizedLabel - : p.info.name) + + (p.nonLocalizedLabel != null + ? p.nonLocalizedLabel + : p.getName()) + ":"); - Log.v(TAG, " Class=" + p.info.name); + Log.v(TAG, " Class=" + p.getName()); } - final int intentsSize = p.intents.size(); + final int intentsSize = p.getIntents().size(); int j; for (j = 0; j < intentsSize; j++) { - PackageParser.ProviderIntentInfo intent = p.intents.get(j); + ParsedProviderIntentInfo intent = p.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } if (!intent.debugCheck()) { - Log.w(TAG, "==> For Provider " + p.info.name); + Log.w(TAG, "==> For Provider " + p.getName()); } addFilter(intent); } } - void removeProvider(PackageParser.Provider p) { + void removeProvider(ParsedProvider p) { mProviders.remove(p.getComponentName()); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + (p.info.nonLocalizedLabel != null - ? p.info.nonLocalizedLabel - : p.info.name) + ":"); - Log.v(TAG, " Class=" + p.info.name); + Log.v(TAG, " " + (p.nonLocalizedLabel != null + ? p.nonLocalizedLabel + : p.getName()) + ":"); + Log.v(TAG, " Class=" + p.getName()); } - final int intentsSize = p.intents.size(); + final int intentsSize = p.getIntents().size(); int j; for (j = 0; j < intentsSize; j++) { - PackageParser.ProviderIntentInfo intent = p.intents.get(j); + ParsedProviderIntentInfo intent = p.getIntents().get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); @@ -1444,12 +1555,11 @@ public class ComponentResolver { @Override protected boolean allowFilterResult( - PackageParser.ProviderIntentInfo filter, List<ResolveInfo> dest) { - ProviderInfo filterPi = filter.provider.info; + ParsedProviderIntentInfo filter, List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; i--) { ProviderInfo destPi = dest.get(i).providerInfo; - if (destPi.name == filterPi.name - && destPi.packageName == filterPi.packageName) { + if (Objects.equals(destPi.name, filter.getClassName()) + && Objects.equals(destPi.packageName, filter.getPackageName())) { return false; } } @@ -1457,47 +1567,68 @@ public class ComponentResolver { } @Override - protected PackageParser.ProviderIntentInfo[] newArray(int size) { - return new PackageParser.ProviderIntentInfo[size]; + protected ParsedProviderIntentInfo[] newArray(int size) { + return new ParsedProviderIntentInfo[size]; } @Override - protected boolean isFilterStopped(PackageParser.ProviderIntentInfo filter, int userId) { + protected boolean isFilterStopped(ParsedProviderIntentInfo filter, int userId) { if (!sUserManager.exists(userId)) { return true; } - PackageParser.Package p = filter.provider.owner; - if (p != null) { - PackageSetting ps = (PackageSetting) p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg == null) { + return false; + } + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); + if (ps == null) { + return false; } - return false; + + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); } @Override protected boolean isPackageForFilter(String packageName, - PackageParser.ProviderIntentInfo info) { - return packageName.equals(info.provider.owner.packageName); + ParsedProviderIntentInfo info) { + return packageName.equals(info.getPackageName()); } @Override - protected ResolveInfo newResult(PackageParser.ProviderIntentInfo filter, + protected ResolveInfo newResult(ParsedProviderIntentInfo filter, int match, int userId) { if (!sUserManager.exists(userId)) { return null; } - final PackageParser.ProviderIntentInfo info = filter; - if (!sPackageManagerInternal.isEnabledAndMatches(info.provider.info, mFlags, userId)) { + + ParsedProvider provider = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getProviders() != null) { + for (ParsedProvider parsedProvider : pkg.getProviders()) { + if (Objects.equals(parsedProvider.className, filter.getClassName())) { + provider = parsedProvider; + } + } + } + + if (provider == null) { + return null; + } + + if (!sPackageManagerInternal.isEnabledAndMatches(provider, mFlags, userId)) { return null; } - final PackageParser.Provider provider = info.provider; - PackageSetting ps = (PackageSetting) provider.owner.mExtras; + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); if (ps == null) { return null; } @@ -1507,7 +1638,7 @@ public class ComponentResolver { final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; // throw out filters that aren't visible to instant applications if (matchVisibleToInstantApp - && !(info.isVisibleToInstantApp() || userState.instantApp)) { + && !(filter.isVisibleToInstantApp() || userState.instantApp)) { return null; } // throw out instant application filters if we're not explicitly requesting them @@ -1519,8 +1650,8 @@ public class ComponentResolver { if (userState.instantApp && ps.isUpdateAvailable()) { return null; } - ProviderInfo pi = PackageParser.generateProviderInfo(provider, mFlags, - userState, userId); + ProviderInfo pi = PackageInfoUtils.generateProviderInfo(pkg, provider, + mFlags, userState, userId); if (pi == null) { return null; } @@ -1529,13 +1660,13 @@ public class ComponentResolver { if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = filter; } - res.priority = info.getPriority(); - res.preferredOrder = provider.owner.mPreferredOrder; + res.priority = filter.getPriority(); + res.preferredOrder = pkg.getPreferredOrder(); res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - res.icon = info.icon; + res.isDefault = filter.hasDefault; + res.labelRes = filter.labelRes; + res.nonLocalizedLabel = filter.nonLocalizedLabel; + res.icon = filter.icon; res.system = res.providerInfo.applicationInfo.isSystemApp(); return res; } @@ -1547,26 +1678,37 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ProviderIntentInfo filter) { + ParsedProviderIntentInfo filter) { + ParsedProvider provider = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getProviders() != null) { + for (ParsedProvider parsedProvider : pkg.getProviders()) { + if (Objects.equals(parsedProvider.className, filter.getClassName())) { + provider = parsedProvider; + } + } + } + out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(filter.provider))); + out.print(Integer.toHexString(System.identityHashCode(provider))); out.print(' '); - filter.provider.printComponentShortName(out); + ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); out.print(" filter "); out.println(Integer.toHexString(System.identityHashCode(filter))); } @Override - protected Object filterToLabel(PackageParser.ProviderIntentInfo filter) { - return filter.provider; + protected Object filterToLabel(ParsedProviderIntentInfo filter) { + return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - final PackageParser.Provider provider = (PackageParser.Provider) label; + final ParsedProviderIntentInfo provider = (ParsedProviderIntentInfo) label; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(provider))); out.print(' '); - provider.printComponentShortName(out); + ComponentName.printShortString(out, provider.getPackageName(), provider.getClassName()); if (count > 1) { out.print(" ("); out.print(count); @@ -1575,12 +1717,12 @@ public class ComponentResolver { out.println(); } - private final ArrayMap<ComponentName, PackageParser.Provider> mProviders = new ArrayMap<>(); + private final ArrayMap<ComponentName, ParsedProvider> mProviders = new ArrayMap<>(); private int mFlags; } private static final class ServiceIntentResolver - extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> { + extends IntentResolver<ParsedServiceIntentInfo, ResolveInfo> { @Override public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { @@ -1598,22 +1740,22 @@ public class ComponentResolver { } List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, List<PackageParser.Service> packageServices, int userId) { + int flags, List<ParsedService> packageServices, int userId) { if (!sUserManager.exists(userId)) return null; if (packageServices == null) { - return null; + return Collections.emptyList(); } mFlags = flags; final boolean defaultOnly = (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0; final int servicesSize = packageServices.size(); - ArrayList<PackageParser.ServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize); + ArrayList<ParsedServiceIntentInfo[]> listCut = new ArrayList<>(servicesSize); - ArrayList<PackageParser.ServiceIntentInfo> intentFilters; + List<ParsedServiceIntentInfo> intentFilters; for (int i = 0; i < servicesSize; ++i) { intentFilters = packageServices.get(i).intents; if (intentFilters != null && intentFilters.size() > 0) { - PackageParser.ServiceIntentInfo[] array = - new PackageParser.ServiceIntentInfo[intentFilters.size()]; + ParsedServiceIntentInfo[] array = + new ParsedServiceIntentInfo[intentFilters.size()]; intentFilters.toArray(array); listCut.add(array); } @@ -1621,40 +1763,40 @@ public class ComponentResolver { return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } - void addService(PackageParser.Service s) { + void addService(ParsedService s) { mServices.put(s.getComponentName(), s); if (DEBUG_SHOW_INFO) { Log.v(TAG, " " - + (s.info.nonLocalizedLabel != null - ? s.info.nonLocalizedLabel : s.info.name) + ":"); - Log.v(TAG, " Class=" + s.info.name); + + (s.nonLocalizedLabel != null + ? s.nonLocalizedLabel : s.getName()) + ":"); + Log.v(TAG, " Class=" + s.getName()); } final int intentsSize = s.intents.size(); int j; for (j = 0; j < intentsSize; j++) { - PackageParser.ServiceIntentInfo intent = s.intents.get(j); + ParsedServiceIntentInfo intent = s.intents.get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); } if (!intent.debugCheck()) { - Log.w(TAG, "==> For Service " + s.info.name); + Log.w(TAG, "==> For Service " + s.getName()); } addFilter(intent); } } - void removeService(PackageParser.Service s) { + void removeService(ParsedService s) { mServices.remove(s.getComponentName()); if (DEBUG_SHOW_INFO) { - Log.v(TAG, " " + (s.info.nonLocalizedLabel != null - ? s.info.nonLocalizedLabel : s.info.name) + ":"); - Log.v(TAG, " Class=" + s.info.name); + Log.v(TAG, " " + (s.nonLocalizedLabel != null + ? s.nonLocalizedLabel : s.getName()) + ":"); + Log.v(TAG, " Class=" + s.getName()); } final int intentsSize = s.intents.size(); int j; for (j = 0; j < intentsSize; j++) { - PackageParser.ServiceIntentInfo intent = s.intents.get(j); + ParsedServiceIntentInfo intent = s.intents.get(j); if (DEBUG_SHOW_INFO) { Log.v(TAG, " IntentFilter:"); intent.dump(new LogPrinter(Log.VERBOSE, TAG), " "); @@ -1665,12 +1807,11 @@ public class ComponentResolver { @Override protected boolean allowFilterResult( - PackageParser.ServiceIntentInfo filter, List<ResolveInfo> dest) { - ServiceInfo filterSi = filter.service.info; + ParsedServiceIntentInfo filter, List<ResolveInfo> dest) { for (int i = dest.size() - 1; i >= 0; --i) { ServiceInfo destAi = dest.get(i).serviceInfo; - if (destAi.name == filterSi.name - && destAi.packageName == filterSi.packageName) { + if (Objects.equals(destAi.name, filter.getClassName()) + && Objects.equals(destAi.packageName, filter.getPackageName())) { return false; } } @@ -1678,48 +1819,69 @@ public class ComponentResolver { } @Override - protected PackageParser.ServiceIntentInfo[] newArray(int size) { - return new PackageParser.ServiceIntentInfo[size]; + protected ParsedServiceIntentInfo[] newArray(int size) { + return new ParsedServiceIntentInfo[size]; } @Override - protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) { + protected boolean isFilterStopped(ParsedServiceIntentInfo filter, int userId) { if (!sUserManager.exists(userId)) return true; - PackageParser.Package p = filter.service.owner; - if (p != null) { - PackageSetting ps = (PackageSetting) p.mExtras; - if (ps != null) { - // System apps are never considered stopped for purposes of - // filtering, because there may be no way for the user to - // actually re-launch them. - return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 - && ps.getStopped(userId); - } + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg == null) { + return false; } - return false; + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); + if (ps == null) { + return false; + } + + // System apps are never considered stopped for purposes of + // filtering, because there may be no way for the user to + // actually re-launch them. + return (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0 + && ps.getStopped(userId); } @Override protected boolean isPackageForFilter(String packageName, - PackageParser.ServiceIntentInfo info) { - return packageName.equals(info.service.owner.packageName); + ParsedServiceIntentInfo info) { + return packageName.equals(info.getPackageName()); } @Override - protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, + protected ResolveInfo newResult(ParsedServiceIntentInfo filter, int match, int userId) { if (!sUserManager.exists(userId)) return null; - final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo) filter; - if (!sPackageManagerInternal.isEnabledAndMatches(info.service.info, mFlags, userId)) { + + ParsedService service = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getServices() != null) { + for (ParsedService parsedService : pkg.getServices()) { + if (Objects.equals(parsedService.className, filter.getClassName())) { + service = parsedService; + } + } + } + + if (service == null) { + return null; + } + + if (!sPackageManagerInternal.isEnabledAndMatches(service, mFlags, userId)) { return null; } - final PackageParser.Service service = info.service; - PackageSetting ps = (PackageSetting) service.owner.mExtras; + + PackageSetting ps = (PackageSetting) sPackageManagerInternal.getPackageSetting( + filter.getPackageName()); if (ps == null) { return null; } final PackageUserState userState = ps.readUserState(userId); - ServiceInfo si = PackageParser.generateServiceInfo(service, mFlags, + ServiceInfo si = PackageInfoUtils.generateServiceInfo(pkg, service, mFlags, userState, userId); if (si == null) { return null; @@ -1729,7 +1891,7 @@ public class ComponentResolver { final boolean isInstantApp = (mFlags & PackageManager.MATCH_INSTANT) != 0; // throw out filters that aren't visible to ephemeral apps if (matchVisibleToInstantApp - && !(info.isVisibleToInstantApp() || userState.instantApp)) { + && !(filter.isVisibleToInstantApp() || userState.instantApp)) { return null; } // throw out ephemeral filters if we're not explicitly requesting them @@ -1746,13 +1908,13 @@ public class ComponentResolver { if ((mFlags & PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = filter; } - res.priority = info.getPriority(); - res.preferredOrder = service.owner.mPreferredOrder; + res.priority = filter.getPriority(); + res.preferredOrder = pkg.getPreferredOrder(); res.match = match; - res.isDefault = info.hasDefault; - res.labelRes = info.labelRes; - res.nonLocalizedLabel = info.nonLocalizedLabel; - res.icon = info.icon; + res.isDefault = filter.hasDefault; + res.labelRes = filter.labelRes; + res.nonLocalizedLabel = filter.nonLocalizedLabel; + res.icon = filter.icon; res.system = res.serviceInfo.applicationInfo.isSystemApp(); return res; } @@ -1764,31 +1926,42 @@ public class ComponentResolver { @Override protected void dumpFilter(PrintWriter out, String prefix, - PackageParser.ServiceIntentInfo filter) { + ParsedServiceIntentInfo filter) { + ParsedService service = null; + + AndroidPackage pkg = sPackageManagerInternal.getPackage(filter.getPackageName()); + if (pkg != null && pkg.getServices() != null) { + for (ParsedService parsedService : pkg.getServices()) { + if (Objects.equals(parsedService.className, filter.getClassName())) { + service = parsedService; + } + } + } + out.print(prefix); - out.print(Integer.toHexString(System.identityHashCode(filter.service))); + out.print(Integer.toHexString(System.identityHashCode(service))); out.print(' '); - filter.service.printComponentShortName(out); + ComponentName.printShortString(out, filter.getPackageName(), filter.getClassName()); out.print(" filter "); out.print(Integer.toHexString(System.identityHashCode(filter))); - if (filter.service.info.permission != null) { - out.print(" permission "); out.println(filter.service.info.permission); + if (service != null && service.getPermission() != null) { + out.print(" permission "); out.println(service.getPermission()); } else { out.println(); } } @Override - protected Object filterToLabel(PackageParser.ServiceIntentInfo filter) { - return filter.service; + protected Object filterToLabel(ParsedServiceIntentInfo filter) { + return filter; } protected void dumpFilterLabel(PrintWriter out, String prefix, Object label, int count) { - final PackageParser.Service service = (PackageParser.Service) label; + final ParsedServiceIntentInfo service = (ParsedServiceIntentInfo) label; out.print(prefix); out.print(Integer.toHexString(System.identityHashCode(service))); out.print(' '); - service.printComponentShortName(out); + ComponentName.printShortString(out, service.getPackageName(), service.getClassName()); if (count > 1) { out.print(" ("); out.print(count); out.print(" filters)"); } @@ -1796,7 +1969,7 @@ public class ComponentResolver { } // Keys are String (activity class name), values are Activity. - private final ArrayMap<ComponentName, PackageParser.Service> mServices = new ArrayMap<>(); + private final ArrayMap<ComponentName, ParsedService> mServices = new ArrayMap<>(); private int mFlags; } @@ -1885,7 +2058,7 @@ public class ComponentResolver { /** Generic to create an {@link Iterator} for a data type */ static class IterGenerator<E> { - public Iterator<E> generate(ActivityIntentInfo info) { + public Iterator<E> generate(ParsedActivityIntentInfo info) { return null; } } @@ -1893,7 +2066,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent actions */ static class ActionIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ActivityIntentInfo info) { + public Iterator<String> generate(ParsedActivityIntentInfo info) { return info.actionsIterator(); } } @@ -1901,7 +2074,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent categories */ static class CategoriesIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ActivityIntentInfo info) { + public Iterator<String> generate(ParsedActivityIntentInfo info) { return info.categoriesIterator(); } } @@ -1909,7 +2082,7 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent schemes */ static class SchemesIterGenerator extends IterGenerator<String> { @Override - public Iterator<String> generate(ActivityIntentInfo info) { + public Iterator<String> generate(ParsedActivityIntentInfo info) { return info.schemesIterator(); } } @@ -1917,9 +2090,39 @@ public class ComponentResolver { /** Create an {@link Iterator} for intent authorities */ static class AuthoritiesIterGenerator extends IterGenerator<IntentFilter.AuthorityEntry> { @Override - public Iterator<IntentFilter.AuthorityEntry> generate(ActivityIntentInfo info) { + public Iterator<IntentFilter.AuthorityEntry> generate(ParsedActivityIntentInfo info) { return info.authoritiesIterator(); } } + // TODO(b/135203078): Document or remove this if possible. + class EffectiveProvider extends ParsedProvider { + + private String mEffectiveAuthority; + private boolean mEffectiveSyncable; + + public EffectiveProvider(ParsedProvider parsedProvider) { + this.setFrom(parsedProvider); + this.mEffectiveAuthority = parsedProvider.getAuthority(); + this.mEffectiveSyncable = parsedProvider.isSyncable(); + } + + public void setEffectiveAuthority(String authority) { + this.mEffectiveAuthority = authority; + } + + public void setEffectiveSyncable(boolean syncable) { + this.mEffectiveSyncable = syncable; + } + + @Override + public String getAuthority() { + return mEffectiveAuthority; + } + + @Override + public boolean isSyncable() { + return mEffectiveSyncable; + } + } } diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index 9e04c4b69bd0..f9113fa38825 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -20,9 +20,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.InstantAppInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; @@ -137,7 +139,7 @@ class InstantAppRegistry { public byte[] getInstantAppCookieLPw(@NonNull String packageName, @UserIdInt int userId) { // Only installed packages can get their own cookie - PackageParser.Package pkg = mService.mPackages.get(packageName); + AndroidPackage pkg = mService.mPackages.get(packageName); if (pkg == null) { return null; } @@ -171,7 +173,7 @@ class InstantAppRegistry { } // Only an installed package can set its own cookie - PackageParser.Package pkg = mService.mPackages.get(packageName); + AndroidPackage pkg = mService.mPackages.get(packageName); if (pkg == null) { return false; } @@ -264,15 +266,15 @@ class InstantAppRegistry { } @GuardedBy("mService.mLock") - public void onPackageInstalledLPw(@NonNull PackageParser.Package pkg, @NonNull int[] userIds) { - PackageSetting ps = (PackageSetting) pkg.mExtras; + public void onPackageInstalledLPw(@NonNull AndroidPackage pkg, @NonNull int[] userIds) { + PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null) { return; } for (int userId : userIds) { // Ignore not installed apps - if (mService.mPackages.get(pkg.packageName) == null || !ps.getInstalled(userId)) { + if (mService.mPackages.get(pkg.getPackageName()) == null || !ps.getInstalled(userId)) { continue; } @@ -286,16 +288,16 @@ class InstantAppRegistry { // Remove the in-memory state removeUninstalledInstantAppStateLPw((UninstalledInstantAppState state) -> - state.mInstantAppInfo.getPackageName().equals(pkg.packageName), + state.mInstantAppInfo.getPackageName().equals(pkg.getPackageName()), userId); // Remove the on-disk state except the cookie - File instantAppDir = getInstantApplicationDir(pkg.packageName, userId); + File instantAppDir = getInstantApplicationDir(pkg.getPackageName(), userId); new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete(); new File(instantAppDir, INSTANT_APP_ICON_FILE).delete(); // If app signature changed - wipe the cookie - File currentCookieFile = peekInstantCookieFile(pkg.packageName, userId); + File currentCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId); if (currentCookieFile == null) { continue; } @@ -310,7 +312,7 @@ class InstantAppRegistry { // We prefer the modern computation procedure where all certs are taken // into account but also allow the value from the old computation to avoid // data loss. - if (pkg.mSigningDetails.checkCapability(currentCookieSha256, + if (pkg.getSigningDetails().checkCapability(currentCookieSha256, PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) { return; } @@ -318,7 +320,7 @@ class InstantAppRegistry { // For backwards compatibility we accept match based on any signature, since we may have // recorded only the first for multiply-signed packages final String[] signaturesSha256Digests = - PackageUtils.computeSignaturesSha256Digests(pkg.mSigningDetails.signatures); + PackageUtils.computeSignaturesSha256Digests(pkg.getSigningDetails().signatures); for (String s : signaturesSha256Digests) { if (s.equals(currentCookieSha256)) { return; @@ -326,7 +328,7 @@ class InstantAppRegistry { } // Sorry, you are out of luck - different signatures - nuke data - Slog.i(LOG_TAG, "Signature for package " + pkg.packageName + Slog.i(LOG_TAG, "Signature for package " + pkg.getPackageName() + " changed - dropping cookie"); // Make sure a pending write for the old signed app is cancelled mCookiePersistence.cancelPendingPersistLPw(pkg, userId); @@ -335,15 +337,15 @@ class InstantAppRegistry { } @GuardedBy("mService.mLock") - public void onPackageUninstalledLPw(@NonNull PackageParser.Package pkg, + public void onPackageUninstalledLPw(@NonNull AndroidPackage pkg, @NonNull int[] userIds) { - PackageSetting ps = (PackageSetting) pkg.mExtras; + PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null) { return; } for (int userId : userIds) { - if (mService.mPackages.get(pkg.packageName) != null && ps.getInstalled(userId)) { + if (mService.mPackages.get(pkg.getPackageName()) != null && ps.getInstalled(userId)) { continue; } @@ -353,7 +355,7 @@ class InstantAppRegistry { removeInstantAppLPw(userId, ps.appId); } else { // Deleting an app prunes all instant state such as cookie - deleteDir(getInstantApplicationDir(pkg.packageName, userId)); + deleteDir(getInstantApplicationDir(pkg.getPackageName(), userId)); mCookiePersistence.cancelPendingPersistLPw(pkg, userId); removeAppLPw(userId, ps.appId); } @@ -487,7 +489,7 @@ class InstantAppRegistry { } @GuardedBy("mService.mLock") - private void addUninstalledInstantAppLPw(@NonNull PackageParser.Package pkg, + private void addUninstalledInstantAppLPw(@NonNull AndroidPackage pkg, @UserIdInt int userId) { InstantAppInfo uninstalledApp = createInstantAppInfoForPackage( pkg, userId, false); @@ -511,14 +513,15 @@ class InstantAppRegistry { writeInstantApplicationIconLPw(pkg, userId); } - private void writeInstantApplicationIconLPw(@NonNull PackageParser.Package pkg, + private void writeInstantApplicationIconLPw(@NonNull AndroidPackage pkg, @UserIdInt int userId) { - File appDir = getInstantApplicationDir(pkg.packageName, userId); + File appDir = getInstantApplicationDir(pkg.getPackageName(), userId); if (!appDir.exists()) { return; } - Drawable icon = pkg.applicationInfo.loadIcon(mService.mContext.getPackageManager()); + // TODO(b/135203078): Remove toAppInfo call? Requires significant additions/changes to PM + Drawable icon = pkg.toAppInfo().loadIcon(mService.mContext.getPackageManager()); final Bitmap bitmap; if (icon instanceof BitmapDrawable) { @@ -531,7 +534,7 @@ class InstantAppRegistry { icon.draw(canvas); } - File iconFile = new File(getInstantApplicationDir(pkg.packageName, userId), + File iconFile = new File(getInstantApplicationDir(pkg.getPackageName(), userId), INSTANT_APP_ICON_FILE); try (FileOutputStream out = new FileOutputStream(iconFile)) { @@ -690,14 +693,16 @@ class InstantAppRegistry { final int packageCount = mService.mPackages.size(); for (int i = 0; i < packageCount; i++) { - final PackageParser.Package pkg = mService.mPackages.valueAt(i); + final AndroidPackage pkg = mService.mPackages.valueAt(i); if (now - pkg.getLatestPackageUseTimeInMills() < maxInstalledCacheDuration) { continue; } - if (!(pkg.mExtras instanceof PackageSetting)) { + + final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); + if (ps == null) { continue; } - final PackageSetting ps = (PackageSetting) pkg.mExtras; + boolean installedOnlyAsInstantApp = false; for (int userId : allUsers) { if (ps.getInstalled(userId)) { @@ -713,14 +718,14 @@ class InstantAppRegistry { if (packagesToDelete == null) { packagesToDelete = new ArrayList<>(); } - packagesToDelete.add(pkg.packageName); + packagesToDelete.add(pkg.getPackageName()); } } if (packagesToDelete != null) { packagesToDelete.sort((String lhs, String rhs) -> { - final PackageParser.Package lhsPkg = mService.mPackages.get(lhs); - final PackageParser.Package rhsPkg = mService.mPackages.get(rhs); + final AndroidPackage lhsPkg = mService.mPackages.get(lhs); + final AndroidPackage rhsPkg = mService.mPackages.get(rhs); if (lhsPkg == null && rhsPkg == null) { return 0; } else if (lhsPkg == null) { @@ -735,18 +740,23 @@ class InstantAppRegistry { rhsPkg.getLatestPackageUseTimeInMills()) { return -1; } else { - if (lhsPkg.mExtras instanceof PackageSetting - && rhsPkg.mExtras instanceof PackageSetting) { - final PackageSetting lhsPs = (PackageSetting) lhsPkg.mExtras; - final PackageSetting rhsPs = (PackageSetting) rhsPkg.mExtras; - if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) { - return 1; - } else { - return -1; - } - } else { + final PackageSetting lhsPs = mService.getPackageSetting( + lhsPkg.getPackageName()); + if (lhsPs == null) { + return 0; + } + + final PackageSetting rhsPs = mService.getPackageSetting( + rhsPkg.getPackageName()); + if (rhsPs == null) { return 0; } + + if (lhsPs.firstInstallTime > rhsPs.firstInstallTime) { + return 1; + } else { + return -1; + } } } }); @@ -818,8 +828,8 @@ class InstantAppRegistry { final int packageCount = mService.mPackages.size(); for (int i = 0; i < packageCount; i++) { - final PackageParser.Package pkg = mService.mPackages.valueAt(i); - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final AndroidPackage pkg = mService.mPackages.valueAt(i); + final PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null || !ps.getInstantApp(userId)) { continue; } @@ -839,9 +849,9 @@ class InstantAppRegistry { private @NonNull InstantAppInfo createInstantAppInfoForPackage( - @NonNull PackageParser.Package pkg, @UserIdInt int userId, + @NonNull AndroidPackage pkg, @UserIdInt int userId, boolean addApplicationInfo) { - PackageSetting ps = (PackageSetting) pkg.mExtras; + PackageSetting ps = mService.getPackageSetting(pkg.getPackageName()); if (ps == null) { return null; } @@ -849,19 +859,20 @@ class InstantAppRegistry { return null; } - String[] requestedPermissions = new String[pkg.requestedPermissions.size()]; - pkg.requestedPermissions.toArray(requestedPermissions); + String[] requestedPermissions = new String[pkg.getRequestedPermissions().size()]; + pkg.getRequestedPermissions().toArray(requestedPermissions); Set<String> permissions = ps.getPermissionsState().getPermissions(userId); String[] grantedPermissions = new String[permissions.size()]; permissions.toArray(grantedPermissions); + ApplicationInfo appInfo = pkg.toAppInfo(); if (addApplicationInfo) { - return new InstantAppInfo(pkg.applicationInfo, + return new InstantAppInfo(appInfo, requestedPermissions, grantedPermissions); } else { - return new InstantAppInfo(pkg.applicationInfo.packageName, - pkg.applicationInfo.loadLabel(mService.mContext.getPackageManager()), + return new InstantAppInfo(appInfo.packageName, + appInfo.loadLabel(mService.mContext.getPackageManager()), requestedPermissions, grantedPermissions); } } @@ -887,10 +898,10 @@ class InstantAppRegistry { return uninstalledApps; } - private void propagateInstantAppPermissionsIfNeeded(@NonNull PackageParser.Package pkg, + private void propagateInstantAppPermissionsIfNeeded(@NonNull AndroidPackage pkg, @UserIdInt int userId) { InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo( - pkg.packageName, userId); + pkg.getPackageName(), userId); if (appInfo == null) { return; } @@ -902,8 +913,10 @@ class InstantAppRegistry { for (String grantedPermission : appInfo.getGrantedPermissions()) { final boolean propagatePermission = mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission); - if (propagatePermission && pkg.requestedPermissions.contains(grantedPermission)) { - mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId); + if (propagatePermission && pkg.getRequestedPermissions().contains( + grantedPermission)) { + mService.grantRuntimePermission(pkg.getPackageName(), grantedPermission, + userId); } } } finally { @@ -1188,18 +1201,19 @@ class InstantAppRegistry { super(looper); } - public void schedulePersistLPw(@UserIdInt int userId, @NonNull PackageParser.Package pkg, + public void schedulePersistLPw(@UserIdInt int userId, @NonNull AndroidPackage pkg, @NonNull byte[] cookie) { // Before we used only the first signature to compute the SHA 256 but some // apps could be singed by multiple certs and the cert order is undefined. // We prefer the modern computation procedure where all certs are taken // into account and delete the file derived via the legacy hash computation. - File newCookieFile = computeInstantCookieFile(pkg.packageName, - PackageUtils.computeSignaturesSha256Digest(pkg.mSigningDetails.signatures), userId); - if (!pkg.mSigningDetails.hasSignatures()) { + File newCookieFile = computeInstantCookieFile(pkg.getPackageName(), + PackageUtils.computeSignaturesSha256Digest(pkg.getSigningDetails().signatures), + userId); + if (!pkg.getSigningDetails().hasSignatures()) { Slog.wtf(LOG_TAG, "Parsed Instant App contains no valid signatures!"); } - File oldCookieFile = peekInstantCookieFile(pkg.packageName, userId); + File oldCookieFile = peekInstantCookieFile(pkg.getPackageName(), userId); if (oldCookieFile != null && !newCookieFile.equals(oldCookieFile)) { oldCookieFile.delete(); } @@ -1209,12 +1223,12 @@ class InstantAppRegistry { PERSIST_COOKIE_DELAY_MILLIS); } - public @Nullable byte[] getPendingPersistCookieLPr(@NonNull PackageParser.Package pkg, + public @Nullable byte[] getPendingPersistCookieLPr(@NonNull AndroidPackage pkg, @UserIdInt int userId) { ArrayMap<String, SomeArgs> pendingWorkForUser = mPendingPersistCookies.get(userId); if (pendingWorkForUser != null) { - SomeArgs state = pendingWorkForUser.get(pkg.packageName); + SomeArgs state = pendingWorkForUser.get(pkg.getPackageName()); if (state != null) { return (byte[]) state.arg1; } @@ -1222,7 +1236,7 @@ class InstantAppRegistry { return null; } - public void cancelPendingPersistLPw(@NonNull PackageParser.Package pkg, + public void cancelPendingPersistLPw(@NonNull AndroidPackage pkg, @UserIdInt int userId) { removeMessages(userId, pkg); SomeArgs state = removePendingPersistCookieLPr(pkg, userId); @@ -1232,7 +1246,7 @@ class InstantAppRegistry { } private void addPendingPersistCookieLPw(@UserIdInt int userId, - @NonNull PackageParser.Package pkg, @NonNull byte[] cookie, + @NonNull AndroidPackage pkg, @NonNull byte[] cookie, @NonNull File cookieFile) { ArrayMap<String, SomeArgs> pendingWorkForUser = mPendingPersistCookies.get(userId); @@ -1243,16 +1257,16 @@ class InstantAppRegistry { SomeArgs args = SomeArgs.obtain(); args.arg1 = cookie; args.arg2 = cookieFile; - pendingWorkForUser.put(pkg.packageName, args); + pendingWorkForUser.put(pkg.getPackageName(), args); } - private SomeArgs removePendingPersistCookieLPr(@NonNull PackageParser.Package pkg, + private SomeArgs removePendingPersistCookieLPr(@NonNull AndroidPackage pkg, @UserIdInt int userId) { ArrayMap<String, SomeArgs> pendingWorkForUser = mPendingPersistCookies.get(userId); SomeArgs state = null; if (pendingWorkForUser != null) { - state = pendingWorkForUser.remove(pkg.packageName); + state = pendingWorkForUser.remove(pkg.getPackageName()); if (pendingWorkForUser.isEmpty()) { mPendingPersistCookies.remove(userId); } @@ -1263,7 +1277,7 @@ class InstantAppRegistry { @Override public void handleMessage(Message message) { int userId = message.what; - PackageParser.Package pkg = (PackageParser.Package) message.obj; + AndroidPackage pkg = (AndroidPackage) message.obj; SomeArgs state = removePendingPersistCookieLPr(pkg, userId); if (state == null) { return; @@ -1271,7 +1285,7 @@ class InstantAppRegistry { byte[] cookie = (byte[]) state.arg1; File cookieFile = (File) state.arg2; state.recycle(); - persistInstantApplicationCookie(cookie, pkg.packageName, cookieFile, userId); + persistInstantApplicationCookie(cookie, pkg.getPackageName(), cookieFile, userId); } } } diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java index ec48713b0874..0a065eba4309 100644 --- a/services/core/java/com/android/server/pm/InstructionSets.java +++ b/services/core/java/com/android/server/pm/InstructionSets.java @@ -16,7 +16,7 @@ package com.android.server.pm; -import android.content.pm.ApplicationInfo; +import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.SystemProperties; import android.text.TextUtils; @@ -35,30 +35,16 @@ import java.util.List; public class InstructionSets { private static final String PREFERRED_INSTRUCTION_SET = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); - public static String[] getAppDexInstructionSets(ApplicationInfo info) { - if (info.primaryCpuAbi != null) { - if (info.secondaryCpuAbi != null) { - return new String[] { - VMRuntime.getInstructionSet(info.primaryCpuAbi), - VMRuntime.getInstructionSet(info.secondaryCpuAbi) }; - } else { - return new String[] { - VMRuntime.getInstructionSet(info.primaryCpuAbi) }; - } - } - return new String[] { getPreferredInstructionSet() }; - } - - public static String[] getAppDexInstructionSets(PackageSetting ps) { - if (ps.primaryCpuAbiString != null) { - if (ps.secondaryCpuAbiString != null) { + public static String[] getAppDexInstructionSets(String primaryCpuAbi, String secondaryCpuAbi) { + if (primaryCpuAbi != null) { + if (secondaryCpuAbi != null) { return new String[] { - VMRuntime.getInstructionSet(ps.primaryCpuAbiString), - VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) }; + VMRuntime.getInstructionSet(primaryCpuAbi), + VMRuntime.getInstructionSet(secondaryCpuAbi) }; } else { return new String[] { - VMRuntime.getInstructionSet(ps.primaryCpuAbiString) }; + VMRuntime.getInstructionSet(primaryCpuAbi) }; } } @@ -124,4 +110,12 @@ public class InstructionSets { return VMRuntime.getInstructionSet(abis.primary); } + public static String getPrimaryInstructionSet(AndroidPackage pkg) { + if (pkg.getPrimaryCpuAbi() == null) { + return getPreferredInstructionSet(); + } + + return VMRuntime.getInstructionSet(pkg.getPrimaryCpuAbi()); + } + } diff --git a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java index a4e9d103b6da..c97d85df00ab 100644 --- a/services/core/java/com/android/server/pm/IntentFilterVerificationState.java +++ b/services/core/java/com/android/server/pm/IntentFilterVerificationState.java @@ -17,7 +17,7 @@ package com.android.server.pm; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.parsing.ComponentParseUtils; import android.util.ArraySet; import android.util.Slog; @@ -35,7 +35,7 @@ public class IntentFilterVerificationState { private int mState; - private ArrayList<PackageParser.ActivityIntentInfo> mFilters = new ArrayList<>(); + private ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> mFilters = new ArrayList<>(); private ArraySet<String> mHosts = new ArraySet<>(); private int mUserId; @@ -66,7 +66,7 @@ public class IntentFilterVerificationState { setState(STATE_VERIFICATION_PENDING); } - public ArrayList<PackageParser.ActivityIntentInfo> getFilters() { + public ArrayList<ComponentParseUtils.ParsedActivityIntentInfo> getFilters() { return mFilters; } @@ -123,7 +123,7 @@ public class IntentFilterVerificationState { return false; } - public void addFilter(PackageParser.ActivityIntentInfo filter) { + public void addFilter(ComponentParseUtils.ParsedActivityIntentInfo filter) { mFilters.add(filter); mHosts.addAll(filter.getHostsList()); } diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java index 93d3b77511bc..70c0f8d98447 100644 --- a/services/core/java/com/android/server/pm/KeySetManagerService.java +++ b/services/core/java/com/android/server/pm/KeySetManagerService.java @@ -20,23 +20,26 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; import static com.android.server.pm.PackageManagerService.SCAN_INITIAL; -import com.android.internal.util.Preconditions; import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Base64; -import android.util.Slog; import android.util.LongSparseArray; +import android.util.Slog; -import java.io.IOException; -import java.io.PrintWriter; -import java.security.PublicKey; -import java.util.Set; +import com.android.internal.util.Preconditions; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.IOException; +import java.io.PrintWriter; +import java.security.PublicKey; +import java.util.Map; +import java.util.Set; + /* * Manages system-wide KeySet state. */ @@ -182,33 +185,31 @@ public class KeySetManagerService { * * Returns true if the package can safely be added to the keyset metadata. */ - public void assertScannedPackageValid(PackageParser.Package pkg) + public void assertScannedPackageValid(AndroidPackage pkg) throws PackageManagerException { - if (pkg == null || pkg.packageName == null) { + if (pkg == null || pkg.getPackageName() == null) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Passed invalid package to keyset validation."); } - ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys; + ArraySet<PublicKey> signingKeys = pkg.getSigningDetails().publicKeys; if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package has invalid signing-key-set."); } - ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping; + Map<String, ArraySet<PublicKey>> definedMapping = pkg.getKeySetMapping(); if (definedMapping != null) { if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package has null defined key set."); } - int defMapSize = definedMapping.size(); - for (int i = 0; i < defMapSize; i++) { - if (!(definedMapping.valueAt(i).size() > 0) - || definedMapping.valueAt(i).contains(null)) { + for (ArraySet<PublicKey> value : definedMapping.values()) { + if (!(value.size() > 0) || value.contains(null)) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Package has null/no public keys for defined key-sets."); } } } - ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets; + Set<String> upgradeAliases = pkg.getUpgradeKeySets(); if (upgradeAliases != null) { if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, @@ -217,17 +218,17 @@ public class KeySetManagerService { } } - public void addScannedPackageLPw(PackageParser.Package pkg) { + public void addScannedPackageLPw(AndroidPackage pkg) { Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms."); - Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms."); - PackageSetting ps = mPackages.get(pkg.packageName); - Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName + Preconditions.checkNotNull(pkg.getPackageName(), "Attempted to add null pkg to ksms."); + PackageSetting ps = mPackages.get(pkg.getPackageName()); + Preconditions.checkNotNull(ps, "pkg: " + pkg.getPackageName() + "does not have a corresponding entry in mPackages."); - addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys); - if (pkg.mKeySetMapping != null) { - addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping); - if (pkg.mUpgradeKeySets != null) { - addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets); + addSigningKeySetToPackageLPw(ps, pkg.getSigningDetails().publicKeys); + if (pkg.getKeySetMapping() != null) { + addDefinedKeySetsToPackageLPw(ps, pkg.getKeySetMapping()); + if (pkg.getUpgradeKeySets() != null) { + addUpgradeKeySetsToPackageLPw(ps, pkg.getUpgradeKeySets()); } } } @@ -280,15 +281,14 @@ public class KeySetManagerService { * Remove any KeySets the package no longer defines. */ void addDefinedKeySetsToPackageLPw(PackageSetting pkg, - ArrayMap<String, ArraySet<PublicKey>> definedMapping) { + Map<String, ArraySet<PublicKey>> definedMapping) { ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases(); /* add all of the newly defined KeySets */ - ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>(); - final int defMapSize = definedMapping.size(); - for (int i = 0; i < defMapSize; i++) { - String alias = definedMapping.keyAt(i); - ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i); + Map<String, Long> newKeySetAliases = new ArrayMap<>(); + for (Map.Entry<String, ArraySet<PublicKey>> entry : definedMapping.entrySet()) { + String alias = entry.getKey(); + ArraySet<PublicKey> pubKeys = entry.getValue(); if (alias != null && pubKeys != null && pubKeys.size() > 0) { KeySetHandle ks = addKeySetLPw(pubKeys); newKeySetAliases.put(alias, ks.getId()); @@ -313,12 +313,10 @@ public class KeySetManagerService { * after all of the defined KeySets have been added. */ void addUpgradeKeySetsToPackageLPw(PackageSetting pkg, - ArraySet<String> upgradeAliases) { - final int uaSize = upgradeAliases.size(); - for (int i = 0; i < uaSize; i++) { - pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i)); + Set<String> upgradeAliases) { + for (String upgradeAlias : upgradeAliases) { + pkg.keySetData.addUpgradeKeySet(upgradeAlias); } - return; } /** @@ -364,14 +362,14 @@ public class KeySetManagerService { return true; } - public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, - PackageParser.Package newPkg) { + public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, AndroidPackage pkg) { // Upgrade keysets are being used. Determine if new package has a superset of the // required keys. long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets(); for (int i = 0; i < upgradeKeySets.length; i++) { Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]); - if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) { + if (upgradeSet != null + && pkg.getSigningDetails().publicKeys.containsAll(upgradeSet)) { return true; } } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 3464cab99d93..c844f1bd95ff 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -40,13 +40,13 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutServiceInternal; import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; import android.content.pm.UserInfo; +import android.content.pm.parsing.AndroidPackage; import android.graphics.Rect; import android.net.Uri; import android.os.Binder; @@ -445,7 +445,7 @@ public class LauncherAppsService extends SystemService { } final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); - final PackageParser.Package pkg = pmInt.getPackage(appInfo.packageName); + final AndroidPackage pkg = pmInt.getPackage(appInfo.packageName); if (pkg == null) { // Should not happen, but we shouldn't be failing if it does return false; @@ -456,8 +456,8 @@ public class LauncherAppsService extends SystemService { appInfo.packageName); } - private boolean requestsPermissions(@NonNull PackageParser.Package pkg) { - return !ArrayUtils.isEmpty(pkg.requestedPermissions); + private boolean requestsPermissions(@NonNull AndroidPackage pkg) { + return !ArrayUtils.isEmpty(pkg.getRequestedPermissions()); } private boolean hasDefaultEnableLauncherActivity(@NonNull String packageName) { diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index d49ecdda679d..ae7a4a7b81f5 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -22,7 +22,7 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import android.annotation.Nullable; import android.content.Context; import android.content.pm.IOtaDexopt; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.os.Environment; import android.os.RemoteException; import android.os.ResultReceiver; @@ -118,8 +118,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (mDexoptCommands != null) { throw new IllegalStateException("already called prepare()"); } - final List<PackageParser.Package> important; - final List<PackageParser.Package> others; + final List<AndroidPackage> important; + final List<AndroidPackage> others; synchronized (mPackageManagerService.mLock) { // Important: the packages we need to run with ab-ota compiler-reason. important = PackageManagerServiceUtils.getPackagesForDexopt( @@ -133,12 +133,12 @@ public class OtaDexoptService extends IOtaDexopt.Stub { mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2); } - for (PackageParser.Package p : important) { + for (AndroidPackage p : important) { mDexoptCommands.addAll(generatePackageDexopts(p, PackageManagerService.REASON_AB_OTA)); } - for (PackageParser.Package p : others) { + for (AndroidPackage p : others) { // We assume here that there are no core apps left. - if (p.coreApp) { + if (p.isCoreApp()) { throw new IllegalStateException("Found a core app that's not important"); } mDexoptCommands.addAll( @@ -150,8 +150,8 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (spaceAvailable < BULK_DELETE_THRESHOLD) { Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: " + PackageManagerServiceUtils.packagesToString(others)); - for (PackageParser.Package pkg : others) { - mPackageManagerService.deleteOatArtifactsOfPackage(pkg.packageName); + for (AndroidPackage pkg : others) { + mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName()); } } long spaceAvailableNow = getAvailableSpace(); @@ -161,15 +161,15 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (DEBUG_DEXOPT) { try { // Output some data about the packages. - PackageParser.Package lastUsed = Collections.max(important, + AndroidPackage lastUsed = Collections.max(important, (pkg1, pkg2) -> Long.compare( pkg1.getLatestForegroundPackageUseTimeInMills(), pkg2.getLatestForegroundPackageUseTimeInMills())); Log.d(TAG, "A/B OTA: lastUsed time = " + lastUsed.getLatestForegroundPackageUseTimeInMills()); Log.d(TAG, "A/B OTA: deprioritized packages:"); - for (PackageParser.Package pkg : others) { - Log.d(TAG, " " + pkg.packageName + " - " + for (AndroidPackage pkg : others) { + Log.d(TAG, " " + pkg.getPackageName() + " - " + pkg.getLatestForegroundPackageUseTimeInMills()); } } catch (Exception ignored) { @@ -262,7 +262,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { /** * Generate all dexopt commands for the given package. */ - private synchronized List<String> generatePackageDexopts(PackageParser.Package pkg, + private synchronized List<String> generatePackageDexopts(AndroidPackage pkg, int compilationReason) { // Intercept and collect dexopt requests final List<String> commands = new ArrayList<String>(); @@ -336,8 +336,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub { optimizer.performDexOpt(pkg, null /* ISAs */, null /* CompilerStats.PackageStats */, - mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName), - new DexoptOptions(pkg.packageName, compilationReason, + mPackageManagerService.getDexManager().getPackageUseInfoOrDefault( + pkg.getPackageName()), + new DexoptOptions(pkg.getPackageName(), compilationReason, DexoptOptions.DEXOPT_BOOT_COMPLETE)); return commands; @@ -359,10 +360,10 @@ public class OtaDexoptService extends IOtaDexopt.Stub { } // Look into all packages. - Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages(); + Collection<AndroidPackage> pkgs = mPackageManagerService.getPackages(); int packagePaths = 0; int pathsSuccessful = 0; - for (PackageParser.Package pkg : pkgs) { + for (AndroidPackage pkg : pkgs) { if (pkg == null) { continue; } @@ -371,27 +372,28 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (!PackageDexOptimizer.canOptimizePackage(pkg)) { continue; } - if (pkg.codePath == null) { + if (pkg.getCodePath() == null) { Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath"); continue; } // If the path is in /system, /vendor, /product or /system_ext, ignore. It will // have been ota-dexopted into /data/ota and moved into the dalvik-cache already. - if (pkg.codePath.startsWith("/system") - || pkg.codePath.startsWith("/vendor") - || pkg.codePath.startsWith("/product") - || pkg.codePath.startsWith("/system_ext")) { + if (pkg.getCodePath().startsWith("/system") + || pkg.getCodePath().startsWith("/vendor") + || pkg.getCodePath().startsWith("/product") + || pkg.getCodePath().startsWith("/system_ext")) { continue; } - final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); + final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), + pkg.getSecondaryCpuAbi()); final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); for (String dexCodeInstructionSet : dexCodeInstructionSets) { for (String path : paths) { - String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)). - getAbsolutePath(); + String oatDir = PackageDexOptimizer.getOatDir( + new File(pkg.getCodePath())).getAbsolutePath(); // TODO: Check first whether there is an artifact, to save the roundtrip time. diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java index c21d0cf54d91..d7c161cc1a86 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelper.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java @@ -17,7 +17,8 @@ package com.android.server.pm; import android.annotation.Nullable; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; @@ -25,21 +26,21 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.File; import java.util.Set; +// TODO: Move to .parsing sub-package @VisibleForTesting public interface PackageAbiHelper { /** * Derive and get the location of native libraries for the given package, * which varies depending on where and how the package was installed. */ - NativeLibraryPaths getNativeLibraryPaths( - PackageParser.Package pkg, File appLib32InstallDir); + NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, File appLib32InstallDir); /** * Calculate the abis for a bundled app. These can uniquely be determined from the contents of * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not * validate any of this information, and instead assume that the system was built sensibly. */ - Abis getBundledAppAbis(PackageParser.Package pkg); + Abis getBundledAppAbis(AndroidPackage pkg); /** * Derive the ABI of a non-system package located at {@code pkg}. This information @@ -48,7 +49,7 @@ public interface PackageAbiHelper { * If {@code extractLibs} is true, native libraries are extracted from the app if required. */ Pair<Abis, NativeLibraryPaths> derivePackageAbi( - PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs) + AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs) throws PackageManagerException; /** @@ -69,11 +70,11 @@ public interface PackageAbiHelper { */ @Nullable String getAdjustedAbiForSharedUser( - Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage); + Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage); /** * The native library paths and related properties that should be set on a - * {@link android.content.pm.PackageParser.Package}. + * {@link ParsedPackage}. */ final class NativeLibraryPaths { public final String nativeLibraryRootDir; @@ -91,11 +92,11 @@ public interface PackageAbiHelper { this.secondaryNativeLibraryDir = secondaryNativeLibraryDir; } - public void applyTo(PackageParser.Package pkg) { - pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir; - pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa; - pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir; - pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir; + public void applyTo(ParsedPackage pkg) { + pkg.setNativeLibraryRootDir(nativeLibraryRootDir) + .setNativeLibraryRootRequiresIsa(nativeLibraryRootRequiresIsa) + .setNativeLibraryDir(nativeLibraryDir) + .setSecondaryNativeLibraryDir(secondaryNativeLibraryDir); } } @@ -112,13 +113,13 @@ public interface PackageAbiHelper { this.secondary = secondary; } - Abis(PackageParser.Package pkg) { - this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi); + Abis(AndroidPackage pkg) { + this(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()); } - public void applyTo(PackageParser.Package pkg) { - pkg.applicationInfo.primaryCpuAbi = primary; - pkg.applicationInfo.secondaryCpuAbi = secondary; + public void applyTo(ParsedPackage pkg) { + pkg.setPrimaryCpuAbi(primary) + .setSecondaryCpuAbi(secondary); } public void applyTo(PackageSetting pkgSetting) { // pkgSetting might be null during rescan following uninstall of updates diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java index 1d3d24c27041..6de5203f0f73 100644 --- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java +++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java @@ -28,7 +28,7 @@ import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.Environment; import android.os.FileUtils; @@ -122,10 +122,10 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { @Override public NativeLibraryPaths getNativeLibraryPaths( - PackageParser.Package pkg, File appLib32InstallDir) { - return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.codePath, - pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(), - pkg.applicationInfo.isUpdatedSystemApp()); + AndroidPackage pkg, File appLib32InstallDir) { + return getNativeLibraryPaths(new Abis(pkg), appLib32InstallDir, pkg.getCodePath(), + pkg.getBaseCodePath(), pkg.isSystemApp(), + pkg.isUpdatedSystemApp()); } private static NativeLibraryPaths getNativeLibraryPaths(final Abis abis, @@ -192,12 +192,12 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { } @Override - public Abis getBundledAppAbis(PackageParser.Package pkg) { - final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath()); + public Abis getBundledAppAbis(AndroidPackage pkg) { + final String apkName = deriveCodePathName(pkg.getCodePath()); // If "/system/lib64/apkname" exists, assume that is the per-package // native library directory to use; otherwise use "/system/lib/apkname". - final String apkRoot = calculateBundledApkRoot(pkg.applicationInfo.sourceDir); + final String apkRoot = calculateBundledApkRoot(pkg.getBaseCodePath()); final Abis abis = getBundledAppAbi(pkg, apkRoot, apkName); return abis; } @@ -210,8 +210,8 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { * {@code /oem} under which system libraries are installed. * @param apkName the name of the installed package. */ - private Abis getBundledAppAbi(PackageParser.Package pkg, String apkRoot, String apkName) { - final File codeFile = new File(pkg.codePath); + private Abis getBundledAppAbi(AndroidPackage pkg, String apkRoot, String apkName) { + final File codeFile = new File(pkg.getCodePath()); final boolean has64BitLibs; final boolean has32BitLibs; @@ -263,7 +263,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { // ABI that's higher on the list, i.e, a device that's configured to prefer // 64 bit apps will see a 64 bit primary ABI, - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) == 0) { Slog.e(PackageManagerService.TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch."); } @@ -284,14 +284,14 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { @Override public Pair<Abis, NativeLibraryPaths> derivePackageAbi( - PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs) + AndroidPackage pkg, String cpuAbiOverride, boolean extractLibs) throws PackageManagerException { // Give ourselves some initial paths; we'll come back for another // pass once we've determined ABI below. final NativeLibraryPaths initialLibraryPaths = getNativeLibraryPaths(new Abis(pkg), - PackageManagerService.sAppLib32InstallDir, pkg.codePath, - pkg.applicationInfo.sourceDir, pkg.applicationInfo.isSystemApp(), - pkg.applicationInfo.isUpdatedSystemApp()); + PackageManagerService.sAppLib32InstallDir, pkg.getCodePath(), + pkg.getBaseCodePath(), pkg.isSystemApp(), + pkg.isUpdatedSystemApp()); // We shouldn't attempt to extract libs from system app when it was not updated. if (PackageManagerService.isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) { @@ -318,12 +318,13 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { // Null out the abis so that they can be recalculated. primaryCpuAbi = null; secondaryCpuAbi = null; - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_MULTIARCH) != 0) { // Warn if we've set an abiOverride for multi-lib packages.. // By definition, we need to copy both 32 and 64 bit libraries for // such packages. - if (pkg.cpuAbiOverride != null - && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(pkg.cpuAbiOverride)) { + if (pkg.getCpuAbiOverride() != null + && !NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals( + pkg.getCpuAbiOverride())) { Slog.w(PackageManagerService.TAG, "Ignoring abiOverride for multi arch application."); } @@ -382,7 +383,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { if (abi32 >= 0) { final String abi = Build.SUPPORTED_32_BIT_ABIS[abi32]; if (abi64 >= 0) { - if (pkg.use32bitAbi) { + if (pkg.isUse32BitAbi()) { secondaryCpuAbi = primaryCpuAbi; primaryCpuAbi = abi; } else { @@ -449,9 +450,9 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { final Abis abis = new Abis(primaryCpuAbi, secondaryCpuAbi); return new Pair<>(abis, getNativeLibraryPaths(abis, PackageManagerService.sAppLib32InstallDir, - pkg.codePath, pkg.applicationInfo.sourceDir, - pkg.applicationInfo.isSystemApp(), - pkg.applicationInfo.isUpdatedSystemApp())); + pkg.getCodePath(), pkg.getBaseCodePath(), + pkg.isSystemApp(), + pkg.isUpdatedSystemApp())); } /** @@ -470,11 +471,11 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { @Override @Nullable public String getAdjustedAbiForSharedUser( - Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage) { + Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) { String requiredInstructionSet = null; - if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) { + if (scannedPackage != null && scannedPackage.getPrimaryCpuAbi() != null) { requiredInstructionSet = VMRuntime.getInstructionSet( - scannedPackage.applicationInfo.primaryCpuAbi); + scannedPackage.getPrimaryCpuAbi()); } PackageSetting requirer = null; @@ -483,7 +484,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { // when scannedPackage is an update of an existing package. Without this check, // we will never be able to change the ABI of any package belonging to a shared // user, even if it's compatible with other packages. - if (scannedPackage != null && scannedPackage.packageName.equals(ps.name)) { + if (scannedPackage != null && scannedPackage.getPackageName().equals(ps.name)) { continue; } if (ps.primaryCpuAbiString == null) { @@ -521,7 +522,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper { } else { // requirer == null implies that we're updating all ABIs in the set to // match scannedPackage. - adjustedAbi = scannedPackage.applicationInfo.primaryCpuAbi; + adjustedAbi = scannedPackage.getPrimaryCpuAbi(); } return adjustedAbi; } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 4f7c8c8da4a9..2b422211077b 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -41,10 +41,10 @@ import static dalvik.system.DexFile.isProfileGuidedCompilerFilter; import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageParser; import android.content.pm.SharedLibraryInfo; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; +import android.content.pm.parsing.AndroidPackage; import android.os.FileUtils; import android.os.PowerManager; import android.os.SystemClock; @@ -53,6 +53,7 @@ import android.os.UserHandle; import android.os.WorkSource; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; @@ -109,9 +110,9 @@ public class PackageDexOptimizer { this.mSystemReady = from.mSystemReady; } - static boolean canOptimizePackage(PackageParser.Package pkg) { + static boolean canOptimizePackage(AndroidPackage pkg) { // We do not dexopt a package with no code. - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) == 0) { return false; } @@ -125,18 +126,18 @@ public class PackageDexOptimizer { * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are * synchronized on {@link #mInstallLock}. */ - int performDexOpt(PackageParser.Package pkg, + int performDexOpt(AndroidPackage pkg, String[] instructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { - if (pkg.applicationInfo.uid == -1) { - throw new IllegalArgumentException("Dexopt for " + pkg.packageName + if (pkg.getUid() == -1) { + throw new IllegalArgumentException("Dexopt for " + pkg.getPackageName() + " has invalid uid."); } if (!canOptimizePackage(pkg)) { return DEX_OPT_SKIPPED; } synchronized (mInstallLock) { - final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid); + final long acquireTime = acquireWakeLockLI(pkg.getUid()); try { return performDexOptLI(pkg, instructionSets, packageStats, packageUseInfo, options); @@ -151,19 +152,20 @@ public class PackageDexOptimizer { * It assumes the install lock is held. */ @GuardedBy("mInstallLock") - private int performDexOptLI(PackageParser.Package pkg, + private int performDexOptLI(AndroidPackage pkg, String[] targetInstructionSets, CompilerStats.PackageStats packageStats, PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) { - final List<SharedLibraryInfo> sharedLibraries = pkg.usesLibraryInfos; + final List<SharedLibraryInfo> sharedLibraries = pkg.getUsesLibraryInfos(); final String[] instructionSets = targetInstructionSets != null ? - targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo); + targetInstructionSets : getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), + pkg.getSecondaryCpuAbi()); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); final List<String> paths = pkg.getAllCodePaths(); - int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + int sharedGid = UserHandle.getSharedAppGid(pkg.getUid()); if (sharedGid == -1) { - Slog.wtf(TAG, "Well this is awkward; package " + pkg.applicationInfo.name + " had UID " - + pkg.applicationInfo.uid, new Throwable()); + Slog.wtf(TAG, "Well this is awkward; package " + pkg.getAppInfoName() + " had UID " + + pkg.getUid(), new Throwable()); sharedGid = android.os.Process.NOBODY_UID; } @@ -171,21 +173,21 @@ public class PackageDexOptimizer { // For each code path in the package, this array contains the class loader context that // needs to be passed to dexopt in order to ensure correct optimizations. boolean[] pathsWithCode = new boolean[paths.size()]; - pathsWithCode[0] = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0; + pathsWithCode[0] = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0; for (int i = 1; i < paths.size(); i++) { - pathsWithCode[i] = (pkg.splitFlags[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0; + pathsWithCode[i] = (pkg.getSplitFlags()[i - 1] & ApplicationInfo.FLAG_HAS_CODE) != 0; } String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts( - pkg.applicationInfo, sharedLibraries, pathsWithCode); + pkg, sharedLibraries, pathsWithCode); // Sanity check that we do not call dexopt with inconsistent data. if (paths.size() != classLoaderContexts.length) { - String[] splitCodePaths = pkg.applicationInfo.getSplitCodePaths(); + String[] splitCodePaths = pkg.getSplitCodePaths(); throw new IllegalStateException("Inconsistent information " + "between PackageParser.Package and its ApplicationInfo. " + "pkg.getAllCodePaths=" + paths - + " pkg.applicationInfo.getBaseCodePath=" + pkg.applicationInfo.getBaseCodePath() - + " pkg.applicationInfo.getSplitCodePaths=" + + " pkg.getBaseCodePath=" + pkg.getBaseCodePath() + + " pkg.getSplitCodePaths=" + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths))); } @@ -211,7 +213,8 @@ public class PackageDexOptimizer { } } - String profileName = ArtManager.getProfileName(i == 0 ? null : pkg.splitNames[i - 1]); + String profileName = ArtManager.getProfileName( + i == 0 ? null : pkg.getSplitNames()[i - 1]); String dexMetadataPath = null; if (options.isDexoptInstallWithDexMetadata()) { @@ -222,7 +225,7 @@ public class PackageDexOptimizer { final boolean isUsedByOtherApps = options.isDexoptAsSharedLibrary() || packageUseInfo.isUsedByOtherApps(path); - final String compilerFilter = getRealCompilerFilter(pkg.applicationInfo, + final String compilerFilter = getRealCompilerFilter(pkg, options.getCompilerFilter(), isUsedByOtherApps); final boolean profileUpdated = options.isCheckForProfileUpdates() && isProfileUpdated(pkg, sharedGid, profileName, compilerFilter); @@ -257,7 +260,7 @@ public class PackageDexOptimizer { * DEX_OPT_SKIPPED if the path does not need to be deopt-ed. */ @GuardedBy("mInstallLock") - private int dexOptPath(PackageParser.Package pkg, String path, String isa, + private int dexOptPath(AndroidPackage pkg, String path, String isa, String compilerFilter, boolean profileUpdated, String classLoaderContext, int dexoptFlags, int uid, CompilerStats.PackageStats packageStats, boolean downgrade, String profileName, String dexMetadataPath, int compilationReason) { @@ -270,7 +273,7 @@ public class PackageDexOptimizer { String oatDir = getPackageOatDirIfSupported(pkg); Log.i(TAG, "Running dexopt (dexoptNeeded=" + dexoptNeeded + ") on: " + path - + " pkg=" + pkg.applicationInfo.packageName + " isa=" + isa + + " pkg=" + pkg.getAppInfoPackageName() + " isa=" + isa + " dexoptFlags=" + printDexoptFlags(dexoptFlags) + " targetFilter=" + compilerFilter + " oatDir=" + oatDir + " classLoaderContext=" + classLoaderContext); @@ -281,9 +284,9 @@ public class PackageDexOptimizer { // TODO: Consider adding 2 different APIs for primary and secondary dexopt. // installd only uses downgrade flag for secondary dex files and ignores it for // primary dex files. - mInstaller.dexopt(path, uid, pkg.packageName, isa, dexoptNeeded, oatDir, dexoptFlags, - compilerFilter, pkg.volumeUuid, classLoaderContext, pkg.applicationInfo.seInfo, - false /* downgrade*/, pkg.applicationInfo.targetSdkVersion, + mInstaller.dexopt(path, uid, pkg.getPackageName(), isa, dexoptNeeded, oatDir, + dexoptFlags, compilerFilter, pkg.getVolumeUuid(), classLoaderContext, + pkg.getSeInfo(), false /* downgrade*/, pkg.getTargetSdkVersion(), profileName, dexMetadataPath, getAugmentedReasonName(compilationReason, dexMetadataPath != null)); @@ -446,9 +449,10 @@ public class PackageDexOptimizer { /** * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}. */ - void dumpDexoptState(IndentingPrintWriter pw, PackageParser.Package pkg, + void dumpDexoptState(IndentingPrintWriter pw, AndroidPackage pkg, PackageDexUsage.PackageUseInfo useInfo) { - final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo); + final String[] instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), + pkg.getSecondaryCpuAbi()); final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); @@ -504,7 +508,7 @@ public class PackageDexOptimizer { // When an app or priv app is configured to run out of box, only verify it. if (info.isEmbeddedDexUsed() || (info.isPrivilegedApp() - && DexManager.isPackageSelectedToRunOob(info.packageName))) { + && DexManager.isPackageSelectedToRunOob(info.packageName))) { return "verify"; } @@ -535,12 +539,43 @@ public class PackageDexOptimizer { } /** - * Computes the dex flags that needs to be pass to installd for the given package and compiler - * filter. + * Returns the compiler filter that should be used to optimize the package code. + * The target filter will be updated if the package code is used by other apps + * or if it has the safe mode flag set. */ - private int getDexFlags(PackageParser.Package pkg, String compilerFilter, - DexoptOptions options) { - return getDexFlags(pkg.applicationInfo, compilerFilter, options); + private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter, + boolean isUsedByOtherApps) { + // When an app or priv app is configured to run out of box, only verify it. + if (pkg.isEmbeddedDexUsed() + || (pkg.isPrivileged() + && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) { + return "verify"; + } + + // We force vmSafeMode on debuggable apps as well: + // - the runtime ignores their compiled code + // - they generally have lots of methods that could make the compiler used run + // out of memory (b/130828957) + // Note that forcing the compiler filter here applies to all compilations (even if they + // are done via adb shell commands). That's ok because right now the runtime will ignore + // the compiled code anyway. The alternative would have been to update either + // PackageDexOptimizer#canOptimizePackage or PackageManagerService#getOptimizablePackages + // but that would have the downside of possibly producing a big odex files which would + // be ignored anyway. + boolean vmSafeModeOrDebuggable = ((pkg.getFlags() & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0) + || ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0); + + if (vmSafeModeOrDebuggable) { + return getSafeModeCompilerFilter(targetCompilerFilter); + } + + if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) { + // If the dex files is used by other apps, apply the shared filter. + return PackageManagerServiceCompilerMapping.getCompilerFilterForReason( + PackageManagerService.REASON_SHARED); + } + + return targetCompilerFilter; } private boolean isAppImageEnabled() { @@ -548,7 +583,24 @@ public class PackageDexOptimizer { } private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) { - int flags = info.flags; + return getDexFlags(info.flags, info.getHiddenApiEnforcementPolicy(), + info.splitDependencies, info.requestsIsolatedSplitLoading(), compilerFilter, + options); + } + private int getDexFlags(AndroidPackage pkg, String compilerFilter, + DexoptOptions options) { + return getDexFlags(pkg.getFlags(), pkg.getHiddenApiEnforcementPolicy(), + pkg.getSplitDependencies(), pkg.requestsIsolatedSplitLoading(), compilerFilter, + options); + } + + /** + * Computes the dex flags that needs to be pass to installd for the given package and compiler + * filter. + */ + private int getDexFlags(int flags, int hiddenApiEnforcementPolicy, + SparseArray<int[]> splitDependencies, boolean requestsIsolatedSplitLoading, + String compilerFilter, DexoptOptions options) { boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; // Profile guide compiled oat files should not be public unles they are based // on profiles from dex metadata archives. @@ -560,7 +612,9 @@ public class PackageDexOptimizer { // Some apps are executed with restrictions on hidden API usage. If this app is one // of them, pass a flag to dexopt to enable the same restrictions during compilation. // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist - int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_DISABLED + // TODO(b/135203078): This flag is no longer set as part of AndroidPackage + // and may not be preserved + int hiddenApiFlag = hiddenApiEnforcementPolicy == HIDDEN_API_ENFORCEMENT_DISABLED ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS; // Avoid generating CompactDex for modes that are latency critical. @@ -578,8 +632,8 @@ public class PackageDexOptimizer { // declare inter-split dependencies, then all the splits will be loaded in the base // apk class loader (in the order of their definition, otherwise disable app images // because they are unsupported for multiple class loaders. b/7269679 - boolean generateAppImage = isProfileGuidedFilter && (info.splitDependencies == null || - !info.requestsIsolatedSplitLoading()) && isAppImageEnabled(); + boolean generateAppImage = isProfileGuidedFilter && (splitDependencies == null || + !requestsIsolatedSplitLoading) && isAppImageEnabled(); int dexFlags = (isPublic ? DEXOPT_PUBLIC : 0) | (debuggable ? DEXOPT_DEBUGGABLE : 0) @@ -617,7 +671,7 @@ public class PackageDexOptimizer { * current profile and the reference profile will be merged and subsequent calls * may return a different result. */ - private boolean isProfileUpdated(PackageParser.Package pkg, int uid, String profileName, + private boolean isProfileUpdated(AndroidPackage pkg, int uid, String profileName, String compilerFilter) { // Check if we are allowed to merge and if the compiler filter is profile guided. if (!isProfileGuidedCompilerFilter(compilerFilter)) { @@ -625,7 +679,7 @@ public class PackageDexOptimizer { } // Merge profiles. It returns whether or not there was an updated in the profile info. try { - return mInstaller.mergeProfiles(uid, pkg.packageName, profileName); + return mInstaller.mergeProfiles(uid, pkg.getPackageName(), profileName); } catch (InstallerException e) { Slog.w(TAG, "Failed to merge profiles", e); } @@ -645,11 +699,11 @@ public class PackageDexOptimizer { * not needed or unsupported for the package. */ @Nullable - private String getPackageOatDirIfSupported(PackageParser.Package pkg) { + private String getPackageOatDirIfSupported(AndroidPackage pkg) { if (!pkg.canHaveOatDir()) { return null; } - File codePath = new File(pkg.codePath); + File codePath = new File(pkg.getCodePath()); if (!codePath.isDirectory()) { return null; } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index b72029046067..a34ca914f548 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -66,6 +66,7 @@ import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.dex.DexMetadataHelper; +import android.content.pm.parsing.ApkLiteParseUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Binder; @@ -1573,7 +1574,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { for (File addedFile : addedFiles) { final ApkLite apk; try { - apk = PackageParser.parseApkLite( + apk = ApkLiteParseUtils.parseApkLite( addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES); } catch (PackageParserException e) { throw PackageManagerException.from(e); @@ -1672,7 +1673,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { ApplicationInfo appInfo = pkgInfo.applicationInfo; try { existing = PackageParser.parsePackageLite(new File(appInfo.getCodePath()), 0); - existingBase = PackageParser.parseApkLite(new File(appInfo.getBaseCodePath()), + existingBase = ApkLiteParseUtils.parseApkLite(new File(appInfo.getBaseCodePath()), PackageParser.PARSE_COLLECT_CERTIFICATES); } catch (PackageParserException e) { throw PackageManagerException.from(e); diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java index 031b5ce3d5b9..10685b06716f 100644 --- a/services/core/java/com/android/server/pm/PackageKeySetData.java +++ b/services/core/java/com/android/server/pm/PackageKeySetData.java @@ -20,6 +20,8 @@ import android.util.ArrayMap; import com.android.internal.util.ArrayUtils; +import java.util.Map; + public class PackageKeySetData { static final long KEYSET_UNASSIGNED = -1; @@ -90,16 +92,13 @@ public class PackageKeySetData { /* * Replace defined keysets with new ones. */ - protected void setAliases(ArrayMap<String, Long> newAliases) { + protected void setAliases(Map<String, Long> newAliases) { /* remove old aliases */ removeAllDefinedKeySets(); /* add new ones */ - final int newAliasSize = newAliases.size(); - for (int i = 0; i < newAliasSize; i++) { - mKeySetAliases.put(newAliases.keyAt(i), newAliases.valueAt(i));; - } + mKeySetAliases.putAll(newAliases); } protected void addDefinedKeySet(long ks, String alias) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index d07e2d232ea6..f706dc3d3219 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -34,7 +34,6 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.content.pm.PackageManager.DELETE_KEEP_DATA; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED; import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT; @@ -158,7 +157,6 @@ import android.content.pm.InstrumentationInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.KeySet; import android.content.pm.ModuleInfo; -import android.content.pm.PackageBackwardCompatibility; import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageInstaller; @@ -169,7 +167,6 @@ import android.content.pm.PackageManager.ModuleInfoFlags; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.ActivityIntentInfo; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.ParseFlags; @@ -194,6 +191,19 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.IArtManager; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ApkParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.library.PackageBackwardCompatibility; import android.content.res.Resources; import android.content.rollback.IRollbackManager; import android.database.ContentObserver; @@ -460,20 +470,19 @@ public class PackageManagerService extends IPackageManager.Stub static final int SCAN_REQUIRE_KNOWN = 1 << 7; static final int SCAN_MOVE = 1 << 8; static final int SCAN_INITIAL = 1 << 9; - static final int SCAN_CHECK_ONLY = 1 << 10; - static final int SCAN_DONT_KILL_APP = 1 << 11; - static final int SCAN_IGNORE_FROZEN = 1 << 12; - static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 13; - static final int SCAN_AS_INSTANT_APP = 1 << 14; - static final int SCAN_AS_FULL_APP = 1 << 15; - static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 16; - static final int SCAN_AS_SYSTEM = 1 << 17; - static final int SCAN_AS_PRIVILEGED = 1 << 18; - static final int SCAN_AS_OEM = 1 << 19; - static final int SCAN_AS_VENDOR = 1 << 20; - static final int SCAN_AS_PRODUCT = 1 << 21; - static final int SCAN_AS_SYSTEM_EXT = 1 << 22; - static final int SCAN_AS_ODM = 1 << 23; + static final int SCAN_DONT_KILL_APP = 1 << 10; + static final int SCAN_IGNORE_FROZEN = 1 << 11; + static final int SCAN_FIRST_BOOT_OR_UPGRADE = 1 << 12; + static final int SCAN_AS_INSTANT_APP = 1 << 13; + static final int SCAN_AS_FULL_APP = 1 << 14; + static final int SCAN_AS_VIRTUAL_PRELOAD = 1 << 15; + static final int SCAN_AS_SYSTEM = 1 << 16; + static final int SCAN_AS_PRIVILEGED = 1 << 17; + static final int SCAN_AS_OEM = 1 << 18; + static final int SCAN_AS_VENDOR = 1 << 19; + static final int SCAN_AS_PRODUCT = 1 << 20; + static final int SCAN_AS_SYSTEM_EXT = 1 << 21; + static final int SCAN_AS_ODM = 1 << 22; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -484,7 +493,6 @@ public class PackageManagerService extends IPackageManager.Stub SCAN_REQUIRE_KNOWN, SCAN_MOVE, SCAN_INITIAL, - SCAN_CHECK_ONLY, SCAN_DONT_KILL_APP, SCAN_IGNORE_FROZEN, SCAN_FIRST_BOOT_OR_UPGRADE, @@ -603,11 +611,19 @@ public class PackageManagerService extends IPackageManager.Stub public static final int REASON_LAST = REASON_SHARED; /** - * Whether the package parser cache is enabled. + * The initial enabled state of the cache before other checks are done. */ private static final boolean DEFAULT_PACKAGE_PARSER_CACHE_ENABLED = true; /** + * Whether to skip all other checks and force the cache to be enabled. + * + * Setting this to true will cause the cache to be named "debug" to avoid eviction from + * build fingerprint changes. + */ + private static final boolean FORCE_PACKAGE_PARSED_CACHE_ENABLED = false; + + /** * Permissions required in order to receive instant application lifecycle broadcasts. */ private static final String[] INSTANT_APP_BROADCAST_PERMISSION = @@ -664,7 +680,7 @@ public class PackageManagerService extends IPackageManager.Stub // Keys are String (package name), values are Package. @GuardedBy("mLock") - final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<>(); + final ArrayMap<String, AndroidPackage> mPackages = new ArrayMap<>(); // Keys are isolated uids and values are the uid of the application // that created the isolated proccess. @@ -977,17 +993,17 @@ public class PackageManagerService extends IPackageManager.Stub return PackageManagerService.this.hasSystemFeature(feature, 0); } - final List<PackageParser.Package> getStaticOverlayPackages( - Collection<PackageParser.Package> allPackages, String targetPackageName) { + final List<AndroidPackage> getStaticOverlayPackages( + Collection<AndroidPackage> allPackages, String targetPackageName) { if ("android".equals(targetPackageName)) { // Static RROs targeting to "android", ie framework-res.apk, are already applied by // native AssetManager. return null; } - List<PackageParser.Package> overlayPackages = null; - for (PackageParser.Package p : allPackages) { - if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) { + List<AndroidPackage> overlayPackages = null; + for (AndroidPackage p : allPackages) { + if (targetPackageName.equals(p.getOverlayTarget()) && p.isOverlayIsStatic()) { if (overlayPackages == null) { overlayPackages = new ArrayList<>(); } @@ -995,25 +1011,25 @@ public class PackageManagerService extends IPackageManager.Stub } } if (overlayPackages != null) { - Comparator<PackageParser.Package> cmp = - Comparator.comparingInt(p -> p.mOverlayPriority); + Comparator<AndroidPackage> cmp = + Comparator.comparingInt(p -> p.getOverlayPriority()); overlayPackages.sort(cmp); } return overlayPackages; } - final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages, + final String[] getStaticOverlayPaths(List<AndroidPackage> overlayPackages, String targetPath) { if (overlayPackages == null || overlayPackages.isEmpty()) { return null; } List<String> overlayPathList = null; - for (PackageParser.Package overlayPackage : overlayPackages) { + for (AndroidPackage overlayPackage : overlayPackages) { if (targetPath == null) { if (overlayPathList == null) { overlayPathList = new ArrayList<>(); } - overlayPathList.add(overlayPackage.baseCodePath); + overlayPathList.add(overlayPackage.getBaseCodePath()); continue; } @@ -1023,23 +1039,23 @@ public class PackageManagerService extends IPackageManager.Stub // // OverlayManagerService will update each of them with a correct gid from its // target package app id. - mInstaller.idmap(targetPath, overlayPackage.baseCodePath, + mInstaller.idmap(targetPath, overlayPackage.getBaseCodePath(), UserHandle.getSharedAppGid( UserHandle.getUserGid(UserHandle.USER_SYSTEM))); if (overlayPathList == null) { overlayPathList = new ArrayList<>(); } - overlayPathList.add(overlayPackage.baseCodePath); + overlayPathList.add(overlayPackage.getBaseCodePath()); } catch (InstallerException e) { Slog.e(TAG, "Failed to generate idmap for " + targetPath + " and " + - overlayPackage.baseCodePath); + overlayPackage.getBaseCodePath()); } } return overlayPathList == null ? null : overlayPathList.toArray(new String[0]); } String[] getStaticOverlayPaths(String targetPackageName, String targetPath) { - List<PackageParser.Package> overlayPackages; + List<AndroidPackage> overlayPackages; synchronized (mInstallLock) { synchronized (mLock) { overlayPackages = getStaticOverlayPackages( @@ -1062,12 +1078,12 @@ public class PackageManagerService extends IPackageManager.Stub } class ParallelPackageParserCallback extends PackageParserCallback { - List<PackageParser.Package> mOverlayPackages = null; + List<AndroidPackage> mOverlayPackages = null; void findStaticOverlayPackages() { synchronized (mLock) { - for (PackageParser.Package p : mPackages.values()) { - if (p.mOverlayIsStatic) { + for (AndroidPackage p : mPackages.values()) { + if (p.isOverlayIsStatic()) { if (mOverlayPackages == null) { mOverlayPackages = new ArrayList<>(); } @@ -1101,7 +1117,7 @@ public class PackageManagerService extends IPackageManager.Stub new ArrayMap<>(); // Mapping from instrumentation class names to info about them. - final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation = + final ArrayMap<ComponentName, ParsedInstrumentation> mInstrumentation = new ArrayMap<>(); // Packages whose data we have transfered into another package, thus @@ -1150,13 +1166,13 @@ public class PackageManagerService extends IPackageManager.Stub final ActivityInfo mResolveActivity = new ActivityInfo(); final ResolveInfo mResolveInfo = new ResolveInfo(); ComponentName mResolveComponentName; - PackageParser.Package mPlatformPackage; + AndroidPackage mPlatformPackage; ComponentName mCustomResolverComponentName; boolean mResolverReplaced = false; private final @Nullable ComponentName mIntentFilterVerifierComponent; - private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier; + private final @Nullable IntentFilterVerifier<ParsedActivityIntentInfo> mIntentFilterVerifier; private int mIntentFilterVerificationToken = 0; @@ -1189,14 +1205,19 @@ public class PackageManagerService extends IPackageManager.Stub private Future<?> mPrepareAppDataFuture; private static class IFVerificationParams { - PackageParser.Package pkg; + String packageName; + boolean hasDomainUrls; + List<ParsedActivity> activities; boolean replacing; int userId; int verifierUid; - public IFVerificationParams(PackageParser.Package _pkg, boolean _replacing, + public IFVerificationParams(String packageName, boolean hasDomainUrls, + List<ParsedActivity> activities, boolean _replacing, int _userId, int _verifierUid) { - pkg = _pkg; + this.packageName = packageName; + this.hasDomainUrls = hasDomainUrls; + this.activities = activities; replacing = _replacing; userId = _userId; verifierUid = _verifierUid; @@ -1210,7 +1231,7 @@ public class PackageManagerService extends IPackageManager.Stub void receiveVerificationResponse(int verificationId); } - private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> { + private class IntentVerifierProxy implements IntentFilterVerifier<ParsedActivityIntentInfo> { private Context mContext; private ComponentName mIntentFilterVerifierComponent; private ArrayList<Integer> mCurrentIntentFilterVerifications = new ArrayList<>(); @@ -1235,11 +1256,11 @@ public class PackageManagerService extends IPackageManager.Stub String packageName = ivs.getPackageName(); - ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters(); + ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters(); final int filterCount = filters.size(); ArraySet<String> domainsSet = new ArraySet<>(); for (int m=0; m<filterCount; m++) { - PackageParser.ActivityIntentInfo filter = filters.get(m); + ParsedActivityIntentInfo filter = filters.get(m); domainsSet.addAll(filter.getHostsList()); } synchronized (mLock) { @@ -1291,14 +1312,14 @@ public class PackageManagerService extends IPackageManager.Stub final boolean verified = ivs.isVerified(); - ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters(); + ArrayList<ParsedActivityIntentInfo> filters = ivs.getFilters(); final int count = filters.size(); if (DEBUG_DOMAIN_VERIFICATION) { Slog.i(TAG, "Received verification response " + verificationId + " for " + count + " filters, verified=" + verified); } for (int n=0; n<count; n++) { - PackageParser.ActivityIntentInfo filter = filters.get(n); + ParsedActivityIntentInfo filter = filters.get(n); filter.setVerified(verified); if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "IntentFilter " + filter.toString() @@ -1411,7 +1432,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean addOneIntentFilterVerification(int verifierUid, int userId, int verificationId, - ActivityIntentInfo filter, String packageName) { + ParsedActivityIntentInfo filter, String packageName) { if (!hasValidDomains(filter)) { return false; } @@ -1440,7 +1461,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static boolean hasValidDomains(ActivityIntentInfo filter) { + private static boolean hasValidDomains(ParsedActivityIntentInfo filter) { return filter.hasCategory(Intent.CATEGORY_BROWSABLE) && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)); @@ -1705,7 +1726,7 @@ public class PackageManagerService extends IPackageManager.Stub final List<String> whitelistedRestrictedPermissions = ((args.installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0 && parentRes.pkg != null) - ? parentRes.pkg.requestedPermissions + ? parentRes.pkg.getRequestedPermissions() : args.whitelistedRestrictedPermissions; // Handle the parent package @@ -1851,8 +1872,8 @@ public class PackageManagerService extends IPackageManager.Stub } case START_INTENT_FILTER_VERIFICATIONS: { IFVerificationParams params = (IFVerificationParams) msg.obj; - verifyIntentFiltersIfNeeded(params.userId, params.verifierUid, - params.replacing, params.pkg); + verifyIntentFiltersIfNeeded(params.userId, params.verifierUid, params.replacing, + params.packageName, params.hasDomainUrls, params.activities); break; } case INTENT_FILTER_VERIFIED: { @@ -2002,20 +2023,11 @@ public class PackageManagerService extends IPackageManager.Stub ? res.removedInfo.installerPackageName : null; - // If this is the first time we have child packages for a disabled privileged - // app that had no children, we grant requested runtime permissions to the new - // children if the parent on the system image had them already granted. - if (res.pkg.parentPackage != null) { - final int callingUid = Binder.getCallingUid(); - mPermissionManager.grantRuntimePermissionsGrantedToDisabledPackage( - res.pkg, callingUid); - } - synchronized (mLock) { mInstantAppRegistry.onPackageInstalledLPw(res.pkg, res.newUsers); } - final String packageName = res.pkg.applicationInfo.packageName; + final String packageName = res.pkg.getAppInfoPackageName(); // Determine the set of users who are adding this package for // the first time vs. those who are seeing an update. @@ -2024,7 +2036,7 @@ public class PackageManagerService extends IPackageManager.Stub int[] updateUserIds = EMPTY_INT_ARRAY; int[] instantUserIds = EMPTY_INT_ARRAY; final boolean allNewUsers = res.origUsers == null || res.origUsers.length == 0; - final PackageSetting ps = (PackageSetting) res.pkg.mExtras; + final PackageSetting ps = getPackageSetting(res.pkg.getPackageName()); for (int newUser : res.newUsers) { final boolean isInstantApp = ps.getInstantApp(newUser); if (allNewUsers) { @@ -2058,13 +2070,14 @@ public class PackageManagerService extends IPackageManager.Stub } // Send installed broadcasts if the package is not a static shared lib. - if (res.pkg.staticSharedLibName == null) { - mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(res.pkg.baseCodePath); + if (res.pkg.getStaticSharedLibName() == null) { + mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash( + res.pkg.getBaseCodePath()); // Send added for users that see the package for the first time // sendPackageAddedForNewUsers also deals with system apps int appId = UserHandle.getAppId(res.uid); - boolean isSystem = res.pkg.applicationInfo.isSystemApp(); + boolean isSystem = res.pkg.isSystemApp(); sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds); @@ -2142,30 +2155,30 @@ public class PackageManagerService extends IPackageManager.Stub final StorageManager storage = mInjector.getStorageManager(); VolumeInfo volume = storage.findVolumeByUuid( - res.pkg.applicationInfo.storageUuid.toString()); + res.pkg.getStorageUuid().toString()); int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(res.pkg)); // If the package was installed externally, log it. if (packageExternalStorageType != StorageEnums.UNKNOWN) { StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED, - packageExternalStorageType, res.pkg.packageName); + packageExternalStorageType, res.pkg.getPackageName()); } } if (DEBUG_INSTALL) { Slog.i(TAG, "upgrading pkg " + res.pkg + " is external"); } - final int[] uidArray = new int[]{res.pkg.applicationInfo.uid}; + final int[] uidArray = new int[]{res.pkg.getUid()}; ArrayList<String> pkgList = new ArrayList<>(1); pkgList.add(packageName); sendResourcesChangedBroadcast(true, true, pkgList, uidArray, null); } } else if (!ArrayUtils.isEmpty(res.libraryConsumers)) { // if static shared lib for (int i = 0; i < res.libraryConsumers.size(); i++) { - PackageParser.Package pkg = res.libraryConsumers.get(i); + AndroidPackage pkg = res.libraryConsumers.get(i); // send broadcast that all consumers of the static shared library have changed - sendPackageChangedBroadcast(pkg.packageName, false /*killFlag*/, - new ArrayList<>(Collections.singletonList(pkg.packageName)), - pkg.applicationInfo.uid); + sendPackageChangedBroadcast(pkg.getPackageName(), false /*killFlag*/, + new ArrayList<>(Collections.singletonList(pkg.getPackageName())), + pkg.getUid()); } } @@ -2295,7 +2308,7 @@ public class PackageManagerService extends IPackageManager.Stub private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info, IPackageInstallObserver2 observer) { - String packageName = info.pkg.packageName; + String packageName = info.pkg.getPackageName(); mNoKillInstallObservers.put(packageName, Pair.create(info, observer)); Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName); mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS); @@ -2833,11 +2846,11 @@ public class PackageManagerService extends IPackageManager.Stub final List<String> stubSystemApps = new ArrayList<>(); if (!mOnlyCore) { // do this first before mucking with mPackages for the "expecting better" case - final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator(); + final Iterator<AndroidPackage> pkgIterator = mPackages.values().iterator(); while (pkgIterator.hasNext()) { - final PackageParser.Package pkg = pkgIterator.next(); - if (pkg.isStub) { - stubSystemApps.add(pkg.packageName); + final AndroidPackage pkg = pkgIterator.next(); + if (pkg.isStub()) { + stubSystemApps.add(pkg.getPackageName()); } } @@ -2856,7 +2869,7 @@ public class PackageManagerService extends IPackageManager.Stub /* * If the package is scanned, it's not erased. */ - final PackageParser.Package scannedPkg = mPackages.get(ps.name); + final AndroidPackage scannedPkg = mPackages.get(ps.name); if (scannedPkg != null) { /* * If the system app is both scanned and in the @@ -2933,7 +2946,7 @@ public class PackageManagerService extends IPackageManager.Stub // app completely. Otherwise, revoke their system privileges. for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) { final String packageName = possiblyDeletedUpdatedSystemApps.get(i); - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); final String msg; // remove from the disabled system list; do this first so any future @@ -2959,7 +2972,7 @@ public class PackageManagerService extends IPackageManager.Stub // special privileges removePackageLI(pkg, true); try { - final File codePath = new File(pkg.applicationInfo.getCodePath()); + final File codePath = new File(pkg.getAppInfoCodePath()); scanPackageTracedLI(codePath, 0, scanFlags, 0, null); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to parse updated, ex-system package: " @@ -3154,7 +3167,7 @@ public class PackageManagerService extends IPackageManager.Stub } int count = 0; for (String pkgName : deferPackages) { - PackageParser.Package pkg = null; + AndroidPackage pkg = null; synchronized (mLock) { PackageSetting ps = mSettings.getPackageLPr(pkgName); if (ps != null && ps.getInstalled(UserHandle.USER_SYSTEM)) { @@ -3254,12 +3267,12 @@ public class PackageManagerService extends IPackageManager.Stub // Initialize InstantAppRegistry's Instant App list for all users. final int[] userIds = UserManagerService.getInstance().getUserIds(); - for (PackageParser.Package pkg : mPackages.values()) { + for (AndroidPackage pkg : mPackages.values()) { if (pkg.isSystem()) { continue; } for (int userId : userIds) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps == null || !ps.getInstantApp(userId) || !ps.getInstalled(userId)) { continue; } @@ -3346,7 +3359,7 @@ public class PackageManagerService extends IPackageManager.Stub continue; } // skip if the package isn't installed (?!); this should never happen - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { systemStubPackageNames.remove(i); continue; @@ -3390,43 +3403,46 @@ public class PackageManagerService extends IPackageManager.Stub * APK will be installed and the package will be disabled. To recover from this situation, * the user will need to go into system settings and re-enable the package. */ - private boolean enableCompressedPackage(PackageParser.Package stubPkg) { + private boolean enableCompressedPackage(AndroidPackage stubPkg) { final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | PackageParser.PARSE_ENFORCE_CODE; synchronized (mInstallLock) { - final PackageParser.Package pkg; + final AndroidPackage pkg; try (PackageFreezer freezer = - freezePackage(stubPkg.packageName, "setEnabledSetting")) { + freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) { pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/); synchronized (mLock) { prepareAppDataAfterInstallLIF(pkg); try { - updateSharedLibrariesLocked(pkg, null, mPackages); + updateSharedLibrariesLocked(pkg, null, + Collections.unmodifiableMap(mPackages)); } catch (PackageManagerException e) { Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e); } - mPermissionManager.updatePermissions(pkg.packageName, pkg); + mPermissionManager.updatePermissions(pkg.getPackageName(), pkg); mSettings.writeLPr(); } } catch (PackageManagerException e) { // Whoops! Something went very wrong; roll back to the stub and disable the package try (PackageFreezer freezer = - freezePackage(stubPkg.packageName, "setEnabledSetting")) { + freezePackage(stubPkg.getPackageName(), "setEnabledSetting")) { synchronized (mLock) { // NOTE: Ensure the system package is enabled; even for a compressed stub. // If we don't, installing the system package fails during scan enableSystemPackageLPw(stubPkg); } - installPackageFromSystemLIF(stubPkg.codePath, + installPackageFromSystemLIF(stubPkg.getCodePath(), null /*allUserHandles*/, null /*origUserHandles*/, null /*origPermissionsState*/, true /*writeSettings*/); } catch (PackageManagerException pme) { // Serious WTF; we have to be able to install the stub - Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme); + Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(), + pme); } finally { // Disable the package; the stub by itself is not runnable synchronized (mLock) { - final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName); + final PackageSetting stubPs = mSettings.mPackages.get( + stubPkg.getPackageName()); if (stubPs != null) { stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android"); @@ -3438,31 +3454,33 @@ public class PackageManagerService extends IPackageManager.Stub } clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); - mDexManager.notifyPackageUpdated(pkg.packageName, - pkg.baseCodePath, pkg.splitCodePaths); + mDexManager.notifyPackageUpdated(pkg.getPackageName(), + pkg.getBaseCodePath(), pkg.getSplitCodePaths()); } return true; } - private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg, + private AndroidPackage installStubPackageLI(AndroidPackage stubPkg, @ParseFlags int parseFlags, @ScanFlags int scanFlags) throws PackageManagerException { if (DEBUG_COMPRESSION) { - Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.packageName); + Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.getPackageName()); } // uncompress the binary to its eventual destination on /data - final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath); + final File scanFile = decompressPackage(stubPkg.getPackageName(), stubPkg.getCodePath()); if (scanFile == null) { - throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath); + throw new PackageManagerException( + "Unable to decompress stub at " + stubPkg.getCodePath()); } synchronized (mLock) { - mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/); + mSettings.disableSystemPackageLPw(stubPkg.getPackageName(), true /*replaced*/); } removePackageLI(stubPkg, true /*chatty*/); try { return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null); } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.packageName, e); + Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(), + e); // Remove the failed install removeCodePathLI(scanFile); throw e; @@ -3545,18 +3563,20 @@ public class PackageManagerService extends IPackageManager.Stub } private static @Nullable File preparePackageParserCache() { - if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) { - return null; - } + if (!FORCE_PACKAGE_PARSED_CACHE_ENABLED) { + if (!DEFAULT_PACKAGE_PARSER_CACHE_ENABLED) { + return null; + } - // Disable package parsing on eng builds to allow for faster incremental development. - if (Build.IS_ENG) { - return null; - } + // Disable package parsing on eng builds to allow for faster incremental development. + if (Build.IS_ENG) { + return null; + } - if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) { - Slog.i(TAG, "Disabling package parser cache due to system property."); - return null; + if (SystemProperties.getBoolean("pm.boot.disable_package_cache", false)) { + Slog.i(TAG, "Disabling package parser cache due to system property."); + return null; + } } // The base directory for the package parser cache lives under /data/system/. @@ -3568,10 +3588,12 @@ public class PackageManagerService extends IPackageManager.Stub // There are several items that need to be combined together to safely // identify cached items. In particular, changing the value of certain // feature flags should cause us to invalidate any caches. - final String cacheName = SystemProperties.digestOf( - "ro.build.fingerprint", - StorageManager.PROP_ISOLATED_STORAGE, - StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT); + final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug" + : SystemProperties.digestOf( + "ro.build.fingerprint", + StorageManager.PROP_ISOLATED_STORAGE, + StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT + ); // Reconcile cache directories, keeping only what we'd actually use. for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) { @@ -3895,7 +3917,7 @@ public class PackageManagerService extends IPackageManager.Stub ArraySet<String> packages = systemConfig.getLinkedApps(); for (String packageName : packages) { - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); if (pkg != null) { if (!pkg.isSystem()) { Slog.w(TAG, "Non-system app '" + packageName + "' in sysconfig <app-link>"); @@ -3903,13 +3925,15 @@ public class PackageManagerService extends IPackageManager.Stub } ArraySet<String> domains = null; - for (PackageParser.Activity a : pkg.activities) { - for (ActivityIntentInfo filter : a.intents) { - if (hasValidDomains(filter)) { - if (domains == null) { - domains = new ArraySet<>(); + if (pkg.getActivities() != null) { + for (ParsedActivity a : pkg.getActivities()) { + for (ParsedActivityIntentInfo filter : a.intents) { + if (hasValidDomains(filter)) { + if (domains == null) { + domains = new ArraySet<>(); + } + domains.addAll(filter.getHostsList()); } - domains.addAll(filter.getHostsList()); } } } @@ -4025,7 +4049,7 @@ public class PackageManagerService extends IPackageManager.Stub } final PackageUserState state = ps.readUserState(userId); - PackageParser.Package p = ps.pkg; + AndroidPackage p = ps.pkg; if (p != null) { final PermissionsState permissionsState = ps.getPermissionsState(); @@ -4033,10 +4057,10 @@ public class PackageManagerService extends IPackageManager.Stub final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId); // Compute granted permissions only if package has requested permissions - final Set<String> permissions = ArrayUtils.isEmpty(p.requestedPermissions) + final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions()) ? Collections.emptySet() : permissionsState.getPermissions(userId); - PackageInfo packageInfo = PackageParser.generatePackageInfo(p, gids, flags, + PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags, ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId); if (packageInfo == null) { @@ -4099,7 +4123,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new SecurityException("Package " + packageName + " is currently frozen!"); } - if (!userKeyUnlocked && !ps.pkg.applicationInfo.isEncryptionAware()) { + if (!userKeyUnlocked && !ps.pkg.isEncryptionAware()) { throw new SecurityException("Package " + packageName + " is not encryption aware!"); } } @@ -4112,9 +4136,9 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/, false /*checkShell*/, "is package available"); synchronized (mLock) { - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (p != null) { - final PackageSetting ps = (PackageSetting) p.mExtras; + final PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return false; } @@ -4179,21 +4203,22 @@ public class PackageManagerService extends IPackageManager.Stub } } - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (matchFactoryOnly && p != null && !isSystemApp(p)) { return null; } if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getPackageInfo " + packageName + ": " + p); if (p != null) { - final PackageSetting ps = (PackageSetting) p.mExtras; + final PackageSetting ps = getPackageSetting(p.getPackageName()); if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) { return null; } if (ps != null && shouldFilterApplicationLocked(ps, filterCallingUid, userId)) { return null; } - return generatePackageInfo((PackageSetting)p.mExtras, flags, userId); + + return generatePackageInfo(ps, flags, userId); } if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); @@ -4229,34 +4254,34 @@ public class PackageManagerService extends IPackageManager.Stub private boolean isComponentVisibleToInstantApp( @Nullable ComponentName component, @ComponentType int type) { if (type == TYPE_ACTIVITY) { - final PackageParser.Activity activity = mComponentResolver.getActivity(component); + final ParsedActivity activity = mComponentResolver.getActivity(component); if (activity == null) { return false; } final boolean visibleToInstantApp = - (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; + (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean explicitlyVisibleToInstantApp = - (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; + (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && explicitlyVisibleToInstantApp; } else if (type == TYPE_RECEIVER) { - final PackageParser.Activity activity = mComponentResolver.getReceiver(component); + final ParsedActivity activity = mComponentResolver.getReceiver(component); if (activity == null) { return false; } final boolean visibleToInstantApp = - (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; + (activity.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0; final boolean explicitlyVisibleToInstantApp = - (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; + (activity.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0; return visibleToInstantApp && !explicitlyVisibleToInstantApp; } else if (type == TYPE_SERVICE) { - final PackageParser.Service service = mComponentResolver.getService(component); + final ParsedService service = mComponentResolver.getService(component); return service != null - ? (service.info.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 + ? (service.flags & ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 : false; } else if (type == TYPE_PROVIDER) { - final PackageParser.Provider provider = mComponentResolver.getProvider(component); + final ParsedProvider provider = mComponentResolver.getProvider(component); return provider != null - ? (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 + ? (provider.getFlags() & ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0 : false; } else if (type == TYPE_UNKNOWN) { return isComponentVisibleToInstantApp(component); @@ -4300,16 +4325,16 @@ public class PackageManagerService extends IPackageManager.Stub // request for a specific component; if it hasn't been explicitly exposed through // property or instrumentation target, filter if (component != null) { - final PackageParser.Instrumentation instrumentation = + final ParsedInstrumentation instrumentation = mInstrumentation.get(component); if (instrumentation != null - && isCallerSameApp(instrumentation.info.targetPackage, callingUid)) { + && isCallerSameApp(instrumentation.getTargetPackage(), callingUid)) { return false; } return !isComponentVisibleToInstantApp(component, componentType); } // request for application; if no components have been explicitly exposed, filter - return !ps.pkg.visibleToInstantApps; + return !ps.pkg.isVisibleToInstantApps(); } if (ps.getInstantApp(userId)) { // caller can see all components of all instant applications, don't filter @@ -4358,12 +4383,12 @@ public class PackageManagerService extends IPackageManager.Stub } // No package means no static lib as it is always on internal storage - if (ps == null || ps.pkg == null || !ps.pkg.applicationInfo.isStaticSharedLibrary()) { + if (ps == null || ps.pkg == null || !ps.pkg.isStaticSharedLibrary()) { return false; } - final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ps.pkg.staticSharedLibName, - ps.pkg.staticSharedLibVersion); + final SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr( + ps.pkg.getStaticSharedLibName(), ps.pkg.getStaticSharedLibVersion()); if (libraryInfo == null) { return false; } @@ -4385,7 +4410,8 @@ public class PackageManagerService extends IPackageManager.Stub if (index < 0) { continue; } - if (uidPs.pkg.usesStaticLibrariesVersions[index] == libraryInfo.getLongVersion()) { + if (uidPs.pkg.getUsesStaticLibrariesVersions()[index] + == libraryInfo.getLongVersion()) { return false; } } @@ -4459,13 +4485,13 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final PackageParser.Package p = mPackages.get(packageName); + final AndroidPackage p = mPackages.get(packageName); if (p != null && p.isMatch(flags)) { - PackageSetting ps = (PackageSetting) p.mExtras; + PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return -1; } - return UserHandle.getUid(userId, p.applicationInfo.uid); + return UserHandle.getUid(userId, p.getUid()); } if ((flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); @@ -4489,9 +4515,9 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final PackageParser.Package p = mPackages.get(packageName); + final AndroidPackage p = mPackages.get(packageName); if (p != null && p.isMatch(flags)) { - PackageSetting ps = (PackageSetting) p.mExtras; + PackageSetting ps = getPackageSetting(p.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, userId)) { return null; } @@ -4541,7 +4567,7 @@ public class PackageManagerService extends IPackageManager.Stub } return null; } - ApplicationInfo ai = PackageParser.generateApplicationInfo(ps.pkg, flags, + ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, flags, ps.readUserState(userId), userId); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(ps.pkg); @@ -4579,7 +4605,7 @@ public class PackageManagerService extends IPackageManager.Stub packageName = resolveInternalPackageNameLPr(packageName, PackageManager.VERSION_CODE_HIGHEST); - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getApplicationInfo " + packageName + ": " + p); @@ -4593,7 +4619,7 @@ public class PackageManagerService extends IPackageManager.Stub return null; } // Note: isEnabledLP() does not apply here - always return info - ApplicationInfo ai = PackageParser.generateApplicationInfo( + ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo( p, flags, ps.readUserState(userId), userId); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(p); @@ -4969,17 +4995,19 @@ public class PackageManagerService extends IPackageManager.Stub } synchronized (mLock) { - PackageParser.Activity a = mComponentResolver.getActivity(component); + ParsedActivity a = mComponentResolver.getActivity(component); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); - if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) { + + AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName()); + if (pkg != null && mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) { return null; } - return PackageParser.generateActivityInfo( + return PackageInfoUtils.generateActivityInfo(pkg, a, flags, ps.readUserState(userId), userId); } if (mResolveComponentName.equals(component)) { @@ -5016,7 +5044,7 @@ public class PackageManagerService extends IPackageManager.Stub } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - PackageParser.Activity a = mComponentResolver.getActivity(component); + ParsedActivity a = mComponentResolver.getActivity(component); if (a == null) { return false; } @@ -5046,17 +5074,27 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get receiver info"); synchronized (mLock) { - PackageParser.Activity a = mComponentResolver.getReceiver(component); + ParsedActivity a = mComponentResolver.getReceiver(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getReceiverInfo " + component + ": " + a); - if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) { + + if (a == null) { + return null; + } + + AndroidPackage pkg = mPackages.get(a.getPackageName()); + if (pkg == null) { + return null; + } + + if (mSettings.isEnabledAndMatchLPr(pkg, a, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_RECEIVER, userId)) { return null; } - return PackageParser.generateActivityInfo( + return PackageInfoUtils.generateActivityInfo(pkg, a, flags, ps.readUserState(userId), userId); } } @@ -5235,13 +5273,13 @@ public class PackageManagerService extends IPackageManager.Stub } // If the dependent is a static shared lib, use the public package name String dependentPackageName = ps.name; - if (ps.pkg != null && ps.pkg.applicationInfo.isStaticSharedLibrary()) { - dependentPackageName = ps.pkg.manifestPackageName; + if (ps.pkg != null && ps.pkg.isStaticSharedLibrary()) { + dependentPackageName = ps.pkg.getManifestPackageName(); } versionedPackages.add(new VersionedPackage(dependentPackageName, ps.versionCode)); } else if (ps.pkg != null) { - if (ArrayUtils.contains(ps.pkg.usesLibraries, libName) - || ArrayUtils.contains(ps.pkg.usesOptionalLibraries, libName)) { + if (ArrayUtils.contains(ps.pkg.getUsesLibraries(), libName) + || ArrayUtils.contains(ps.pkg.getUsesOptionalLibraries(), libName)) { if (versionedPackages == null) { versionedPackages = new ArrayList<>(); } @@ -5261,17 +5299,22 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get service info"); synchronized (mLock) { - PackageParser.Service s = mComponentResolver.getService(component); + ParsedService s = mComponentResolver.getService(component); if (DEBUG_PACKAGE_INFO) Log.v( - TAG, "getServiceInfo " + component + ": " + s); - if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) { + TAG, "getServiceInfo " + component + ": " + s); + if (s == null) { + return null; + } + + AndroidPackage pkg = mPackages.get(s.getPackageName()); + if (mSettings.isEnabledAndMatchLPr(pkg, s, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_SERVICE, userId)) { return null; } - return PackageParser.generateServiceInfo( + return PackageInfoUtils.generateServiceInfo(pkg, s, flags, ps.readUserState(userId), userId); } } @@ -5286,18 +5329,27 @@ public class PackageManagerService extends IPackageManager.Stub mPermissionManager.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */, false /* checkShell */, "get provider info"); synchronized (mLock) { - PackageParser.Provider p = mComponentResolver.getProvider(component); + ParsedProvider p = mComponentResolver.getProvider(component); if (DEBUG_PACKAGE_INFO) Log.v( - TAG, "getProviderInfo " + component + ": " + p); - if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) { + TAG, "getProviderInfo " + component + ": " + p); + if (p == null) { + return null; + } + + AndroidPackage pkg = mPackages.get(p.getPackageName()); + if (pkg == null) { + return null; + } + + if (mSettings.isEnabledAndMatchLPr(pkg, p, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; if (shouldFilterApplicationLocked( ps, callingUid, component, TYPE_PROVIDER, userId)) { return null; } - return PackageParser.generateProviderInfo( - p, flags, ps.readUserState(userId), userId); + PackageUserState state = ps.readUserState(userId); + return PackageInfoUtils.generateProviderInfo(pkg, p, flags, state, userId); } } return null; @@ -5555,21 +5607,21 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int checkSignatures(String pkg1, String pkg2) { synchronized (mLock) { - final PackageParser.Package p1 = mPackages.get(pkg1); - final PackageParser.Package p2 = mPackages.get(pkg2); - if (p1 == null || p1.mExtras == null - || p2 == null || p2.mExtras == null) { + final AndroidPackage p1 = mPackages.get(pkg1); + final AndroidPackage p2 = mPackages.get(pkg2); + final PackageSetting ps1 = p1 == null ? null : getPackageSetting(p1.getPackageName()); + final PackageSetting ps2 = p2 == null ? null : getPackageSetting(p2.getPackageName()); + if (p1 == null || ps1 == null || p2 == null || ps2 == null) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - final PackageSetting ps1 = (PackageSetting) p1.mExtras; - final PackageSetting ps2 = (PackageSetting) p2.mExtras; if (shouldFilterApplicationLocked(ps1, callingUid, callingUserId) || shouldFilterApplicationLocked(ps2, callingUid, callingUserId)) { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - return compareSignatures(p1.mSigningDetails.signatures, p2.mSigningDetails.signatures); + return compareSignatures(p1.getSigningDetails().signatures, + p2.getSigningDetails().signatures); } } @@ -5632,21 +5684,21 @@ public class PackageManagerService extends IPackageManager.Stub String packageName, byte[] certificate, @PackageManager.CertificateInputType int type) { synchronized (mLock) { - final PackageParser.Package p = mPackages.get(packageName); - if (p == null || p.mExtras == null) { + final AndroidPackage p = mPackages.get(packageName); + final PackageSetting ps = getPackageSetting(p.getPackageName()); + if (p == null || ps == null) { return false; } final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - final PackageSetting ps = (PackageSetting) p.mExtras; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return false; } switch (type) { case CERT_INPUT_RAW_X509: - return p.mSigningDetails.hasCertificate(certificate); + return p.getSigningDetails().hasCertificate(certificate); case CERT_INPUT_SHA256: - return p.mSigningDetails.hasSha256Certificate(certificate); + return p.getSigningDetails().hasSha256Certificate(certificate); default: return false; } @@ -5699,16 +5751,16 @@ public class PackageManagerService extends IPackageManager.Stub * external storage) is less than the version where package signatures * were updated, return true. */ - private boolean isCompatSignatureUpdateNeeded(PackageParser.Package scannedPkg) { - return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg)); + private boolean isCompatSignatureUpdateNeeded(AndroidPackage pkg) { + return isCompatSignatureUpdateNeeded(getSettingsVersionForPackage(pkg)); } private static boolean isCompatSignatureUpdateNeeded(VersionInfo ver) { return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY; } - private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) { - return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(scannedPkg)); + private boolean isRecoverSignatureUpdateNeeded(AndroidPackage pkg) { + return isRecoverSignatureUpdateNeeded(getSettingsVersionForPackage(pkg)); } private static boolean isRecoverSignatureUpdateNeeded(VersionInfo ver) { @@ -5727,24 +5779,23 @@ public class PackageManagerService extends IPackageManager.Stub final List<String> result = new ArrayList<>(); if (instantAppPkgName != null) { // caller is an instant application; filter unexposed applications - for (PackageParser.Package pkg : mPackages.values()) { - if (!pkg.visibleToInstantApps) { + for (AndroidPackage pkg : mPackages.values()) { + if (!pkg.isVisibleToInstantApps()) { continue; } - result.add(pkg.packageName); + result.add(pkg.getPackageName()); } } else { // caller is a normal application; filter instant applications - for (PackageParser.Package pkg : mPackages.values()) { - final PackageSetting ps = - pkg.mExtras != null ? (PackageSetting) pkg.mExtras : null; + for (AndroidPackage pkg : mPackages.values()) { + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null && ps.getInstantApp(callingUserId) && !mInstantAppRegistry.isInstantAccessGranted( callingUserId, UserHandle.getAppId(callingUid), ps.appId)) { continue; } - result.add(pkg.packageName); + result.add(pkg.getPackageName()); } } return result; @@ -6590,7 +6641,7 @@ public class PackageManagerService extends IPackageManager.Stub if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; final boolean isInstantApp = ps.getInstantApp(UserHandle.getUserId(callingUid)); - return isInstantApp ? ps.pkg.packageName : null; + return isInstantApp ? ps.pkg.getPackageName() : null; } } return null; @@ -6662,9 +6713,11 @@ public class PackageManagerService extends IPackageManager.Stub list.add(ri); } } - return applyPostResolutionFilter( + + List<ResolveInfo> result = applyPostResolutionFilter( list, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent); + return result; } // reader @@ -6741,11 +6794,11 @@ public class PackageManagerService extends IPackageManager.Stub sortResult = true; } } else { - final PackageParser.Package pkg = mPackages.get(pkgName); + final AndroidPackage pkg = mPackages.get(pkgName); result = null; if (pkg != null) { result = filterIfNotSystemUser(mComponentResolver.queryActivities( - intent, resolvedType, flags, pkg.activities, userId), userId); + intent, resolvedType, flags, pkg.getActivities(), userId), userId); } if (result == null || result.size() == 0) { // the caller wants to resolve for a particular package; however, there @@ -7638,10 +7691,10 @@ public class PackageManagerService extends IPackageManager.Stub result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); } - final PackageParser.Package pkg = mPackages.get(pkgName); + final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { final List<ResolveInfo> result = mComponentResolver.queryReceivers( - intent, resolvedType, flags, pkg.receivers, userId); + intent, resolvedType, flags, pkg.getReceivers(), userId); return applyPostResolutionFilter( result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId, intent); @@ -7740,11 +7793,11 @@ public class PackageManagerService extends IPackageManager.Stub mComponentResolver.queryServices(intent, resolvedType, flags, userId), instantAppPkgName); } - final PackageParser.Package pkg = mPackages.get(pkgName); + final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { return applyPostServiceResolutionFilter( - mComponentResolver.queryServices(intent, resolvedType, flags, pkg.services, - userId), + mComponentResolver.queryServices(intent, resolvedType, flags, + pkg.getServices(), userId), instantAppPkgName); } return Collections.emptyList(); @@ -7858,11 +7911,11 @@ public class PackageManagerService extends IPackageManager.Stub mComponentResolver.queryProviders(intent, resolvedType, flags, userId), instantAppPkgName); } - final PackageParser.Package pkg = mPackages.get(pkgName); + final AndroidPackage pkg = mPackages.get(pkgName); if (pkg != null) { return applyPostContentProviderResolutionFilter( mComponentResolver.queryProviders(intent, resolvedType, flags, - pkg.providers, userId), + pkg.getProviders(), userId), instantAppPkgName); } return Collections.emptyList(); @@ -7947,16 +8000,15 @@ public class PackageManagerService extends IPackageManager.Stub } } else { list = new ArrayList<>(mPackages.size()); - for (PackageParser.Package p : mPackages.values()) { - final PackageSetting ps = (PackageSetting) p.mExtras; + for (AndroidPackage p : mPackages.values()) { + final PackageSetting ps = getPackageSetting(p.getPackageName()); if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } - final PackageInfo pi = generatePackageInfo((PackageSetting) - p.mExtras, flags, userId); + final PackageInfo pi = generatePackageInfo(ps, flags, userId); if (pi != null) { list.add(pi); } @@ -8035,8 +8087,8 @@ public class PackageManagerService extends IPackageManager.Stub userId); } } else { - for (PackageParser.Package pkg : mPackages.values()) { - PackageSetting ps = (PackageSetting)pkg.mExtras; + for (AndroidPackage pkg : mPackages.values()) { + PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null) { addPackageHoldingPermissions(list, ps, permissions, tmpBools, flags, userId); @@ -8089,7 +8141,7 @@ public class PackageManagerService extends IPackageManager.Stub if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } - ai = PackageParser.generateApplicationInfo(ps.pkg, effectiveFlags, + ai = PackageInfoUtils.generateApplicationInfo(ps.pkg, effectiveFlags, ps.readUserState(userId), userId); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(ps.pkg); @@ -8106,16 +8158,16 @@ public class PackageManagerService extends IPackageManager.Stub } } else { list = new ArrayList<>(mPackages.size()); - for (PackageParser.Package p : mPackages.values()) { - if (p.mExtras != null) { - PackageSetting ps = (PackageSetting) p.mExtras; + for (AndroidPackage p : mPackages.values()) { + final PackageSetting ps = getPackageSetting(p.getPackageName()); + if (ps != null) { if (filterSharedLibPackageLPr(ps, Binder.getCallingUid(), userId, flags)) { continue; } if (shouldFilterApplicationLocked(ps, callingUid, userId)) { continue; } - ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, + ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { ai.packageName = resolveExternalPackageNameLPr(p); @@ -8171,7 +8223,6 @@ public class PackageManagerService extends IPackageManager.Stub callingUid = mIsolatedOwners.get(callingUid); } final PackageSetting ps = mSettings.mPackages.get(packageName); - PackageParser.Package pkg = mPackages.get(packageName); final boolean returnAllowed = ps != null && (isCallerSameApp(packageName, callingUid) @@ -8242,9 +8293,9 @@ public class PackageManagerService extends IPackageManager.Stub } private boolean isCallerSameApp(String packageName, int uid) { - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); return pkg != null - && UserHandle.getAppId(uid) == pkg.applicationInfo.uid; + && UserHandle.getAppId(uid) == pkg.getUid(); } @Override @@ -8260,23 +8311,22 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final Iterator<PackageParser.Package> i = mPackages.values().iterator(); + final Iterator<AndroidPackage> i = mPackages.values().iterator(); final int userId = UserHandle.getCallingUserId(); while (i.hasNext()) { - final PackageParser.Package p = i.next(); - if (p.applicationInfo == null) continue; + final AndroidPackage p = i.next(); final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0) - && !p.applicationInfo.isDirectBootAware(); + && !p.isDirectBootAware(); final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0) - && p.applicationInfo.isDirectBootAware(); + && p.isDirectBootAware(); - if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0 + if ((p.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0 && (!mSafeMode || isSystemApp(p)) && (matchesUnaware || matchesAware)) { - PackageSetting ps = mSettings.mPackages.get(p.packageName); + PackageSetting ps = mSettings.mPackages.get(p.getPackageName()); if (ps != null) { - ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags, + ApplicationInfo ai = PackageInfoUtils.generateApplicationInfo(p, flags, ps.readUserState(userId), userId); if (ai != null) { finalList.add(ai); @@ -8298,7 +8348,8 @@ public class PackageManagerService extends IPackageManager.Stub if (!mUserManager.exists(userId)) return null; flags = updateFlagsForComponent(flags, userId, name); final int callingUid = Binder.getCallingUid(); - final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId); + final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, callingUid, + userId); if (providerInfo == null) { return null; } @@ -8380,8 +8431,8 @@ public class PackageManagerService extends IPackageManager.Stub ps, callingUid, component, TYPE_UNKNOWN, callingUserId)) { return null; } - final PackageParser.Instrumentation i = mInstrumentation.get(component); - return PackageParser.generateInstrumentationInfo(i, flags); + final ParsedInstrumentation i = mInstrumentation.get(component); + return PackageInfoUtils.generateInstrumentationInfo(i, flags); } } @@ -8403,12 +8454,12 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final Iterator<PackageParser.Instrumentation> i = mInstrumentation.values().iterator(); + final Iterator<ParsedInstrumentation> i = mInstrumentation.values().iterator(); while (i.hasNext()) { - final PackageParser.Instrumentation p = i.next(); + final ParsedInstrumentation p = i.next(); if (targetPackage == null - || targetPackage.equals(p.info.targetPackage)) { - InstrumentationInfo ii = PackageParser.generateInstrumentationInfo(p, + || targetPackage.equals(p.getTargetPackage())) { + InstrumentationInfo ii = PackageInfoUtils.generateInstrumentationInfo(p, flags); if (ii != null) { finalList.add(ii); @@ -8465,18 +8516,18 @@ public class PackageManagerService extends IPackageManager.Stub if (throwable == null) { // TODO(toddke): move lower in the scan chain // Static shared libraries have synthetic package names - if (parseResult.pkg.applicationInfo.isStaticSharedLibrary()) { - renameStaticSharedLibraryPackage(parseResult.pkg); + if (parseResult.parsedPackage.isStaticSharedLibrary()) { + renameStaticSharedLibraryPackage(parseResult.parsedPackage); } try { - scanPackageChildLI(parseResult.pkg, parseFlags, scanFlags, + addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime, null); } catch (PackageManagerException e) { errorCode = e.error; Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage()); } - } else if (throwable instanceof PackageParser.PackageParserException) { - PackageParser.PackageParserException e = (PackageParser.PackageParserException) + } else if (throwable instanceof PackageParserException) { + PackageParserException e = (PackageParserException) throwable; errorCode = e.error; Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage()); @@ -8500,15 +8551,16 @@ public class PackageManagerService extends IPackageManager.Stub logCriticalInfo(priority, msg); } - private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, + private void collectCertificatesLI(PackageSetting ps, ParsedPackage parsedPackage, boolean forceCollect, boolean skipVerify) throws PackageManagerException { // When upgrading from pre-N MR1, verify the package time stamp using the package // directory and not the APK file. final long lastModifiedTime = mIsPreNMR1Upgrade - ? new File(pkg.codePath).lastModified() : getLastModifiedTime(pkg); - final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(pkg); + ? new File(parsedPackage.getCodePath()).lastModified() + : getLastModifiedTime(parsedPackage); + final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage); if (ps != null && !forceCollect - && ps.codePathString.equals(pkg.codePath) + && ps.codePathString.equals(parsedPackage.getCodePath()) && ps.timeStamp == lastModifiedTime && !isCompatSignatureUpdateNeeded(settingsVersionForPackage) && !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) { @@ -8518,21 +8570,21 @@ public class PackageManagerService extends IPackageManager.Stub != SignatureSchemeVersion.UNKNOWN) { // Optimization: reuse the existing cached signing data // if the package appears to be unchanged. - pkg.mSigningDetails = - new PackageParser.SigningDetails(ps.signatures.mSigningDetails); + parsedPackage.setSigningDetails( + new PackageParser.SigningDetails(ps.signatures.mSigningDetails)); return; } Slog.w(TAG, "PackageSetting for " + ps.name + " is missing signatures. Collecting certs again to recover them."); } else { - Slog.i(TAG, pkg.codePath + " changed; collecting certs" + + Slog.i(TAG, parsedPackage.getCodePath() + " changed; collecting certs" + (forceCollect ? " (forced)" : "")); } try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates"); - PackageParser.collectCertificates(pkg, skipVerify); + ApkParseUtils.collectCertificates(parsedPackage, skipVerify); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { @@ -8546,20 +8598,20 @@ public class PackageManagerService extends IPackageManager.Stub */ private void maybeClearProfilesForUpgradesLI( @Nullable PackageSetting originalPkgSetting, - @NonNull PackageParser.Package currentPkg) { + @NonNull AndroidPackage pkg) { if (originalPkgSetting == null || !isDeviceUpgrading()) { return; } - if (originalPkgSetting.versionCode == currentPkg.mVersionCode) { + if (originalPkgSetting.versionCode == pkg.getVersionCode()) { return; } - clearAppProfilesLIF(currentPkg, UserHandle.USER_ALL); + clearAppProfilesLIF(pkg, UserHandle.USER_ALL); if (DEBUG_INSTALL) { Slog.d(TAG, originalPkgSetting.name + " clear profile due to version change " + originalPkgSetting.versionCode + " != " - + currentPkg.mVersionCode); + + pkg.getVersionCode()); } } @@ -8568,7 +8620,7 @@ public class PackageManagerService extends IPackageManager.Stub * @see #scanPackageLI(File, int, int, long, UserHandle) */ @GuardedBy({"mInstallLock", "mLock"}) - private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags, + private AndroidPackage scanPackageTracedLI(File scanFile, final int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]"); try { @@ -8583,7 +8635,7 @@ public class PackageManagerService extends IPackageManager.Stub * Returns {@code null} in case of errors and the error code is stored in mLastScanError */ @GuardedBy({"mInstallLock", "mLock"}) - private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, + private AndroidPackage scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); PackageParser pp = new PackageParser(); @@ -8593,9 +8645,9 @@ public class PackageManagerService extends IPackageManager.Stub pp.setCallback(mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); - final PackageParser.Package pkg; + final ParsedPackage parsedPackage; try { - pkg = pp.parsePackage(scanFile, parseFlags); + parsedPackage = pp.parseParsedPackage(scanFile, parseFlags, false); } catch (PackageParserException e) { throw PackageManagerException.from(e); } finally { @@ -8603,66 +8655,25 @@ public class PackageManagerService extends IPackageManager.Stub } // Static shared libraries have synthetic package names - if (pkg.applicationInfo.isStaticSharedLibrary()) { - renameStaticSharedLibraryPackage(pkg); - } - - return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user); - } - - /** - * Scans a package and returns the newly parsed package. - * @throws PackageManagerException on a parse error. - */ - @GuardedBy({"mInstallLock", "mLock"}) - private PackageParser.Package scanPackageChildLI(PackageParser.Package pkg, - final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, - @Nullable UserHandle user) - throws PackageManagerException { - // If the package has children and this is the first dive in the function - // we scan the package with the SCAN_CHECK_ONLY flag set to see whether all - // packages (parent and children) would be successfully scanned before the - // actual scan since scanning mutates internal state and we want to atomically - // install the package and its children. - if ((scanFlags & SCAN_CHECK_ONLY) == 0) { - if (pkg.childPackages != null && pkg.childPackages.size() > 0) { - scanFlags |= SCAN_CHECK_ONLY; - } - } else { - scanFlags &= ~SCAN_CHECK_ONLY; - } - - // Scan the parent - PackageParser.Package scannedPkg = addForInitLI(pkg, parseFlags, - scanFlags, currentTime, user); - - // Scan the children - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPackage = pkg.childPackages.get(i); - addForInitLI(childPackage, parseFlags, scanFlags, - currentTime, user); + if (parsedPackage.isStaticSharedLibrary()) { + renameStaticSharedLibraryPackage(parsedPackage); } - - if ((scanFlags & SCAN_CHECK_ONLY) != 0) { - return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user); - } - - return scannedPkg; + return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user); } /** * Returns if forced apk verification can be skipped for the whole package, including splits. */ - private boolean canSkipForcedPackageVerification(PackageParser.Package pkg) { - if (!canSkipForcedApkVerification(pkg.baseCodePath)) { + private boolean canSkipForcedPackageVerification(AndroidPackage pkg) { + if (!canSkipForcedApkVerification(pkg.getBaseCodePath())) { return false; } // TODO: Allow base and splits to be verified individually. - if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { - for (int i = 0; i < pkg.splitCodePaths.length; i++) { - if (!canSkipForcedApkVerification(pkg.splitCodePaths[i])) { + String[] splitCodePaths = pkg.getSplitCodePaths(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + if (!canSkipForcedApkVerification(splitCodePaths[i])) { return false; } } @@ -8711,7 +8722,7 @@ public class PackageManagerService extends IPackageManager.Stub * <p>NOTE: The return value should be removed. It's the passed in package object. */ @GuardedBy({"mInstallLock", "mLock"}) - private PackageParser.Package addForInitLI(PackageParser.Package pkg, + private AndroidPackage addForInitLI(ParsedPackage parsedPackage, @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { @@ -8727,25 +8738,27 @@ public class PackageManagerService extends IPackageManager.Stub // stack [such as scanPackageOnly()]. However, we verify the application // info prior to that [in scanPackageNew()] and thus have to setup // the application info early. - pkg.setApplicationVolumeUuid(pkg.volumeUuid); - pkg.setApplicationInfoCodePath(pkg.codePath); - pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths); - pkg.setApplicationInfoResourcePath(pkg.codePath); - pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths); + // TODO(b/135203078): Remove all of these application info calls + parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) + .setApplicationInfoCodePath(parsedPackage.getCodePath()) + .setApplicationInfoResourcePath(parsedPackage.getCodePath()) + .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) + .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); synchronized (mLock) { - renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage); - final String realPkgName = getRealPackageName(pkg, renamedPkgName); + renamedPkgName = mSettings.getRenamedPackageLPr(parsedPackage.getRealPackage()); + final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName); if (realPkgName != null) { - ensurePackageRenamed(pkg, renamedPkgName); + ensurePackageRenamed(parsedPackage, renamedPkgName); } - final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName); - final PackageSetting installedPkgSetting = mSettings.getPackageLPr(pkg.packageName); + final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage, + renamedPkgName); + final PackageSetting installedPkgSetting = mSettings.getPackageLPr( + parsedPackage.getPackageName()); pkgSetting = originalPkgSetting == null ? installedPkgSetting : originalPkgSetting; pkgAlreadyExists = pkgSetting != null; - final String disabledPkgName = pkgAlreadyExists ? pkgSetting.name : pkg.packageName; + final String disabledPkgName = + pkgAlreadyExists ? pkgSetting.name : parsedPackage.getPackageName(); disabledPkgSetting = mSettings.getDisabledSystemPkgLPr(disabledPkgName); isSystemPkgUpdated = disabledPkgSetting != null; @@ -8753,49 +8766,29 @@ public class PackageManagerService extends IPackageManager.Stub Slog.d(TAG, "updatedPkg = " + disabledPkgSetting); } - final SharedUserSetting sharedUserSetting = (pkg.mSharedUserId != null) - ? mSettings.getSharedUserLPw(pkg.mSharedUserId, + final SharedUserSetting sharedUserSetting = (parsedPackage.getSharedUserId() != null) + ? mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(), 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true) : null; if (DEBUG_PACKAGE_SCANNING && (parseFlags & PackageParser.PARSE_CHATTY) != 0 && sharedUserSetting != null) { - Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId() + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); } if (scanSystemPartition) { - // Potentially prune child packages. If the application on the /system - // partition has been updated via OTA, but, is still disabled by a - // version on /data, cycle through all of its children packages and - // remove children that are no longer defined. if (isSystemPkgUpdated) { - final int scannedChildCount = (pkg.childPackages != null) - ? pkg.childPackages.size() : 0; - final int disabledChildCount = disabledPkgSetting.childPackageNames != null - ? disabledPkgSetting.childPackageNames.size() : 0; - for (int i = 0; i < disabledChildCount; i++) { - String disabledChildPackageName = - disabledPkgSetting.childPackageNames.get(i); - boolean disabledPackageAvailable = false; - for (int j = 0; j < scannedChildCount; j++) { - PackageParser.Package childPkg = pkg.childPackages.get(j); - if (childPkg.packageName.equals(disabledChildPackageName)) { - disabledPackageAvailable = true; - break; - } - } - if (!disabledPackageAvailable) { - mSettings.removeDisabledSystemPackageLPw(disabledChildPackageName); - } - } // we're updating the disabled package, so, scan it as the package setting - final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, null, - disabledPkgSetting /* pkgSetting */, null /* disabledPkgSetting */, - null /* originalPkgSetting */, null, parseFlags, scanFlags, - (pkg == mPlatformPackage), user); - applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage); + boolean isPlatformPackage = mPlatformPackage != null + && Objects.equals(mPlatformPackage.getPackageName(), + parsedPackage.getPackageName()); + final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting, + null, disabledPkgSetting /* pkgSetting */, + null /* disabledPkgSetting */, null /* originalPkgSetting */, + null, parseFlags, scanFlags, isPlatformPackage, user); + applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage); final ScanResult scanResult = scanPackageOnlyLI(request, mInjector, mFactoryTest, -1L); if (scanResult.existingSettingCopied && scanResult.request.pkgSetting != null) { @@ -8806,9 +8799,9 @@ public class PackageManagerService extends IPackageManager.Stub } final boolean newPkgChangedPaths = - pkgAlreadyExists && !pkgSetting.codePathString.equals(pkg.codePath); + pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath()); final boolean newPkgVersionGreater = - pkgAlreadyExists && pkg.getLongVersionCode() > pkgSetting.versionCode; + pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode; final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated && newPkgChangedPaths && newPkgVersionGreater; if (isSystemPkgBetter) { @@ -8824,12 +8817,13 @@ public class PackageManagerService extends IPackageManager.Stub logCriticalInfo(Log.WARN, "System package updated;" + " name: " + pkgSetting.name - + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() - + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); + + "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode() + + "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath()); final InstallArgs args = createInstallArgsForExisting( pkgSetting.codePathString, - pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting)); + pkgSetting.resourcePathString, getAppDexInstructionSets( + pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString)); args.cleanUpResourcesLI(); synchronized (mLock) { mSettings.enableSystemPackageLPw(pkgSetting.name); @@ -8840,9 +8834,10 @@ public class PackageManagerService extends IPackageManager.Stub // The version of the application on the /system partition is less than or // equal to the version on the /data partition. Throw an exception and use // the application already installed on the /data partition. - throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at " - + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode - + " better than this " + pkg.getLongVersionCode()); + throw new PackageManagerException(Log.WARN, "Package " + parsedPackage.getPackageName() + + " at " + parsedPackage.getCodePath() + " ignored: updated version " + + pkgSetting.versionCode + " better than this " + + parsedPackage.getLongVersionCode()); } // Verify certificates against what was last scanned. Force re-collecting certificate in two @@ -8853,18 +8848,18 @@ public class PackageManagerService extends IPackageManager.Stub final boolean forceCollect = scanSystemPartition ? mIsUpgrade : PackageManagerServiceUtils.isApkVerificationForced(pkgSetting); if (DEBUG_VERIFY && forceCollect) { - Slog.d(TAG, "Force collect certificate of " + pkg.packageName); + Slog.d(TAG, "Force collect certificate of " + parsedPackage.getPackageName()); } // Full APK verification can be skipped during certificate collection, only if the file is // in verified partition, or can be verified on access (when apk verity is enabled). In both // cases, only data in Signing Block is verified instead of the whole file. final boolean skipVerify = scanSystemPartition - || (forceCollect && canSkipForcedPackageVerification(pkg)); - collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify); + || (forceCollect && canSkipForcedPackageVerification(parsedPackage)); + collectCertificatesLI(pkgSetting, parsedPackage, forceCollect, skipVerify); // Reset profile if the application version is changed - maybeClearProfilesForUpgradesLI(pkgSetting, pkg); + maybeClearProfilesForUpgradesLI(pkgSetting, parsedPackage); /* * A new system app appeared, but we already had a non-system one of the @@ -8876,17 +8871,20 @@ public class PackageManagerService extends IPackageManager.Stub if (scanSystemPartition && !isSystemPkgUpdated && pkgAlreadyExists && !pkgSetting.isSystem()) { - if (!pkg.mSigningDetails.checkCapability(pkgSetting.signatures.mSigningDetails, + if (!parsedPackage.getSigningDetails() + .checkCapability(pkgSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA) && !pkgSetting.signatures.mSigningDetails.checkCapability( - pkg.mSigningDetails, + parsedPackage.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) { logCriticalInfo(Log.WARN, "System package signature mismatch;" + " name: " + pkgSetting.name); - try (PackageFreezer freezer = freezePackage(pkg.packageName, + try (@SuppressWarnings("unused") PackageFreezer freezer = freezePackage( + parsedPackage.getPackageName(), "scanPackageInternalLI")) { - deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null); + deletePackageLIF(parsedPackage.getPackageName(), null, true, null, 0, null, + false, null); } pkgSetting = null; } else if (newPkgVersionGreater) { @@ -8895,12 +8893,15 @@ public class PackageManagerService extends IPackageManager.Stub // and replace it with the version on /system. logCriticalInfo(Log.WARN, "System package enabled;" - + " name: " + pkgSetting.name - + "; " + pkgSetting.versionCode + " --> " + pkg.getLongVersionCode() - + "; " + pkgSetting.codePathString + " --> " + pkg.codePath); + + " name: " + pkgSetting.name + + "; " + pkgSetting.versionCode + " --> " + + parsedPackage.getLongVersionCode() + + "; " + pkgSetting.codePathString + " --> " + + parsedPackage.getCodePath()); InstallArgs args = createInstallArgsForExisting( pkgSetting.codePathString, - pkgSetting.resourcePathString, getAppDexInstructionSets(pkgSetting)); + pkgSetting.resourcePathString, getAppDexInstructionSets( + pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString)); synchronized (mInstallLock) { args.cleanUpResourcesLI(); } @@ -8911,13 +8912,15 @@ public class PackageManagerService extends IPackageManager.Stub shouldHideSystemApp = true; logCriticalInfo(Log.INFO, "System package disabled;" - + " name: " + pkgSetting.name - + "; old: " + pkgSetting.codePathString + " @ " + pkgSetting.versionCode - + "; new: " + pkg.codePath + " @ " + pkg.codePath); + + " name: " + pkgSetting.name + + "; old: " + pkgSetting.codePathString + " @ " + + pkgSetting.versionCode + + "; new: " + parsedPackage.getCodePath() + " @ " + + parsedPackage.getCodePath()); } } - final ScanResult scanResult = scanPackageNewLI(pkg, parseFlags, scanFlags + final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); if (scanResult.success) { synchronized (mLock) { @@ -8930,7 +8933,7 @@ public class PackageManagerService extends IPackageManager.Stub mSharedLibraries, mPackages, Collections.singletonMap( - pkgName, getSettingsVersionForPackage(pkg)), + pkgName, getSettingsVersionForPackage(parsedPackage)), Collections.singletonMap(pkgName, getSharedLibLatestVersionSetting(scanResult))), mSettings.mKeySetManagerService); @@ -8947,16 +8950,17 @@ public class PackageManagerService extends IPackageManager.Stub if (shouldHideSystemApp) { synchronized (mLock) { - mSettings.disableSystemPackageLPw(pkg.packageName, true); + mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true); } } return scanResult.pkgSetting.pkg; } - private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) { + // TODO:(b/135203078): Move to parsing + private static void renameStaticSharedLibraryPackage(ParsedPackage parsedPackage) { // Derive the new package synthetic package name - pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER - + pkg.staticSharedLibVersion); + parsedPackage.setPackageName(parsedPackage.getPackageName() + STATIC_SHARED_LIB_DELIMITER + + parsedPackage.getStaticSharedLibVersion()); } static String fixProcessName(String defProcessName, String processName) { @@ -9057,7 +9061,7 @@ public class PackageManagerService extends IPackageManager.Stub return; } - List<PackageParser.Package> pkgs; + List<AndroidPackage> pkgs; synchronized (mLock) { pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this); } @@ -9080,8 +9084,8 @@ public class PackageManagerService extends IPackageManager.Stub /* * Return the prebuilt profile path given a package base code path. */ - private static String getPrebuildProfilePath(PackageParser.Package pkg) { - return pkg.baseCodePath + ".prof"; + private static String getPrebuildProfilePath(AndroidPackage pkg) { + return pkg.getBaseCodePath() + ".prof"; } /** @@ -9090,7 +9094,7 @@ public class PackageManagerService extends IPackageManager.Stub * which are (in order) {@code numberOfPackagesOptimized}, {@code numberOfPackagesSkipped} * and {@code numberOfPackagesFailed}. */ - private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog, + private int[] performDexOptUpgrade(List<AndroidPackage> pkgs, boolean showDialog, final int compilationReason, boolean bootComplete) { int numberOfPackagesVisited = 0; @@ -9099,7 +9103,7 @@ public class PackageManagerService extends IPackageManager.Stub int numberOfPackagesFailed = 0; final int numberOfPackagesToDexopt = pkgs.size(); - for (PackageParser.Package pkg : pkgs) { + for (AndroidPackage pkg : pkgs) { numberOfPackagesVisited++; boolean useProfileForDexopt = false; @@ -9115,7 +9119,7 @@ public class PackageManagerService extends IPackageManager.Stub // PackageDexOptimizer to prevent this happening on first boot. The issue // is that we don't have a good way to say "do this only once". if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), - pkg.applicationInfo.uid, pkg.packageName, + pkg.getUid(), pkg.getPackageName(), ArtManager.getProfileName(null))) { Log.e(TAG, "Installer failed to copy system profile!"); } else { @@ -9128,11 +9132,12 @@ public class PackageManagerService extends IPackageManager.Stub e); } } else { - PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName); + PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr( + pkg.getPackageName()); // Handle compressed APKs in this path. Only do this for stubs with profiles to // minimize the number off apps being speed-profile compiled during first boot. // The other paths will not change the filter. - if (disabledPs != null && disabledPs.pkg.isStub) { + if (disabledPs != null && disabledPs.pkg.isStub()) { // The package is the stub one, remove the stub suffix to get the normal // package and APK names. String systemProfilePath = @@ -9151,7 +9156,7 @@ public class PackageManagerService extends IPackageManager.Stub // issue is that we don't have a good way to say "do this only // once". if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(), - pkg.applicationInfo.uid, pkg.packageName, + pkg.getUid(), pkg.getPackageName(), ArtManager.getProfileName(null))) { Log.e(TAG, "Failed to copy system profile for stub package!"); } else { @@ -9168,7 +9173,7 @@ public class PackageManagerService extends IPackageManager.Stub if (!PackageDexOptimizer.canOptimizePackage(pkg)) { if (DEBUG_DEXOPT) { - Log.i(TAG, "Skipping update of of non-optimizable app " + pkg.packageName); + Log.i(TAG, "Skipping update of non-optimizable app " + pkg.getPackageName()); } numberOfPackagesSkipped++; continue; @@ -9176,7 +9181,7 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_DEXOPT) { Log.i(TAG, "Updating app " + numberOfPackagesVisited + " of " + - numberOfPackagesToDexopt + ": " + pkg.packageName); + numberOfPackagesToDexopt + ": " + pkg.getPackageName()); } if (showDialog) { @@ -9213,7 +9218,7 @@ public class PackageManagerService extends IPackageManager.Stub dexoptFlags |= DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE; } int primaryDexOptStaus = performDexOptTraced(new DexoptOptions( - pkg.packageName, + pkg.getPackageName(), pkgCompilationReason, dexoptFlags)); @@ -9257,11 +9262,11 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private void notifyPackageUseLocked(String packageName, int reason) { - final PackageParser.Package p = mPackages.get(packageName); + final AndroidPackage p = mPackages.get(packageName); if (p == null) { return; } - p.mLastPackageUsageTimeInMills[reason] = System.currentTimeMillis(); + p.mutate().setLastPackageUsageTimeInMills(reason, System.currentTimeMillis()); } @Override @@ -9341,7 +9346,7 @@ public class PackageManagerService extends IPackageManager.Stub */ @Override public boolean compileLayouts(String packageName) { - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -9388,7 +9393,7 @@ public class PackageManagerService extends IPackageManager.Stub // Run dexopt on a given package. Returns true if dexopt did not fail, i.e. // if the package can now be considered up to date for the given filter. private int performDexOptInternal(DexoptOptions options) { - PackageParser.Package p; + AndroidPackage p; synchronized (mLock) { p = mPackages.get(options.getPackageName()); if (p == null) { @@ -9411,16 +9416,16 @@ public class PackageManagerService extends IPackageManager.Stub public ArraySet<String> getOptimizablePackages() { ArraySet<String> pkgs = new ArraySet<>(); synchronized (mLock) { - for (PackageParser.Package p : mPackages.values()) { + for (AndroidPackage p : mPackages.values()) { if (PackageDexOptimizer.canOptimizePackage(p)) { - pkgs.add(p.packageName); + pkgs.add(p.getPackageName()); } } } return pkgs; } - private int performDexOptInternalWithDependenciesLI(PackageParser.Package p, + private int performDexOptInternalWithDependenciesLI(AndroidPackage p, DexoptOptions options) { // Select the dex optimizer based on the force parameter. // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to @@ -9437,14 +9442,15 @@ public class PackageManagerService extends IPackageManager.Stub // and the first package that uses the library will dexopt it. The // others will see that the compiled code for the library is up to date. Collection<SharedLibraryInfo> deps = findSharedLibraries(p); - final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo); + final String[] instructionSets = getAppDexInstructionSets(p.getPrimaryCpuAbi(), + p.getSecondaryCpuAbi()); if (!deps.isEmpty()) { DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(), options.getCompilationReason(), options.getCompilerFilter(), options.getSplitName(), options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY); for (SharedLibraryInfo info : deps) { - PackageParser.Package depPackage = null; + AndroidPackage depPackage = null; synchronized (mLock) { depPackage = mPackages.get(info.getPackageName()); } @@ -9452,7 +9458,7 @@ public class PackageManagerService extends IPackageManager.Stub // TODO: Analyze and investigate if we (should) profile libraries. pdo.performDexOpt(depPackage, instructionSets, getOrCreateCompilerPackageStats(depPackage), - mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), + mDexManager.getPackageUseInfoOrDefault(depPackage.getPackageName()), libraryOptions); } else { // TODO(ngeoffray): Support dexopting system shared libraries. @@ -9461,7 +9467,7 @@ public class PackageManagerService extends IPackageManager.Stub } return pdo.performDexOpt(p, instructionSets, getOrCreateCompilerPackageStats(p), - mDexManager.getPackageUseInfoOrDefault(p.packageName), options); + mDexManager.getPackageUseInfoOrDefault(p.getPackageName()), options); } /** @@ -9502,11 +9508,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) { - if (p.usesLibraryInfos != null) { + private static List<SharedLibraryInfo> findSharedLibraries(AndroidPackage p) { + if (p.getUsesLibraryInfos() != null) { ArrayList<SharedLibraryInfo> retValue = new ArrayList<>(); Set<String> collectedNames = new HashSet<>(); - for (SharedLibraryInfo info : p.usesLibraryInfos) { + for (SharedLibraryInfo info : p.getUsesLibraryInfos()) { findSharedLibrariesRecursive(info, retValue, collectedNames); } return retValue; @@ -9529,13 +9535,13 @@ public class PackageManagerService extends IPackageManager.Stub } } - List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package pkg) { + List<AndroidPackage> findSharedNonSystemLibraries(AndroidPackage pkg) { List<SharedLibraryInfo> deps = findSharedLibraries(pkg); if (!deps.isEmpty()) { - ArrayList<PackageParser.Package> retValue = new ArrayList<>(); + ArrayList<AndroidPackage> retValue = new ArrayList<>(); synchronized (mLock) { for (SharedLibraryInfo info : deps) { - PackageParser.Package depPackage = mPackages.get(info.getPackageName()); + AndroidPackage depPackage = mPackages.get(info.getPackageName()); if (depPackage != null) { retValue.add(depPackage); } @@ -9573,9 +9579,9 @@ public class PackageManagerService extends IPackageManager.Stub return versionedLib.get(version); } - private SharedLibraryInfo getLatestSharedLibraVersionLPr(PackageParser.Package pkg) { + private SharedLibraryInfo getLatestSharedLibraVersionLPr(AndroidPackage pkg) { LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get( - pkg.staticSharedLibName); + pkg.getStaticSharedLibName()); if (versionedLib == null) { return null; } @@ -9583,7 +9589,7 @@ public class PackageManagerService extends IPackageManager.Stub final int versionCount = versionedLib.size(); for (int i = 0; i < versionCount; i++) { final long libVersion = versionedLib.keyAt(i); - if (libVersion < pkg.staticSharedLibVersion) { + if (libVersion < pkg.getStaticSharedLibVersion()) { previousLibVersion = Math.max(previousLibVersion, libVersion); } } @@ -9599,7 +9605,7 @@ public class PackageManagerService extends IPackageManager.Stub PackageSetting sharedLibPackage = null; synchronized (mLock) { final SharedLibraryInfo latestSharedLibraVersionLPr = - getLatestSharedLibraVersionLPr(scanResult.pkgSetting.pkg); + getLatestSharedLibraVersionLPr(scanResult.request.parsedPackage); if (latestSharedLibraVersionLPr != null) { sharedLibPackage = mSettings.getPackageLPr( latestSharedLibraVersionLPr.getPackageName()); @@ -9628,7 +9634,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public void dumpProfiles(String packageName) { - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -9639,7 +9645,7 @@ public class PackageManagerService extends IPackageManager.Stub int callingUid = Binder.getCallingUid(); if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID && - callingUid != pkg.applicationInfo.uid) { + callingUid != pkg.getUid()) { throw new SecurityException("dumpProfiles"); } @@ -9654,7 +9660,7 @@ public class PackageManagerService extends IPackageManager.Stub public void forceDexOpt(String packageName) { enforceSystemOrRoot("forceDexOpt"); - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -9681,15 +9687,15 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) { + private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, AndroidPackage newPkg) { if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) { Slog.w(TAG, "Unable to update from " + oldPkg.name - + " to " + newPkg.packageName + + " to " + newPkg.getPackageName() + ": old package not in system partition"); return false; } else if (mPackages.get(oldPkg.name) != null) { Slog.w(TAG, "Unable to update from " + oldPkg.name - + " to " + newPkg.packageName + + " to " + newPkg.getPackageName() + ": old package still exists"); return false; } @@ -9713,122 +9719,86 @@ public class PackageManagerService extends IPackageManager.Stub return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId }; } - private void clearAppDataLIF(PackageParser.Package pkg, int userId, int flags) { + private void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } clearAppDataLeafLIF(pkg, userId, flags); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - clearAppDataLeafLIF(pkg.childPackages.get(i), userId, flags); - } if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) { clearAppProfilesLIF(pkg, UserHandle.USER_ALL); } } - private void clearAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) { + private void clearAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { final PackageSetting ps; synchronized (mLock) { - ps = mSettings.mPackages.get(pkg.packageName); + ps = mSettings.mPackages.get(pkg.getPackageName()); } for (int realUserId : resolveUserIds(userId)) { final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0; try { - mInstaller.clearAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags, - ceDataInode); + mInstaller.clearAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId, + flags, ceDataInode); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } } } - private void destroyAppDataLIF(PackageParser.Package pkg, int userId, int flags) { + private void destroyAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } destroyAppDataLeafLIF(pkg, userId, flags); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - destroyAppDataLeafLIF(pkg.childPackages.get(i), userId, flags); - } } - private void destroyAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) { + private void destroyAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { final PackageSetting ps; synchronized (mLock) { - ps = mSettings.mPackages.get(pkg.packageName); + ps = mSettings.mPackages.get(pkg.getPackageName()); } for (int realUserId : resolveUserIds(userId)) { final long ceDataInode = (ps != null) ? ps.getCeDataInode(realUserId) : 0; try { - mInstaller.destroyAppData(pkg.volumeUuid, pkg.packageName, realUserId, flags, - ceDataInode); + mInstaller.destroyAppData(pkg.getVolumeUuid(), pkg.getPackageName(), realUserId, + flags, ceDataInode); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } - mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId); + mDexManager.notifyPackageDataDestroyed(pkg.getPackageName(), userId); } } - private void destroyAppProfilesLIF(PackageParser.Package pkg) { + private void destroyAppProfilesLIF(AndroidPackage pkg) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } destroyAppProfilesLeafLIF(pkg); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - destroyAppProfilesLeafLIF(pkg.childPackages.get(i)); - } } - private void destroyAppProfilesLeafLIF(PackageParser.Package pkg) { + private void destroyAppProfilesLeafLIF(AndroidPackage pkg) { try { - mInstaller.destroyAppProfiles(pkg.packageName); + mInstaller.destroyAppProfiles(pkg.getPackageName()); } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); } } - private void clearAppProfilesLIF(PackageParser.Package pkg, int userId) { + private void clearAppProfilesLIF(AndroidPackage pkg, int userId) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } mArtManagerService.clearAppProfiles(pkg); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - mArtManagerService.clearAppProfiles(pkg.childPackages.get(i)); - } - } - - private void setInstallAndUpdateTime(PackageParser.Package pkg, long firstInstallTime, - long lastUpdateTime) { - // Set parent install/update time - PackageSetting ps = (PackageSetting) pkg.mExtras; - if (ps != null) { - ps.firstInstallTime = firstInstallTime; - ps.lastUpdateTime = lastUpdateTime; - } - // Set children install/update time - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - ps = (PackageSetting) childPkg.mExtras; - if (ps != null) { - ps.firstInstallTime = firstInstallTime; - ps.lastUpdateTime = lastUpdateTime; - } - } } @GuardedBy("mLock") private void applyDefiningSharedLibraryUpdateLocked( - PackageParser.Package pkg, SharedLibraryInfo libInfo, + AndroidPackage pkg, SharedLibraryInfo libInfo, BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) { // Note that libraries defined by this package may be null if: // - Package manager was unable to create the shared library. The package still @@ -9837,14 +9807,14 @@ public class PackageManagerService extends IPackageManager.Stub // - Package manager is in a state where package isn't scanned yet. This will // get called again after scanning to fix the dependencies. if (pkg.isLibrary()) { - if (pkg.staticSharedLibName != null) { + if (pkg.getStaticSharedLibName() != null) { SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( - pkg.staticSharedLibName, pkg.staticSharedLibVersion); + pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion()); if (definedLibrary != null) { action.accept(definedLibrary, libInfo); } } else { - for (String libraryName : pkg.libraryNames) { + for (String libraryName : pkg.getLibraryNames()) { SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr( libraryName, SharedLibraryInfo.VERSION_UNDEFINED); if (definedLibrary != null) { @@ -9856,19 +9826,19 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles, - SharedLibraryInfo libInfo, PackageParser.Package changingLib) { + private void addSharedLibraryLPr(AndroidPackage pkg, Set<String> usesLibraryFiles, + SharedLibraryInfo libInfo, AndroidPackage changingLib) { if (libInfo.getPath() != null) { usesLibraryFiles.add(libInfo.getPath()); return; } - PackageParser.Package p = mPackages.get(libInfo.getPackageName()); - if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) { + AndroidPackage p = mPackages.get(libInfo.getPackageName()); + if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) { // If we are doing this while in the middle of updating a library apk, // then we need to make sure to use that new apk for determining the // dependencies here. (We haven't yet finished committing the new apk // to the package manager state.) - if (p == null || p.packageName.equals(changingLib.packageName)) { + if (p == null || p.getPackageName().equals(changingLib.getPackageName())) { p = changingLib; } } @@ -9878,23 +9848,23 @@ public class PackageManagerService extends IPackageManager.Stub applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> { definingLibrary.addDependency(dependency); }); - if (p.usesLibraryFiles != null) { - Collections.addAll(usesLibraryFiles, p.usesLibraryFiles); + if (p.getUsesLibraryFiles() != null) { + Collections.addAll(usesLibraryFiles, p.getUsesLibraryFiles()); } } } @GuardedBy("mLock") - private void updateSharedLibrariesLocked(PackageParser.Package pkg, - PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages) + private void updateSharedLibrariesLocked(AndroidPackage pkg, + AndroidPackage changingLib, Map<String, AndroidPackage> availablePackages) throws PackageManagerException { final ArrayList<SharedLibraryInfo> sharedLibraryInfos = collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null); executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos); } - private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(PackageParser.Package pkg, - Map<String, PackageParser.Package> availablePackages, + private static ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(AndroidPackage pkg, + Map<String, AndroidPackage> availablePackages, @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries, @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries) throws PackageManagerException { @@ -9905,44 +9875,45 @@ public class PackageManagerService extends IPackageManager.Stub // that libraries are searched in the correct order) and must have no // duplicates. ArrayList<SharedLibraryInfo> usesLibraryInfos = null; - if (pkg.usesLibraries != null) { - usesLibraryInfos = collectSharedLibraryInfos(pkg.usesLibraries, null, null, - pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, null, + if (pkg.getUsesLibraries() != null) { + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null, + pkg.getPackageName(), true, pkg.getTargetSdkVersion(), null, availablePackages, existingLibraries, newLibraries); } - if (pkg.usesStaticLibraries != null) { - usesLibraryInfos = collectSharedLibraryInfos(pkg.usesStaticLibraries, - pkg.usesStaticLibrariesVersions, pkg.usesStaticLibrariesCertDigests, - pkg.packageName, true, pkg.applicationInfo.targetSdkVersion, usesLibraryInfos, + if (pkg.getUsesStaticLibraries() != null) { + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(), + pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(), + pkg.getPackageName(), true, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } - if (pkg.usesOptionalLibraries != null) { - usesLibraryInfos = collectSharedLibraryInfos(pkg.usesOptionalLibraries, - null, null, pkg.packageName, false, pkg.applicationInfo.targetSdkVersion, + if (pkg.getUsesOptionalLibraries() != null) { + usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(), + null, null, pkg.getPackageName(), false, pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, existingLibraries, newLibraries); } return usesLibraryInfos; } - private void executeSharedLibrariesUpdateLPr(PackageParser.Package pkg, - PackageParser.Package changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) { + private void executeSharedLibrariesUpdateLPr(AndroidPackage pkg, + AndroidPackage changingLib, ArrayList<SharedLibraryInfo> usesLibraryInfos) { // If the package provides libraries, clear their old dependencies. // This method will set them up again. applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> { definingLibrary.clearDependencies(); }); if (usesLibraryInfos != null) { - pkg.usesLibraryInfos = usesLibraryInfos; + pkg.mutate().setUsesLibraryInfos(usesLibraryInfos); // Use LinkedHashSet to preserve the order of files added to // usesLibraryFiles while eliminating duplicates. Set<String> usesLibraryFiles = new LinkedHashSet<>(); for (SharedLibraryInfo libInfo : usesLibraryInfos) { addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib); } - pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]); + pkg.mutate().setUsesLibraryFiles(usesLibraryFiles.toArray( + new String[usesLibraryFiles.size()])); } else { - pkg.usesLibraryInfos = null; - pkg.usesLibraryFiles = null; + pkg.mutate().setUsesLibraryInfos(null) + .setUsesLibraryFiles(null); } } @@ -9952,7 +9923,7 @@ public class PackageManagerService extends IPackageManager.Stub @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests, @NonNull String packageName, boolean required, int targetSdk, @Nullable ArrayList<SharedLibraryInfo> outUsedLibraries, - @NonNull final Map<String, PackageParser.Package> availablePackages, + @NonNull final Map<String, AndroidPackage> availablePackages, @NonNull final Map<String, LongSparseArray<SharedLibraryInfo>> existingLibraries, @Nullable final Map<String, LongSparseArray<SharedLibraryInfo>> newLibraries) throws PackageManagerException { @@ -9981,8 +9952,8 @@ public class PackageManagerService extends IPackageManager.Stub + " library " + libName + " version " + libraryInfo.getLongVersion() + "; failing!"); } - PackageParser.Package libPkg = - availablePackages.get(libraryInfo.getPackageName()); + AndroidPackage pkg = availablePackages.get(libraryInfo.getPackageName()); + SigningDetails libPkg = pkg == null ? null : pkg.getSigningDetails(); if (libPkg == null) { throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires unavailable static shared" @@ -9993,9 +9964,9 @@ public class PackageManagerService extends IPackageManager.Stub // For apps targeting O MR1 we require explicit enumeration of all certs. final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1) ? PackageUtils.computeSignaturesSha256Digests( - libPkg.mSigningDetails.signatures) + libPkg.signatures) : PackageUtils.computeSignaturesSha256Digests( - new Signature[]{libPkg.mSigningDetails.signatures[0]}); + new Signature[]{libPkg.signatures[0]}); // Take a shortcut if sizes don't match. Note that if an app doesn't // target O we don't parse the "additional-certificate" tags similarly @@ -10025,7 +9996,7 @@ public class PackageManagerService extends IPackageManager.Stub // if the new one has been blessed by the old byte[] digestBytes = HexEncoding.decode( expectedCertDigests[0], false /* allowSingleChar */); - if (!libPkg.mSigningDetails.hasSha256Certificate(digestBytes)) { + if (!libPkg.hasSha256Certificate(digestBytes)) { throw new PackageManagerException( INSTALL_FAILED_MISSING_SHARED_LIBRARY, "Package " + packageName + " requires differently signed" + @@ -10057,28 +10028,28 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked( - PackageParser.Package updatedPkg, - Map<String, PackageParser.Package> availablePackages) { - ArrayList<PackageParser.Package> resultList = null; + private ArrayList<AndroidPackage> updateAllSharedLibrariesLocked( + AndroidPackage updatedPkg, + Map<String, AndroidPackage> availablePackages) { + ArrayList<AndroidPackage> resultList = null; // Set of all descendants of a library; used to eliminate cycles ArraySet<String> descendants = null; // The current list of packages that need updating - ArrayList<PackageParser.Package> needsUpdating = null; + ArrayList<AndroidPackage> needsUpdating = null; if (updatedPkg != null) { needsUpdating = new ArrayList<>(1); needsUpdating.add(updatedPkg); } do { - final PackageParser.Package changingPkg = + final AndroidPackage changingPkg = (needsUpdating == null) ? null : needsUpdating.remove(0); for (int i = mPackages.size() - 1; i >= 0; --i) { - final PackageParser.Package pkg = mPackages.valueAt(i); + final AndroidPackage pkg = mPackages.valueAt(i); if (changingPkg != null - && !hasString(pkg.usesLibraries, changingPkg.libraryNames) - && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames) - && !ArrayUtils.contains(pkg.usesStaticLibraries, - changingPkg.staticSharedLibName)) { + && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames()) + && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames()) + && !ArrayUtils.contains(pkg.getUsesStaticLibraries(), + changingPkg.getStaticSharedLibName())) { continue; } if (resultList == null) { @@ -10090,8 +10061,8 @@ public class PackageManagerService extends IPackageManager.Stub if (descendants == null) { descendants = new ArraySet<>(); } - if (!descendants.contains(pkg.packageName)) { - descendants.add(pkg.packageName); + if (!descendants.contains(pkg.getPackageName())) { + descendants.add(pkg.getPackageName()); needsUpdating.add(pkg); } } @@ -10106,8 +10077,9 @@ public class PackageManagerService extends IPackageManager.Stub if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) { final int flags = pkg.isUpdatedSystemApp() ? PackageManager.DELETE_KEEP_DATA : 0; - deletePackageLIF(pkg.packageName, null, true, mUserManager.getUserIds(), - flags , null, true, null); + deletePackageLIF(pkg.getPackageName(), null, true, + mUserManager.getUserIds(), flags, null, + true, null); } Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } @@ -10117,43 +10089,15 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy({"mInstallLock", "mLock"}) - private List<ScanResult> scanPackageTracedLI(PackageParser.Package pkg, + private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); - // If the package has children and this is the first dive in the function - // we recursively scan the package with the SCAN_CHECK_ONLY flag set to see - // whether all packages (parent and children) would be successfully scanned - // before the actual scan since scanning mutates internal state and we want - // to atomically install the package and its children. - if ((scanFlags & SCAN_CHECK_ONLY) == 0) { - if (pkg.childPackages != null && pkg.childPackages.size() > 0) { - scanFlags |= SCAN_CHECK_ONLY; - } - } else { - scanFlags &= ~SCAN_CHECK_ONLY; - } - - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - final List<ScanResult> scanResults = new ArrayList<>(1 + childCount); try { - // Scan the parent - scanResults.add(scanPackageNewLI(pkg, parseFlags, scanFlags, currentTime, user)); - // Scan the children - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - scanResults.add(scanPackageNewLI(childPkg, parseFlags, - scanFlags, currentTime, user)); - } + return scanPackageNewLI(parsedPackage, parseFlags, scanFlags, currentTime, user); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - - if ((scanFlags & SCAN_CHECK_ONLY) != 0) { - return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user); - } - - return scanResults; } /** The result of a package scan. */ @@ -10200,9 +10144,9 @@ public class PackageManagerService extends IPackageManager.Stub @VisibleForTesting static class ScanRequest { /** The parsed package */ - @NonNull public final PackageParser.Package pkg; + @NonNull public final ParsedPackage parsedPackage; /** The package this package replaces */ - @Nullable public final PackageParser.Package oldPkg; + @Nullable public final AndroidPackage oldPkg; /** Shared user settings, if the package has a shared user */ @Nullable public final SharedUserSetting sharedUserSetting; /** @@ -10226,9 +10170,9 @@ public class PackageManagerService extends IPackageManager.Stub /** Whether or not the platform package is being scanned */ public final boolean isPlatformPackage; public ScanRequest( - @NonNull PackageParser.Package pkg, + @NonNull ParsedPackage parsedPackage, @Nullable SharedUserSetting sharedUserSetting, - @Nullable PackageParser.Package oldPkg, + @Nullable AndroidPackage oldPkg, @Nullable PackageSetting pkgSetting, @Nullable PackageSetting disabledPkgSetting, @Nullable PackageSetting originalPkgSetting, @@ -10237,7 +10181,7 @@ public class PackageManagerService extends IPackageManager.Stub @ScanFlags int scanFlags, boolean isPlatformPackage, @Nullable UserHandle user) { - this.pkg = pkg; + this.parsedPackage = parsedPackage; this.oldPkg = oldPkg; this.pkgSetting = pkgSetting; this.sharedUserSetting = sharedUserSetting; @@ -10270,7 +10214,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags, PackageSetting pkgSetting, PackageSetting disabledPkgSetting, UserHandle user, - PackageParser.Package pkg) { + AndroidPackage pkg) { // TODO(patb): Do away entirely with disabledPkgSetting here. PkgSetting will always contain // the correct isSystem value now that we don't disable system packages before scan. @@ -10322,12 +10266,14 @@ public class PackageManagerService extends IPackageManager.Stub && SystemProperties.getInt("ro.vndk.version", 28) < 28; if (((scanFlags & SCAN_AS_PRIVILEGED) == 0) && !pkg.isPrivileged() - && (pkg.mSharedUserId != null) + && (pkg.getSharedUserId() != null) && !skipVendorPrivilegeScan) { SharedUserSetting sharedUserSetting = null; try { - sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false); - } catch (PackageManagerException ignore) {} + sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), 0, + 0, false); + } catch (PackageManagerException ignore) { + } if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. // TODO(b/72378145) Fix this exemption. Force signature apps @@ -10336,7 +10282,8 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); if ((compareSignatures(platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) != PackageManager.SIGNATURE_MATCH)) { + pkg.getSigningDetails().signatures) + != PackageManager.SIGNATURE_MATCH)) { scanFlags |= SCAN_AS_PRIVILEGED; } } @@ -10351,46 +10298,50 @@ public class PackageManagerService extends IPackageManager.Stub // method. Also, we need to solve the problem of potentially creating a new shared user // setting. That can probably be done later and patch things up after the fact. @GuardedBy({"mInstallLock", "mLock"}) - private ScanResult scanPackageNewLI(@NonNull PackageParser.Package pkg, + private ScanResult scanPackageNewLI(@NonNull ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @Nullable UserHandle user) throws PackageManagerException { - final String renamedPkgName = mSettings.getRenamedPackageLPr(pkg.mRealPackage); - final String realPkgName = getRealPackageName(pkg, renamedPkgName); + final String renamedPkgName = mSettings.getRenamedPackageLPr( + parsedPackage.getRealPackage()); + final String realPkgName = getRealPackageName(parsedPackage, renamedPkgName); if (realPkgName != null) { - ensurePackageRenamed(pkg, renamedPkgName); + ensurePackageRenamed(parsedPackage, renamedPkgName); } - final PackageSetting originalPkgSetting = getOriginalPackageLocked(pkg, renamedPkgName); - final PackageSetting pkgSetting = mSettings.getPackageLPr(pkg.packageName); + final PackageSetting originalPkgSetting = getOriginalPackageLocked(parsedPackage, + renamedPkgName); + final PackageSetting pkgSetting = mSettings.getPackageLPr(parsedPackage.getPackageName()); final PackageSetting disabledPkgSetting = - mSettings.getDisabledSystemPkgLPr(pkg.packageName); + mSettings.getDisabledSystemPkgLPr(parsedPackage.getPackageName()); - if (mTransferedPackages.contains(pkg.packageName)) { - Slog.w(TAG, "Package " + pkg.packageName + if (mTransferedPackages.contains(parsedPackage.getPackageName())) { + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " was transferred to another, but its .apk remains"); } - scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, pkg); + scanFlags = adjustScanFlags(scanFlags, pkgSetting, disabledPkgSetting, user, parsedPackage); synchronized (mLock) { - applyPolicy(pkg, parseFlags, scanFlags, mPlatformPackage); - assertPackageIsValid(pkg, parseFlags, scanFlags); + applyPolicy(parsedPackage, parseFlags, scanFlags, mPlatformPackage); + assertPackageIsValid(parsedPackage, parseFlags, scanFlags); SharedUserSetting sharedUserSetting = null; - if (pkg.mSharedUserId != null) { + if (parsedPackage.getSharedUserId() != null) { // SIDE EFFECTS; may potentially allocate a new shared user - sharedUserSetting = mSettings.getSharedUserLPw( - pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/); + sharedUserSetting = mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(), + 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/); if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) - Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId() + " (uid=" + sharedUserSetting.userId + "):" + " packages=" + sharedUserSetting.packages); } } - final ScanRequest request = new ScanRequest(pkg, sharedUserSetting, + String platformPackageName = mPlatformPackage == null + ? null : mPlatformPackage.getPackageName(); + final ScanRequest request = new ScanRequest(parsedPackage, sharedUserSetting, pkgSetting == null ? null : pkgSetting.pkg, pkgSetting, disabledPkgSetting, originalPkgSetting, realPkgName, parseFlags, scanFlags, - (pkg == mPlatformPackage), user); + Objects.equals(parsedPackage.getPackageName(), platformPackageName), user); return scanPackageOnlyLI(request, mInjector, mFactoryTest, currentTime); } } @@ -10433,11 +10384,18 @@ public class PackageManagerService extends IPackageManager.Stub * possible and the system is not left in an inconsistent state. */ @GuardedBy({"mLock", "mInstallLock"}) - private void commitReconciledScanResultLocked(@NonNull ReconciledPackage reconciledPkg) { + private AndroidPackage commitReconciledScanResultLocked( + @NonNull ReconciledPackage reconciledPkg) { final ScanResult result = reconciledPkg.scanResult; final ScanRequest request = result.request; - final PackageParser.Package pkg = request.pkg; - final PackageParser.Package oldPkg = request.oldPkg; + // TODO(b/135203078): Move this even further away + ParsedPackage parsedPackage = request.parsedPackage; + if ("android".equals(parsedPackage.getPackageName())) { + // TODO(b/135203078): Move this to initial parse + parsedPackage.setVersionCode(mSdkVersion) + .setVersionCodeMajor(0); + } + final AndroidPackage oldPkg = request.oldPkg; final @ParseFlags int parseFlags = request.parseFlags; final @ScanFlags int scanFlags = request.scanFlags; final PackageSetting oldPkgSetting = request.oldPkgSetting; @@ -10454,13 +10412,11 @@ public class PackageManagerService extends IPackageManager.Stub if (result.existingSettingCopied) { pkgSetting = request.pkgSetting; pkgSetting.updateFrom(result.pkgSetting); - pkg.mExtras = pkgSetting; } else { pkgSetting = result.pkgSetting; if (originalPkgSetting != null) { - mSettings.addRenamedPackageLPw(pkg.packageName, originalPkgSetting.name); - } - if (originalPkgSetting != null && (scanFlags & SCAN_CHECK_ONLY) == 0) { + mSettings.addRenamedPackageLPw(parsedPackage.getPackageName(), + originalPkgSetting.name); mTransferedPackages.add(originalPkgSetting.name); } } @@ -10473,12 +10429,13 @@ public class PackageManagerService extends IPackageManager.Stub // We need to have this here because addUserToSettingLPw() is sometimes responsible // for creating the application ID. If we did this earlier, we would be saving the // correct ID. - pkg.applicationInfo.uid = pkgSetting.appId; + parsedPackage.setUid(pkgSetting.appId); + final AndroidPackage pkg = parsedPackage.hideAsFinal(); mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting); - if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realPkgName != null) { - mTransferedPackages.add(pkg.packageName); + if (realPkgName != null) { + mTransferedPackages.add(pkg.getPackageName()); } if (reconciledPkg.collectedSharedLibraryInfos != null) { @@ -10487,7 +10444,7 @@ public class PackageManagerService extends IPackageManager.Stub final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (reconciledPkg.removeAppKeySetData) { - ksms.removeAppKeySetDataLPw(pkg.packageName); + ksms.removeAppKeySetDataLPw(pkg.getPackageName()); } if (reconciledPkg.sharedUserSignaturesChanged) { pkgSetting.sharedUser.signaturesChanged = Boolean.TRUE; @@ -10495,17 +10452,17 @@ public class PackageManagerService extends IPackageManager.Stub } pkgSetting.signatures.mSigningDetails = reconciledPkg.signingDetails; - if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) { + if (pkg.getAdoptPermissions() != null) { // This package wants to adopt ownership of permissions from // another package. - for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) { - final String origName = pkg.mAdoptPermissions.get(i); + for (int i = pkg.getAdoptPermissions().size() - 1; i >= 0; i--) { + final String origName = pkg.getAdoptPermissions().get(i); final PackageSetting orig = mSettings.getPackageLPr(origName); if (orig != null) { if (verifyPackageUpdateLPr(orig, pkg)) { Slog.i(TAG, "Adopting permissions from " + origName + " to " - + pkg.packageName); - mSettings.mPermissions.transferPermissions(origName, pkg.packageName); + + pkg.getPackageName()); + mSettings.mPermissions.transferPermissions(origName, pkg.getPackageName()); } } } @@ -10522,21 +10479,15 @@ public class PackageManagerService extends IPackageManager.Stub } } - if ((scanFlags & SCAN_CHECK_ONLY) != 0) { - if (oldPkgSetting != null) { - synchronized (mLock) { - mSettings.mPackages.put(oldPkgSetting.name, oldPkgSetting); - } - } - } else { - final int userId = user == null ? 0 : user.getIdentifier(); - // Modify state for the given package setting - commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags, - (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg); - if (pkgSetting.getInstantApp(userId)) { - mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId); - } + final int userId = user == null ? 0 : user.getIdentifier(); + // Modify state for the given package setting + commitPackageSettings(pkg, oldPkg, pkgSetting, scanFlags, + (parseFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/, reconciledPkg); + if (pkgSetting.getInstantApp(userId)) { + mInstantAppRegistry.addInstantAppLPw(userId, pkgSetting.appId); } + + return pkg; } /** @@ -10544,18 +10495,19 @@ public class PackageManagerService extends IPackageManager.Stub * <p>This may differ from the package's actual name if the application has already * been installed under one of this package's original names. */ - private static @Nullable String getRealPackageName(@NonNull PackageParser.Package pkg, + private static @Nullable String getRealPackageName(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { if (isPackageRenamed(pkg, renamedPkgName)) { - return pkg.mRealPackage; + return pkg.getRealPackage(); } return null; } /** Returns {@code true} if the package has been renamed. Otherwise, {@code false}. */ - private static boolean isPackageRenamed(@NonNull PackageParser.Package pkg, + private static boolean isPackageRenamed(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { - return pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(renamedPkgName); + return pkg.getOriginalPackages() != null + && pkg.getOriginalPackages().contains(renamedPkgName); } /** @@ -10566,14 +10518,14 @@ public class PackageManagerService extends IPackageManager.Stub * shared user [if any]. */ @GuardedBy("mLock") - private @Nullable PackageSetting getOriginalPackageLocked(@NonNull PackageParser.Package pkg, + private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg, @Nullable String renamedPkgName) { if (!isPackageRenamed(pkg, renamedPkgName)) { return null; } - for (int i = pkg.mOriginalPackages.size() - 1; i >= 0; --i) { + for (int i = ArrayUtils.size(pkg.getOriginalPackages()) - 1; i >= 0; --i) { final PackageSetting originalPs = - mSettings.getPackageLPr(pkg.mOriginalPackages.get(i)); + mSettings.getPackageLPr(pkg.getOriginalPackages().get(i)); if (originalPs != null) { // the package is already installed under its original name... // but, should we use it? @@ -10581,18 +10533,18 @@ public class PackageManagerService extends IPackageManager.Stub // the new package is incompatible with the original continue; } else if (originalPs.sharedUser != null) { - if (!originalPs.sharedUser.name.equals(pkg.mSharedUserId)) { + if (!originalPs.sharedUser.name.equals(pkg.getSharedUserId())) { // the shared user id is incompatible with the original Slog.w(TAG, "Unable to migrate data from " + originalPs.name - + " to " + pkg.packageName + ": old uid " + + " to " + pkg.getPackageName() + ": old uid " + originalPs.sharedUser.name - + " differs from " + pkg.mSharedUserId); + + " differs from " + pkg.getSharedUserId()); continue; } // TODO: Add case when shared user id is added [b/28144775] } else { if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package " - + pkg.packageName + " to old name " + originalPs.name); + + pkg.getPackageName() + " to old name " + originalPs.name); } return originalPs; } @@ -10605,19 +10557,19 @@ public class PackageManagerService extends IPackageManager.Stub * <p>When we've already installed the package under an original name, update * the new package so we can continue to have the old name. */ - private static void ensurePackageRenamed(@NonNull PackageParser.Package pkg, + private static void ensurePackageRenamed(@NonNull ParsedPackage parsedPackage, @NonNull String renamedPackageName) { - if (pkg.mOriginalPackages == null - || !pkg.mOriginalPackages.contains(renamedPackageName) - || pkg.packageName.equals(renamedPackageName)) { + if (parsedPackage.getOriginalPackages() == null + || !parsedPackage.getOriginalPackages().contains(renamedPackageName) + || parsedPackage.getPackageName().equals(renamedPackageName)) { return; } - pkg.setPackageName(renamedPackageName); + parsedPackage.setPackageName(renamedPackageName); } /** * Applies the adjusted ABI calculated by - * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all + * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, AndroidPackage)} to all * relevant packages and settings. * @param sharedUserSetting The {@code SharedUserSetting} to adjust * @param scannedPackage the package being scanned or null @@ -10625,22 +10577,20 @@ public class PackageManagerService extends IPackageManager.Stub * @return the list of code paths that belong to packages that had their ABIs adjusted. */ private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting, - PackageParser.Package scannedPackage, String adjustedAbi) { + ParsedPackage scannedPackage, String adjustedAbi) { if (scannedPackage != null) { - scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi; + scannedPackage.setPrimaryCpuAbi(adjustedAbi); } List<String> changedAbiCodePath = null; for (PackageSetting ps : sharedUserSetting.packages) { - if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) { + if (scannedPackage == null || !scannedPackage.getPackageName().equals(ps.name)) { if (ps.primaryCpuAbiString != null) { continue; } ps.primaryCpuAbiString = adjustedAbi; - if (ps.pkg != null && ps.pkg.applicationInfo != null - && !TextUtils.equals( - adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) { - ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi; + if (ps.pkg != null && !TextUtils.equals(adjustedAbi, ps.pkg.getPrimaryCpuAbi())) { + ps.pkg.mutate().setPrimaryCpuAbi(adjustedAbi); if (DEBUG_ABI_SELECTION) { Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi @@ -10680,7 +10630,7 @@ public class PackageManagerService extends IPackageManager.Stub throws PackageManagerException { final PackageAbiHelper packageAbiHelper = injector.getAbiHelper(); final UserManagerInternal userManager = injector.getUserManagerInternal(); - final PackageParser.Package pkg = request.pkg; + ParsedPackage parsedPackage = request.parsedPackage; PackageSetting pkgSetting = request.pkgSetting; final PackageSetting disabledPkgSetting = request.disabledPkgSetting; final PackageSetting originalPkgSetting = request.originalPkgSetting; @@ -10695,13 +10645,12 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_PACKAGE_SCANNING) { if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) - Log.d(TAG, "Scanning package " + pkg.packageName); + Log.d(TAG, "Scanning package " + parsedPackage.getPackageName()); } // Initialize package source and resource directories - final File scanFile = new File(pkg.codePath); - final File destCodeFile = new File(pkg.applicationInfo.getCodePath()); - final File destResourceFile = new File(pkg.applicationInfo.getResourcePath()); + final File destCodeFile = new File(parsedPackage.getAppInfoCodePath()); + final File destResourceFile = new File(parsedPackage.getAppInfoResourcePath()); // We keep references to the derived CPU Abis from settings in oder to reuse // them in the case where we're not upgrading or booting for the first time. @@ -10720,7 +10669,7 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgSetting != null && pkgSetting.sharedUser != sharedUserSetting) { PackageManagerService.reportSettingsProblem(Log.WARN, - "Package " + pkg.packageName + " shared user changed from " + "Package " + parsedPackage.getPackageName() + " shared user changed from " + (pkgSetting.sharedUser != null ? pkgSetting.sharedUser.name : "<nothing>") + " to " @@ -10730,30 +10679,28 @@ public class PackageManagerService extends IPackageManager.Stub } String[] usesStaticLibraries = null; - if (pkg.usesStaticLibraries != null) { - usesStaticLibraries = new String[pkg.usesStaticLibraries.size()]; - pkg.usesStaticLibraries.toArray(usesStaticLibraries); + if (parsedPackage.getUsesStaticLibraries() != null) { + usesStaticLibraries = new String[parsedPackage.getUsesStaticLibraries().size()]; + parsedPackage.getUsesStaticLibraries().toArray(usesStaticLibraries); } final boolean createNewPackage = (pkgSetting == null); if (createNewPackage) { - final String parentPackageName = (pkg.parentPackage != null) - ? pkg.parentPackage.packageName : null; final boolean instantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; final boolean virtualPreload = (scanFlags & SCAN_AS_VIRTUAL_PRELOAD) != 0; // REMOVE SharedUserSetting from method; update in a separate call - pkgSetting = Settings.createNewSetting(pkg.packageName, originalPkgSetting, - disabledPkgSetting, realPkgName, sharedUserSetting, destCodeFile, - destResourceFile, pkg.applicationInfo.nativeLibraryRootDir, - pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi, - pkg.mVersionCode, pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, - user, true /*allowInstall*/, instantApp, virtualPreload, - parentPackageName, pkg.getChildPackageNames(), - UserManagerService.getInstance(), usesStaticLibraries, - pkg.usesStaticLibrariesVersions); + pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(), + originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting, + destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(), + parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(), + parsedPackage.getVersionCode(), parsedPackage.getFlags(), + parsedPackage.getPrivateFlags(), user, true /*allowInstall*/, instantApp, + virtualPreload, UserManagerService.getInstance(), usesStaticLibraries, + parsedPackage.getUsesStaticLibrariesVersions()); } else { // make a deep copy to avoid modifying any existing system state. pkgSetting = new PackageSetting(pkgSetting); - pkgSetting.pkg = pkg; + // TODO(b/135203078): Remove entirely. Set package directly. + parsedPackage.setPackageSettingCallback(pkgSetting); // REMOVE SharedUserSetting from method; update in a separate call. // @@ -10761,18 +10708,18 @@ public class PackageManagerService extends IPackageManager.Stub // secondaryCpuAbi are not known at this point so we always update them // to null here, only to reset them at a later point. Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting, - destCodeFile, destResourceFile, pkg.applicationInfo.nativeLibraryDir, - pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi, - pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, - pkg.getChildPackageNames(), UserManagerService.getInstance(), - usesStaticLibraries, pkg.usesStaticLibrariesVersions); + destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(), + parsedPackage.getPrimaryCpuAbi(), parsedPackage.getSecondaryCpuAbi(), + parsedPackage.getFlags(), parsedPackage.getPrivateFlags(), + UserManagerService.getInstance(), + usesStaticLibraries, parsedPackage.getUsesStaticLibrariesVersions()); } if (createNewPackage && originalPkgSetting != null) { // This is the initial transition from the original package, so, // fix up the new package's name now. We must do this after looking // up the package under its new name, so getPackageLP takes care of // fiddling things correctly. - pkg.setPackageName(originalPkgSetting.name); + parsedPackage.setPackageName(originalPkgSetting.name); // File a report about this. String msg = "New package " + pkgSetting.realName @@ -10791,7 +10738,7 @@ public class PackageManagerService extends IPackageManager.Stub if (disabledPkgSetting != null || (0 != (scanFlags & SCAN_NEW_INSTALL) && pkgSetting != null && pkgSetting.isSystem())) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + parsedPackage.mutate().setUpdatedSystemApp(true); } // Apps which share a sharedUserId must be placed in the same selinux domain. If this @@ -10803,68 +10750,72 @@ public class PackageManagerService extends IPackageManager.Stub // will NOT be modified until next boot, even if a lower targetSdkVersion is used. This // ensures that all packages continue to run in the same selinux domain. final int targetSdkVersion = - ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ? - sharedUserSetting.seInfoTargetSdkVersion : pkg.applicationInfo.targetSdkVersion; + ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) ? + sharedUserSetting.seInfoTargetSdkVersion + : parsedPackage.getTargetSdkVersion(); // TODO(b/71593002): isPrivileged for sharedUser and appInfo should never be out of sync. // They currently can be if the sharedUser apps are signed with the platform key. final boolean isPrivileged = (sharedUserSetting != null) ? - sharedUserSetting.isPrivileged() | pkg.isPrivileged() : pkg.isPrivileged(); - - pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged, - targetSdkVersion); - pkg.applicationInfo.seInfoUser = SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( - userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId)); - - pkg.mExtras = pkgSetting; - pkg.applicationInfo.processName = fixProcessName( - pkg.applicationInfo.packageName, - pkg.applicationInfo.processName); + sharedUserSetting.isPrivileged() | parsedPackage.isPrivileged() + : parsedPackage.isPrivileged(); + + parsedPackage.setSeInfo( + SELinuxMMAC.getSeInfo(parsedPackage, isPrivileged, targetSdkVersion)) + .setSeInfoUser( + SELinuxUtil.assignSeinfoUser(pkgSetting.readUserState( + userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId))) + .setProcessName(fixProcessName( + parsedPackage.getPackageName(), + parsedPackage.getProcessName())); if (!isPlatformPackage) { // Get all of our default paths setup - pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM); + parsedPackage.initForUser(UserHandle.USER_SYSTEM); } - final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting); + final String cpuAbiOverride = deriveAbiOverride(parsedPackage.getCpuAbiOverride(), + pkgSetting); if ((scanFlags & SCAN_NEW_INSTALL) == 0) { if (needToDeriveAbi) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi"); - final boolean extractNativeLibs = !pkg.isLibrary(); + final boolean extractNativeLibs = !parsedPackage.isLibrary(); final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi = - packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs); - derivedAbi.first.applyTo(pkg); - derivedAbi.second.applyTo(pkg); + packageAbiHelper.derivePackageAbi(parsedPackage, cpuAbiOverride, + extractNativeLibs); + derivedAbi.first.applyTo(parsedPackage); + derivedAbi.second.applyTo(parsedPackage); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // Some system apps still use directory structure for native libraries // in which case we might end up not detecting abi solely based on apk // structure. Try to detect abi based on directory structure. - if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() && - pkg.applicationInfo.primaryCpuAbi == null) { + if (isSystemApp(parsedPackage) && !parsedPackage.isUpdatedSystemApp() && + parsedPackage.getPrimaryCpuAbi() == null) { final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis( - pkg); - abis.applyTo(pkg); + parsedPackage); + abis.applyTo(parsedPackage); abis.applyTo(pkgSetting); final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir); - nativeLibraryPaths.applyTo(pkg); + packageAbiHelper.getNativeLibraryPaths(parsedPackage, + sAppLib32InstallDir); + nativeLibraryPaths.applyTo(parsedPackage); } } else { // This is not a first boot or an upgrade, don't bother deriving the // ABI during the scan. Instead, trust the value that was stored in the // package setting. - pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings; - pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings; + parsedPackage.setPrimaryCpuAbi(primaryCpuAbiFromSettings) + .setSecondaryCpuAbi(secondaryCpuAbiFromSettings); final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir); - nativeLibraryPaths.applyTo(pkg); + packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir); + nativeLibraryPaths.applyTo(parsedPackage); if (DEBUG_ABI_SELECTION) { Slog.i(TAG, "Using ABIS and native lib paths from settings : " + - pkg.packageName + " " + pkg.applicationInfo.primaryCpuAbi + ", " + - pkg.applicationInfo.secondaryCpuAbi); + parsedPackage.getPackageName() + " " + parsedPackage.getPrimaryCpuAbi() + + ", " + parsedPackage.getSecondaryCpuAbi()); } } } else { @@ -10872,8 +10823,8 @@ public class PackageManagerService extends IPackageManager.Stub // We haven't run dex-opt for this move (since we've moved the compiled output too) // but we already have this packages package info in the PackageSetting. We just // use that and derive the native library path based on the new codepath. - pkg.applicationInfo.primaryCpuAbi = pkgSetting.primaryCpuAbiString; - pkg.applicationInfo.secondaryCpuAbi = pkgSetting.secondaryCpuAbiString; + parsedPackage.setPrimaryCpuAbi(pkgSetting.primaryCpuAbiString) + .setSecondaryCpuAbi(pkgSetting.secondaryCpuAbiString); } // Set native library paths again. For moves, the path will be updated based on the @@ -10881,8 +10832,8 @@ public class PackageManagerService extends IPackageManager.Stub // ABIs we determined during compilation, but the path will depend on the final // package path (after the rename away from the stage path). final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths = - packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir); - nativeLibraryPaths.applyTo(pkg); + packageAbiHelper.getNativeLibraryPaths(parsedPackage, sAppLib32InstallDir); + nativeLibraryPaths.applyTo(parsedPackage); } // This is a special case for the "system" package, where the ABI is @@ -10890,8 +10841,8 @@ public class PackageManagerService extends IPackageManager.Stub // of this ABI so that we can deal with "normal" applications that run under // the same UID correctly. if (isPlatformPackage) { - pkg.applicationInfo.primaryCpuAbi = VMRuntime.getRuntime().is64Bit() ? - Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]; + parsedPackage.setPrimaryCpuAbi(VMRuntime.getRuntime().is64Bit() ? + Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]); } // If there's a mismatch between the abi-override in the package setting @@ -10899,34 +10850,34 @@ public class PackageManagerService extends IPackageManager.Stub // would've already compiled the app without taking the package setting into // account. if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) { - if (cpuAbiOverride == null && pkg.packageName != null) { + if (cpuAbiOverride == null && parsedPackage.getPackageName() != null) { Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride + - " for package " + pkg.packageName); + " for package " + parsedPackage.getPackageName()); } } - pkgSetting.primaryCpuAbiString = pkg.applicationInfo.primaryCpuAbi; - pkgSetting.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi; + pkgSetting.primaryCpuAbiString = parsedPackage.getPrimaryCpuAbi(); + pkgSetting.secondaryCpuAbiString = parsedPackage.getSecondaryCpuAbi(); pkgSetting.cpuAbiOverrideString = cpuAbiOverride; // Copy the derived override back to the parsed package, so that we can // update the package settings accordingly. - pkg.cpuAbiOverride = cpuAbiOverride; + parsedPackage.setCpuAbiOverride(cpuAbiOverride); if (DEBUG_ABI_SELECTION) { - Slog.d(TAG, "Resolved nativeLibraryRoot for " + pkg.packageName - + " to root=" + pkg.applicationInfo.nativeLibraryRootDir + ", isa=" - + pkg.applicationInfo.nativeLibraryRootRequiresIsa); + Slog.d(TAG, "Resolved nativeLibraryRoot for " + parsedPackage.getPackageName() + + " to root=" + parsedPackage.getNativeLibraryRootDir() + ", isa=" + + parsedPackage.isNativeLibraryRootRequiresIsa()); } // Push the derived path down into PackageSettings so we know what to // clean up at uninstall time. - pkgSetting.legacyNativeLibraryPathString = pkg.applicationInfo.nativeLibraryRootDir; + pkgSetting.legacyNativeLibraryPathString = parsedPackage.getNativeLibraryRootDir(); if (DEBUG_ABI_SELECTION) { - Log.d(TAG, "Abis for package[" + pkg.packageName + "] are" + - " primary=" + pkg.applicationInfo.primaryCpuAbi + - " secondary=" + pkg.applicationInfo.secondaryCpuAbi); + Log.d(TAG, "Abis for package[" + parsedPackage.getPackageName() + "] are" + + " primary=" + parsedPackage.getPrimaryCpuAbi() + + " secondary=" + parsedPackage.getSecondaryCpuAbi()); } if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) { @@ -10936,22 +10887,20 @@ public class PackageManagerService extends IPackageManager.Stub // We also do this *before* we perform dexopt on this package, so that // we can avoid redundant dexopts, and also to make sure we've got the // code and package path correct. - changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg, + changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, parsedPackage, packageAbiHelper.getAdjustedAbiForSharedUser( - pkgSetting.sharedUser.packages, pkg)); + pkgSetting.sharedUser.packages, parsedPackage)); } - if (isUnderFactoryTest && pkg.requestedPermissions.contains( - android.Manifest.permission.FACTORY_TEST)) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST; - } + parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions() + .contains(android.Manifest.permission.FACTORY_TEST)); - if (isSystemApp(pkg)) { + if (isSystemApp(parsedPackage)) { pkgSetting.isOrphaned = true; } // Take care of first install / last update times. - final long scanFileTime = getLastModifiedTime(pkg); + final long scanFileTime = getLastModifiedTime(parsedPackage); if (currentTime != 0) { if (pkgSetting.firstInstallTime == 0) { pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime; @@ -10969,32 +10918,33 @@ public class PackageManagerService extends IPackageManager.Stub } } pkgSetting.setTimeStamp(scanFileTime); - - pkgSetting.pkg = pkg; - pkgSetting.pkgFlags = pkg.applicationInfo.flags; - if (pkg.getLongVersionCode() != pkgSetting.versionCode) { - pkgSetting.versionCode = pkg.getLongVersionCode(); + // TODO(b/135203078): Remove, move to constructor + parsedPackage.setPackageSettingCallback(pkgSetting); + pkgSetting.pkgFlags = parsedPackage.getFlags(); + if (parsedPackage.getLongVersionCode() != pkgSetting.versionCode) { + pkgSetting.versionCode = parsedPackage.getLongVersionCode(); } // Update volume if needed - final String volumeUuid = pkg.applicationInfo.volumeUuid; + final String volumeUuid = parsedPackage.getApplicationInfoVolumeUuid(); if (!Objects.equals(volumeUuid, pkgSetting.volumeUuid)) { Slog.i(PackageManagerService.TAG, "Update" + (pkgSetting.isSystem() ? " system" : "") - + " package " + pkg.packageName + + " package " + parsedPackage.getPackageName() + " volume from " + pkgSetting.volumeUuid + " to " + volumeUuid); pkgSetting.volumeUuid = volumeUuid; } SharedLibraryInfo staticSharedLibraryInfo = null; - if (!TextUtils.isEmpty(pkg.staticSharedLibName)) { - staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(pkg); + if (!TextUtils.isEmpty(parsedPackage.getStaticSharedLibName())) { + staticSharedLibraryInfo = SharedLibraryInfo.createForStatic(parsedPackage); } List<SharedLibraryInfo> dynamicSharedLibraryInfos = null; - if (!ArrayUtils.isEmpty(pkg.libraryNames)) { - dynamicSharedLibraryInfos = new ArrayList<>(pkg.libraryNames.size()); - for (String name : pkg.libraryNames) { - dynamicSharedLibraryInfos.add(SharedLibraryInfo.createForDynamic(pkg, name)); + if (!ArrayUtils.isEmpty(parsedPackage.getLibraryNames())) { + dynamicSharedLibraryInfos = new ArrayList<>(parsedPackage.getLibraryNames().size()); + for (String name : parsedPackage.getLibraryNames()) { + dynamicSharedLibraryInfos.add( + SharedLibraryInfo.createForDynamic(parsedPackage, name)); } } @@ -11030,22 +10980,21 @@ public class PackageManagerService extends IPackageManager.Stub * * @throws PackageManagerException If bytecode could not be found when it should exist */ - private static void assertCodePolicy(PackageParser.Package pkg) + private static void assertCodePolicy(AndroidPackage pkg) throws PackageManagerException { - final boolean shouldHaveCode = - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0; - if (shouldHaveCode && !apkHasCode(pkg.baseCodePath)) { + final boolean shouldHaveCode = (pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0; + if (shouldHaveCode && !apkHasCode(pkg.getBaseCodePath())) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, - "Package " + pkg.baseCodePath + " code is missing"); + "Package " + pkg.getBaseCodePath() + " code is missing"); } - if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { - for (int i = 0; i < pkg.splitCodePaths.length; i++) { + if (!ArrayUtils.isEmpty(pkg.getSplitCodePaths())) { + for (int i = 0; i < pkg.getSplitCodePaths().length; i++) { final boolean splitShouldHaveCode = - (pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0; - if (splitShouldHaveCode && !apkHasCode(pkg.splitCodePaths[i])) { + (pkg.getSplitFlags()[i] & ApplicationInfo.FLAG_HAS_CODE) != 0; + if (splitShouldHaveCode && !apkHasCode(pkg.getSplitCodePaths()[i])) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, - "Package " + pkg.splitCodePaths[i] + " code is missing"); + "Package " + pkg.getSplitCodePaths()[i] + " code is missing"); } } } @@ -11058,118 +11007,59 @@ public class PackageManagerService extends IPackageManager.Stub * Implementation detail: This method must NOT have any side effect. It would * ideally be static, but, it requires locks to read system state. */ - private static void applyPolicy(PackageParser.Package pkg, final @ParseFlags int parseFlags, - final @ScanFlags int scanFlags, PackageParser.Package platformPkg) { + private static void applyPolicy(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, + final @ScanFlags int scanFlags, AndroidPackage platformPkg) { if ((scanFlags & SCAN_AS_SYSTEM) != 0) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; - if (pkg.applicationInfo.isDirectBootAware()) { - // we're direct boot aware; set for all components - for (PackageParser.Service s : pkg.services) { - s.info.directBootAware = true; - } - for (PackageParser.Provider p : pkg.providers) { - p.info.directBootAware = true; - } - for (PackageParser.Activity a : pkg.activities) { - a.info.directBootAware = true; - } - for (PackageParser.Activity r : pkg.receivers) { - r.info.directBootAware = true; - } + parsedPackage.setSystem(true); + // TODO(b/135203078): Can this be done in PackageParser? Or just inferred when the flag + // is set during parse. + if (parsedPackage.isDirectBootAware()) { + parsedPackage.setAllComponentsDirectBootAware(true); } - if (compressedFileExists(pkg.codePath)) { - pkg.isStub = true; + if (compressedFileExists(parsedPackage.getCodePath())) { + parsedPackage.setIsStub(true); } } else { - // non system apps can't be flagged as core - pkg.coreApp = false; - // clear flags not applicable to regular apps - pkg.applicationInfo.flags &= - ~ApplicationInfo.FLAG_PERSISTENT; - pkg.applicationInfo.privateFlags &= - ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; - pkg.applicationInfo.privateFlags &= - ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; - // cap permission priorities - if (pkg.permissionGroups != null && pkg.permissionGroups.size() > 0) { - for (int i = pkg.permissionGroups.size() - 1; i >= 0; --i) { - pkg.permissionGroups.get(i).info.priority = 0; - } - } + parsedPackage + // non system apps can't be flagged as core + .setCoreApp(false) + // clear flags not applicable to regular apps + .setPersistent(false) + .setDefaultToDeviceProtectedStorage(false) + .setDirectBootAware(false) + // non system apps can't have permission priority + .capPermissionPriorities(); } if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) { - // clear protected broadcasts - pkg.protectedBroadcasts = null; - // ignore export request for single user receivers - if (pkg.receivers != null) { - for (int i = pkg.receivers.size() - 1; i >= 0; --i) { - final PackageParser.Activity receiver = pkg.receivers.get(i); - if ((receiver.info.flags & ActivityInfo.FLAG_SINGLE_USER) != 0) { - receiver.info.exported = false; - } - } - } - // ignore export request for single user services - if (pkg.services != null) { - for (int i = pkg.services.size() - 1; i >= 0; --i) { - final PackageParser.Service service = pkg.services.get(i); - if ((service.info.flags & ServiceInfo.FLAG_SINGLE_USER) != 0) { - service.info.exported = false; - } - } - } - // ignore export request for single user providers - if (pkg.providers != null) { - for (int i = pkg.providers.size() - 1; i >= 0; --i) { - final PackageParser.Provider provider = pkg.providers.get(i); - if ((provider.info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0) { - provider.info.exported = false; - } - } - } + parsedPackage + .clearProtectedBroadcasts() + .markNotActivitiesAsNotExportedIfSingleUser(); } - if ((scanFlags & SCAN_AS_PRIVILEGED) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; - } - - if ((scanFlags & SCAN_AS_OEM) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_OEM; - } - - if ((scanFlags & SCAN_AS_VENDOR) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR; - } - - if ((scanFlags & SCAN_AS_PRODUCT) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT; - } - - if ((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT; - } - - if ((scanFlags & SCAN_AS_ODM) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM; - } + parsedPackage.setPrivileged((scanFlags & SCAN_AS_PRIVILEGED) != 0) + .setOem((scanFlags & SCAN_AS_OEM) != 0) + .setVendor((scanFlags & SCAN_AS_VENDOR) != 0) + .setProduct((scanFlags & SCAN_AS_PRODUCT) != 0) + .setSystemExt((scanFlags & SCAN_AS_SYSTEM_EXT) != 0) + .setOdm((scanFlags & SCAN_AS_ODM) != 0); // Check if the package is signed with the same key as the platform package. - if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) || - (platformPkg != null && compareSignatures( - platformPkg.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) == PackageManager.SIGNATURE_MATCH)) { - pkg.applicationInfo.privateFlags |= - ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY; - } - - if (!isSystemApp(pkg)) { + parsedPackage.setSignedWithPlatformKey( + (PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName()) + || (platformPkg != null && compareSignatures( + platformPkg.getSigningDetails().signatures, + parsedPackage.getSigningDetails().signatures + ) == PackageManager.SIGNATURE_MATCH)) + ); + + if (!isSystemApp(parsedPackage)) { // Only system apps can use these features. - pkg.mOriginalPackages = null; - pkg.mRealPackage = null; - pkg.mAdoptPermissions = null; + parsedPackage.clearOriginalPackages() + .setRealPackage(null) + .clearAdoptPermissions(); } - PackageBackwardCompatibility.modifySharedLibraries(pkg); + PackageBackwardCompatibility.modifySharedLibraries(parsedPackage); } private static @NonNull <T> T assertNotNull(@Nullable T object, String message) @@ -11189,15 +11079,15 @@ public class PackageManagerService extends IPackageManager.Stub * * @throws PackageManagerException If the package fails any of the validation checks */ - private void assertPackageIsValid(PackageParser.Package pkg, final @ParseFlags int parseFlags, + private void assertPackageIsValid(AndroidPackage pkg, final @ParseFlags int parseFlags, final @ScanFlags int scanFlags) throws PackageManagerException { if ((parseFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) { assertCodePolicy(pkg); } - if (pkg.applicationInfo.getCodePath() == null || - pkg.applicationInfo.getResourcePath() == null) { + if (pkg.getAppInfoCodePath() == null || + pkg.getAppInfoResourcePath() == null) { // Bail out. The resource and code paths haven't been set. throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "Code and resource paths haven't been set correctly"); @@ -11208,9 +11098,10 @@ public class PackageManagerService extends IPackageManager.Stub final boolean isUserInstall = (scanFlags & SCAN_BOOTING) == 0; final boolean isFirstBootOrUpgrade = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0; if ((isUserInstall || isFirstBootOrUpgrade) - && mApexManager.isApexPackage(pkg.packageName)) { + && mApexManager.isApexPackage(pkg.getPackageName())) { throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, - pkg.packageName + " is an APEX package and can't be installed as an APK."); + pkg.getPackageName() + + " is an APEX package and can't be installed as an APK."); } // Make sure we're not adding any bogus keyset info @@ -11219,11 +11110,11 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { // The special "android" package can only be defined once - if (pkg.packageName.equals("android")) { + if (pkg.getPackageName().equals("android")) { if (mAndroidApplication != null) { Slog.w(TAG, "*************************************************"); Slog.w(TAG, "Core android package being redefined. Skipping."); - Slog.w(TAG, " codePath=" + pkg.codePath); + Slog.w(TAG, " codePath=" + pkg.getCodePath()); Slog.w(TAG, "*************************************************"); throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, "Core android package being redefined. Skipping."); @@ -11231,23 +11122,24 @@ public class PackageManagerService extends IPackageManager.Stub } // A package name must be unique; don't allow duplicates - if ((scanFlags & SCAN_NEW_INSTALL) == 0 && mPackages.containsKey(pkg.packageName)) { + if ((scanFlags & SCAN_NEW_INSTALL) == 0 + && mPackages.containsKey(pkg.getPackageName())) { throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE, - "Application package " + pkg.packageName + "Application package " + pkg.getPackageName() + " already installed. Skipping duplicate."); } - if (pkg.applicationInfo.isStaticSharedLibrary()) { + if (pkg.isStaticSharedLibrary()) { // Static libs have a synthetic package name containing the version // but we still want the base name to be unique. if ((scanFlags & SCAN_NEW_INSTALL) == 0 - && mPackages.containsKey(pkg.manifestPackageName)) { + && mPackages.containsKey(pkg.getManifestPackageName())) { throw new PackageManagerException( "Duplicate static shared lib provider package"); } // Static shared libraries should have at least O target SDK - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) { + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) { throw new PackageManagerException( "Packages declaring static-shared libs must target O SDK or higher"); } @@ -11260,73 +11152,67 @@ public class PackageManagerService extends IPackageManager.Stub // Package declaring static a shared lib cannot be renamed since the package // name is synthetic and apps can't code around package manager internals. - if (!ArrayUtils.isEmpty(pkg.mOriginalPackages)) { + if (!ArrayUtils.isEmpty(pkg.getOriginalPackages())) { throw new PackageManagerException( "Packages declaring static-shared libs cannot be renamed"); } - // Package declaring static a shared lib cannot declare child packages - if (!ArrayUtils.isEmpty(pkg.childPackages)) { - throw new PackageManagerException( - "Packages declaring static-shared libs cannot have child packages"); - } - // Package declaring static a shared lib cannot declare dynamic libs - if (!ArrayUtils.isEmpty(pkg.libraryNames)) { + if (!ArrayUtils.isEmpty(pkg.getLibraryNames())) { throw new PackageManagerException( "Packages declaring static-shared libs cannot declare dynamic libs"); } // Package declaring static a shared lib cannot declare shared users - if (pkg.mSharedUserId != null) { + if (pkg.getSharedUserId() != null) { throw new PackageManagerException( "Packages declaring static-shared libs cannot declare shared users"); } // Static shared libs cannot declare activities - if (!pkg.activities.isEmpty()) { + if (pkg.getActivities() != null && !pkg.getActivities().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare activities"); } // Static shared libs cannot declare services - if (!pkg.services.isEmpty()) { + if (pkg.getServices() != null && !pkg.getServices().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare services"); } // Static shared libs cannot declare providers - if (!pkg.providers.isEmpty()) { + if (pkg.getProviders() != null && !pkg.getProviders().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare content providers"); } // Static shared libs cannot declare receivers - if (!pkg.receivers.isEmpty()) { + if (pkg.getReceivers() != null && !pkg.getReceivers().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare broadcast receivers"); } // Static shared libs cannot declare permission groups - if (!pkg.permissionGroups.isEmpty()) { + if (pkg.getPermissionGroups() != null && !pkg.getPermissionGroups().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permission groups"); } // Static shared libs cannot declare permissions - if (!pkg.permissions.isEmpty()) { + if (pkg.getPermissions() != null && !pkg.getPermissions().isEmpty()) { throw new PackageManagerException( "Static shared libs cannot declare permissions"); } // Static shared libs cannot declare protected broadcasts - if (pkg.protectedBroadcasts != null) { + if (pkg.getProtectedBroadcasts() != null) { throw new PackageManagerException( "Static shared libs cannot declare protected broadcasts"); } // Static shared libs cannot be overlay targets - if (pkg.mOverlayTarget != null) { + if (pkg.getOverlayTarget() != null) { throw new PackageManagerException( "Static shared libs cannot be overlay targets"); } @@ -11336,16 +11222,17 @@ public class PackageManagerService extends IPackageManager.Stub long maxVersionCode = Long.MAX_VALUE; LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get( - pkg.staticSharedLibName); + pkg.getStaticSharedLibName()); if (versionedLib != null) { final int versionCount = versionedLib.size(); for (int i = 0; i < versionCount; i++) { SharedLibraryInfo libInfo = versionedLib.valueAt(i); final long libVersionCode = libInfo.getDeclaringPackage() .getLongVersionCode(); - if (libInfo.getLongVersion() < pkg.staticSharedLibVersion) { + if (libInfo.getLongVersion() < pkg.getStaticSharedLibVersion()) { minVersionCode = Math.max(minVersionCode, libVersionCode + 1); - } else if (libInfo.getLongVersion() > pkg.staticSharedLibVersion) { + } else if (libInfo.getLongVersion() + > pkg.getStaticSharedLibVersion()) { maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1); } else { minVersionCode = maxVersionCode = libVersionCode; @@ -11360,23 +11247,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - // Only privileged apps and updated privileged apps can add child packages. - if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) { - if ((scanFlags & SCAN_AS_PRIVILEGED) == 0) { - throw new PackageManagerException("Only privileged apps can add child " - + "packages. Ignoring package " + pkg.packageName); - } - final int childCount = pkg.childPackages.size(); - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - if (mSettings.hasOtherDisabledSystemPkgWithChildLPr(pkg.packageName, - childPkg.packageName)) { - throw new PackageManagerException("Can't override child of " - + "another disabled app. Ignoring package " + pkg.packageName); - } - } - } - // If we're only installing presumed-existing packages, require that the // scanned APK is both already known and at the path previously established // for it. Previously unknown packages we pick up normally, but if we have an @@ -11386,29 +11256,30 @@ public class PackageManagerService extends IPackageManager.Stub // to the user-installed location. If we don't allow this change, any newer, // user-installed version of the application will be ignored. if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) { - if (mExpectingBetter.containsKey(pkg.packageName)) { + if (mExpectingBetter.containsKey(pkg.getPackageName())) { logCriticalInfo(Log.WARN, - "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName); + "Relax SCAN_REQUIRE_KNOWN requirement for package " + + pkg.getPackageName()); } else { - PackageSetting known = mSettings.getPackageLPr(pkg.packageName); + PackageSetting known = mSettings.getPackageLPr(pkg.getPackageName()); if (known != null) { if (DEBUG_PACKAGE_SCANNING) { - Log.d(TAG, "Examining " + pkg.codePath + Log.d(TAG, "Examining " + pkg.getCodePath() + " and requiring known paths " + known.codePathString + " & " + known.resourcePathString); } - if (!pkg.applicationInfo.getCodePath().equals(known.codePathString) - || !pkg.applicationInfo.getResourcePath().equals( + if (!pkg.getAppInfoCodePath().equals(known.codePathString) + || !pkg.getAppInfoResourcePath().equals( known.resourcePathString)) { throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED, - "Application package " + pkg.packageName - + " found at " + pkg.applicationInfo.getCodePath() + "Application package " + pkg.getPackageName() + + " found at " + pkg.getAppInfoCodePath() + " but expected at " + known.codePathString + "; ignoring."); } } else { throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION, - "Application package " + pkg.packageName + "Application package " + pkg.getPackageName() + " not found; ignoring."); } } @@ -11423,11 +11294,13 @@ public class PackageManagerService extends IPackageManager.Stub } // Verify that packages sharing a user with a privileged app are marked as privileged. - if (!pkg.isPrivileged() && (pkg.mSharedUserId != null)) { + if (!pkg.isPrivileged() && (pkg.getSharedUserId() != null)) { SharedUserSetting sharedUserSetting = null; try { - sharedUserSetting = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, false); - } catch (PackageManagerException ignore) {} + sharedUserSetting = mSettings.getSharedUserLPw(pkg.getSharedUserId(), + 0, 0, false); + } catch (PackageManagerException ignore) { + } if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); @@ -11435,18 +11308,18 @@ public class PackageManagerService extends IPackageManager.Stub != PackageParser.SigningDetails.UNKNOWN) && (compareSignatures( platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) + pkg.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH)) { throw new PackageManagerException("Apps that share a user with a " + "privileged app must themselves be marked as privileged. " + - pkg.packageName + " shares privileged user " + - pkg.mSharedUserId + "."); + pkg.getPackageName() + " shares privileged user " + + pkg.getSharedUserId() + "."); } } } // Apply policies specific for runtime resource overlays (RROs). - if (pkg.mOverlayTarget != null) { + if (pkg.getOverlayTarget() != null) { // System overlays have some restrictions on their use of the 'static' state. if ((scanFlags & SCAN_AS_SYSTEM) != 0) { // We are scanning a system overlay. This can be the first scan of the @@ -11454,54 +11327,62 @@ public class PackageManagerService extends IPackageManager.Stub if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { // This must be an update to a system overlay. final PackageSetting previousPkg = assertNotNull( - mSettings.getPackageLPr(pkg.packageName), + mSettings.getPackageLPr(pkg.getPackageName()), "previous package state not present"); // previousPkg.pkg may be null: the package will be not be scanned if the // package manager knows there is a newer version on /data. // TODO[b/79435695]: Find a better way to keep track of the "static" // property for RROs instead of having to parse packages on /system - PackageParser.Package ppkg = previousPkg.pkg; + AndroidPackage ppkg = previousPkg.pkg; if (ppkg == null) { try { final PackageParser pp = new PackageParser(); - ppkg = pp.parsePackage(previousPkg.codePath, - parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR); + // TODO(b/135203078): Do we really need to parse here? Maybe use + // a shortened path? + ppkg = pp.parseParsedPackage(previousPkg.codePath, + parseFlags | PackageParser.PARSE_IS_SYSTEM_DIR, + false) + .hideAsFinal(); } catch (PackageParserException e) { Slog.w(TAG, "failed to parse " + previousPkg.codePath, e); } } // Static overlays cannot be updated. - if (ppkg != null && ppkg.mOverlayIsStatic) { - throw new PackageManagerException("Overlay " + pkg.packageName + - " is static and cannot be upgraded."); + if (ppkg != null && ppkg.isOverlayIsStatic()) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + + " is static and cannot be upgraded."); // Non-static overlays cannot be converted to static overlays. - } else if (pkg.mOverlayIsStatic) { - throw new PackageManagerException("Overlay " + pkg.packageName + - " cannot be upgraded into a static overlay."); + } else if (pkg.isOverlayIsStatic()) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + + " cannot be upgraded into a static overlay."); } } } else { // The overlay is a non-system overlay. Non-system overlays cannot be static. - if (pkg.mOverlayIsStatic) { - throw new PackageManagerException("Overlay " + pkg.packageName + - " is static but not pre-installed."); + if (pkg.isOverlayIsStatic()) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + + " is static but not pre-installed."); } // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be // signed with the platform certificate. Check this in increasing order of // computational cost. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) { + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) { final PackageSetting platformPkgSetting = mSettings.getPackageLPr("android"); if ((platformPkgSetting.signatures.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) && (compareSignatures( platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) + pkg.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH)) { - throw new PackageManagerException("Overlay " + pkg.packageName + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + " must target Q or later, " + "or be signed with the platform certificate"); } @@ -11511,18 +11392,19 @@ public class PackageManagerService extends IPackageManager.Stub // only be used if it is signed with the same certificate as its target. If the // target is already installed, check this here to augment the last line of // defence which is OMS. - if (pkg.mOverlayTargetName == null) { + if (pkg.getOverlayTargetName() == null) { final PackageSetting targetPkgSetting = - mSettings.getPackageLPr(pkg.mOverlayTarget); + mSettings.getPackageLPr(pkg.getOverlayTarget()); if (targetPkgSetting != null) { if ((targetPkgSetting.signatures.mSigningDetails != PackageParser.SigningDetails.UNKNOWN) && (compareSignatures( targetPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) + pkg.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH)) { - throw new PackageManagerException("Overlay " + pkg.packageName - + " and target " + pkg.mOverlayTarget + " signed with" + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + " and target " + + pkg.getOverlayTarget() + " signed with" + " different certificates, and the overlay lacks" + " <overlay android:targetName>"); } @@ -11602,71 +11484,67 @@ public class PackageManagerService extends IPackageManager.Stub * Adds a scanned package to the system. When this method is finished, the package will * be available for query, resolution, etc... */ - private void commitPackageSettings(PackageParser.Package pkg, - @Nullable PackageParser.Package oldPkg, PackageSetting pkgSetting, + private void commitPackageSettings(AndroidPackage pkg, + @Nullable AndroidPackage oldPkg, PackageSetting pkgSetting, final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) { - final String pkgName = pkg.packageName; + final String pkgName = pkg.getPackageName(); if (mCustomResolverComponentName != null && - mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) { + mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) { setUpCustomResolverActivity(pkg); } - if (pkg.packageName.equals("android")) { + if (pkg.getPackageName().equals("android")) { synchronized (mLock) { - if ((scanFlags & SCAN_CHECK_ONLY) == 0) { - // Set up information for our fall-back user intent resolution activity. - mPlatformPackage = pkg; - pkg.mVersionCode = mSdkVersion; - pkg.mVersionCodeMajor = 0; - mAndroidApplication = pkg.applicationInfo; - if (!mResolverReplaced) { - mResolveActivity.applicationInfo = mAndroidApplication; - mResolveActivity.name = ResolverActivity.class.getName(); - mResolveActivity.packageName = mAndroidApplication.packageName; - mResolveActivity.processName = "system:ui"; - mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; - mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER; - mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; - mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert; - mResolveActivity.exported = true; - mResolveActivity.enabled = true; - mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; - mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE - | ActivityInfo.CONFIG_SCREEN_LAYOUT - | ActivityInfo.CONFIG_ORIENTATION - | ActivityInfo.CONFIG_KEYBOARD - | ActivityInfo.CONFIG_KEYBOARD_HIDDEN; - mResolveInfo.activityInfo = mResolveActivity; - mResolveInfo.priority = 0; - mResolveInfo.preferredOrder = 0; - mResolveInfo.match = 0; - mResolveComponentName = new ComponentName( - mAndroidApplication.packageName, mResolveActivity.name); - } - } - } - } - - ArrayList<PackageParser.Package> clientLibPkgs = null; + // Set up information for our fall-back user intent resolution activity. + mPlatformPackage = pkg; + mAndroidApplication = pkg.toAppInfo(); + if (!mResolverReplaced) { + mResolveActivity.applicationInfo = mAndroidApplication; + mResolveActivity.name = ResolverActivity.class.getName(); + mResolveActivity.packageName = mAndroidApplication.packageName; + mResolveActivity.processName = "system:ui"; + mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER; + mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; + mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert; + mResolveActivity.exported = true; + mResolveActivity.enabled = true; + mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; + mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE + | ActivityInfo.CONFIG_SCREEN_LAYOUT + | ActivityInfo.CONFIG_ORIENTATION + | ActivityInfo.CONFIG_KEYBOARD + | ActivityInfo.CONFIG_KEYBOARD_HIDDEN; + mResolveInfo.activityInfo = mResolveActivity; + mResolveInfo.priority = 0; + mResolveInfo.preferredOrder = 0; + mResolveInfo.match = 0; + mResolveComponentName = new ComponentName( + mAndroidApplication.packageName, mResolveActivity.name); + } + } + } + + ArrayList<AndroidPackage> clientLibPkgs = null; // writer synchronized (mLock) { if (!ArrayUtils.isEmpty(reconciledPkg.allowedSharedLibraryInfos)) { for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) { commitSharedLibraryInfoLocked(info); } - final Map<String, PackageParser.Package> combinedPackages = - reconciledPkg.getCombinedPackages(); + final Map<String, AndroidPackage> combinedSigningDetails = + reconciledPkg.getCombinedAvailablePackages(); try { // Shared libraries for the package need to be updated. - updateSharedLibrariesLocked(pkg, null, combinedPackages); + updateSharedLibrariesLocked(pkg, null, combinedSigningDetails); } catch (PackageManagerException e) { Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e); } // Update all applications that use this library. Skip when booting // since this will be done after all packages are scaned. if ((scanFlags & SCAN_BOOTING) == 0) { - clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages); + clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedSigningDetails); } } } @@ -11690,9 +11568,9 @@ public class PackageManagerService extends IPackageManager.Stub // Also need to kill any apps that are dependent on the library. if (clientLibPkgs != null) { for (int i=0; i<clientLibPkgs.size(); i++) { - PackageParser.Package clientPkg = clientLibPkgs.get(i); - killApplication(clientPkg.applicationInfo.packageName, - clientPkg.applicationInfo.uid, "update lib"); + AndroidPackage clientPkg = clientLibPkgs.get(i); + killApplication(clientPkg.getAppInfoPackageName(), + clientPkg.getUid(), "update lib"); } } @@ -11705,7 +11583,7 @@ public class PackageManagerService extends IPackageManager.Stub // Add the new setting to mSettings mSettings.insertPackageSettingLPw(pkgSetting, pkg); // Add the new setting to mPackages - mPackages.put(pkg.applicationInfo.packageName, pkg); + mPackages.put(pkg.getAppInfoPackageName(), pkg); // Add the package's KeySets to the global KeySetManagerService KeySetManagerService ksms = mSettings.mKeySetManagerService; @@ -11716,7 +11594,7 @@ public class PackageManagerService extends IPackageManager.Stub // Don't allow ephemeral applications to define new permissions groups. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { - Slog.w(TAG, "Permission groups from package " + pkg.packageName + Slog.w(TAG, "Permission groups from package " + pkg.getPackageName() + " ignored: instant apps cannot define new permission groups."); } else { mPermissionManager.addAllPermissionGroups(pkg, chatty); @@ -11724,31 +11602,31 @@ public class PackageManagerService extends IPackageManager.Stub // Don't allow ephemeral applications to define new permissions. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { - Slog.w(TAG, "Permissions from package " + pkg.packageName + Slog.w(TAG, "Permissions from package " + pkg.getPackageName() + " ignored: instant apps cannot define new permissions."); } else { mPermissionManager.addAllPermissions(pkg, chatty); } - int collectionSize = pkg.instrumentation.size(); + int collectionSize = ArrayUtils.size(pkg.getInstrumentations()); StringBuilder r = null; int i; for (i = 0; i < collectionSize; i++) { - PackageParser.Instrumentation a = pkg.instrumentation.get(i); - a.info.packageName = pkg.applicationInfo.packageName; - a.info.sourceDir = pkg.applicationInfo.sourceDir; - a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir; - a.info.splitNames = pkg.splitNames; - a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs; - a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs; - a.info.splitDependencies = pkg.applicationInfo.splitDependencies; - a.info.dataDir = pkg.applicationInfo.dataDir; - a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir; - a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir; - a.info.primaryCpuAbi = pkg.applicationInfo.primaryCpuAbi; - a.info.secondaryCpuAbi = pkg.applicationInfo.secondaryCpuAbi; - a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; - a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir; + ParsedInstrumentation a = pkg.getInstrumentations().get(i); + a.setPackageName(pkg.getAppInfoPackageName()); + a.sourceDir = pkg.getBaseCodePath(); + a.publicSourceDir = pkg.getPublicSourceDir(); + a.splitNames = pkg.getSplitNames(); + a.splitSourceDirs = pkg.getSplitCodePaths(); + a.splitPublicSourceDirs = pkg.getSplitPublicSourceDirs(); + a.splitDependencies = pkg.getSplitDependencies(); + a.dataDir = pkg.getDataDir(); + a.deviceProtectedDataDir = pkg.getDeviceProtectedDataDir(); + a.credentialProtectedDataDir = pkg.getCredentialProtectedDataDir(); + a.primaryCpuAbi = pkg.getPrimaryCpuAbi(); + a.secondaryCpuAbi = pkg.getSecondaryCpuAbi(); + a.nativeLibraryDir = pkg.getNativeLibraryDir(); + a.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir(); mInstrumentation.put(a.getComponentName(), a); if (chatty) { if (r == null) { @@ -11756,19 +11634,16 @@ public class PackageManagerService extends IPackageManager.Stub } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r); } - if (pkg.protectedBroadcasts != null) { - collectionSize = pkg.protectedBroadcasts.size(); + if (pkg.getProtectedBroadcasts() != null) { synchronized (mProtectedBroadcasts) { - for (i = 0; i < collectionSize; i++) { - mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i)); - } + mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts()); } } @@ -11792,14 +11667,14 @@ public class PackageManagerService extends IPackageManager.Stub Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - private void setUpCustomResolverActivity(PackageParser.Package pkg) { + private void setUpCustomResolverActivity(AndroidPackage pkg) { synchronized (mLock) { mResolverReplaced = true; // Set up information for custom user intent resolution activity. - mResolveActivity.applicationInfo = pkg.applicationInfo; + mResolveActivity.applicationInfo = pkg.toAppInfo(); mResolveActivity.name = mCustomResolverComponentName.getClassName(); - mResolveActivity.packageName = pkg.applicationInfo.packageName; - mResolveActivity.processName = pkg.applicationInfo.packageName; + mResolveActivity.packageName = pkg.getAppInfoPackageName(); + mResolveActivity.processName = pkg.getAppInfoProcessName(); mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE; mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS | ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; @@ -11866,22 +11741,13 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void removePackageLI(PackageParser.Package pkg, boolean chatty) { + private void removePackageLI(AndroidPackage pkg, boolean chatty) { // Remove the parent package setting - PackageSetting ps = (PackageSetting) pkg.mExtras; + PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (ps != null) { removePackageLI(ps.name, chatty); } else if (DEBUG_REMOVE && chatty) { - Log.d(TAG, "Not removing package " + pkg.packageName + "; mExtras == null"); - } - // Remove the child package setting - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - ps = (PackageSetting) childPkg.mExtras; - if (ps != null) { - removePackageLI(ps.name, chatty); - } + Log.d(TAG, "Not removing package " + pkg.getPackageName() + "; mExtras == null"); } } @@ -11893,45 +11759,23 @@ public class PackageManagerService extends IPackageManager.Stub // writer synchronized (mLock) { - final PackageParser.Package removedPackage = mPackages.remove(packageName); + final AndroidPackage removedPackage = mPackages.remove(packageName); if (removedPackage != null) { cleanPackageDataStructuresLILPw(removedPackage, chatty); } } } - void removeInstalledPackageLI(PackageParser.Package pkg, boolean chatty) { - if (DEBUG_INSTALL) { - if (chatty) - Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName); - } - - // writer - synchronized (mLock) { - // Remove the parent package - mPackages.remove(pkg.applicationInfo.packageName); - cleanPackageDataStructuresLILPw(pkg, chatty); - - // Remove the child packages - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - mPackages.remove(childPkg.applicationInfo.packageName); - cleanPackageDataStructuresLILPw(childPkg, chatty); - } - } - } - - void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) { + void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) { mComponentResolver.removeAllComponents(pkg, chatty); - mAppsFilter.removePackage(pkg.packageName); + mAppsFilter.removePackage(pkg.getPackageName()); mPermissionManager.removeAllPermissions(pkg, chatty); - final int instrumentationSize = pkg.instrumentation.size(); + final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations()); StringBuilder r = null; int i; for (i = 0; i < instrumentationSize; i++) { - PackageParser.Instrumentation a = pkg.instrumentation.get(i); + ParsedInstrumentation a = pkg.getInstrumentations().get(i); mInstrumentation.remove(a.getComponentName()); if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -11939,7 +11783,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { r.append(' '); } - r.append(a.info.name); + r.append(a.getName()); } } if (r != null) { @@ -11947,12 +11791,12 @@ public class PackageManagerService extends IPackageManager.Stub } r = null; - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) { // Only system apps can hold shared libraries. - if (pkg.libraryNames != null) { - final int libraryNamesSize = pkg.libraryNames.size(); + if (pkg.getLibraryNames() != null) { + final int libraryNamesSize = pkg.getLibraryNames().size(); for (i = 0; i < libraryNamesSize; i++) { - String name = pkg.libraryNames.get(i); + String name = pkg.getLibraryNames().get(i); if (removeSharedLibraryLPw(name, 0)) { if (DEBUG_REMOVE && chatty) { if (r == null) { @@ -11970,15 +11814,16 @@ public class PackageManagerService extends IPackageManager.Stub r = null; // Any package can hold static shared libraries. - if (pkg.staticSharedLibName != null) { - if (removeSharedLibraryLPw(pkg.staticSharedLibName, pkg.staticSharedLibVersion)) { + if (pkg.getStaticSharedLibName() != null) { + if (removeSharedLibraryLPw(pkg.getStaticSharedLibName(), + pkg.getStaticSharedLibVersion())) { if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } - r.append(pkg.staticSharedLibName); + r.append(pkg.getStaticSharedLibName()); } } } @@ -12319,11 +12164,11 @@ public class PackageManagerService extends IPackageManager.Stub // Cannot hide static shared libs as they are considered // a part of the using app (emulating static linking). Also // static libs are installed always on internal storage. - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg != null && pkg.staticSharedLibName != null) { + AndroidPackage pkg = mPackages.get(packageName); + if (pkg != null && pkg.getStaticSharedLibName() != null) { Slog.w(TAG, "Cannot hide package: " + packageName + " providing static shared library: " - + pkg.staticSharedLibName); + + pkg.getStaticSharedLibName()); return false; } // Only allow protected packages to hide themselves. @@ -12369,17 +12214,17 @@ public class PackageManagerService extends IPackageManager.Stub if (pkgSetting == null || !pkgSetting.isSystem()) { return; } - PackageParser.Package pkg = pkgSetting.pkg; - if (pkg != null && pkg.applicationInfo != null) { - pkg.applicationInfo.hiddenUntilInstalled = hidden; + AndroidPackage pkg = pkgSetting.pkg; + if (pkg != null) { + pkg.mutate().setHiddenUntilInstalled(hidden); } final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(packageName); if (disabledPs == null) { return; } pkg = disabledPs.pkg; - if (pkg != null && pkg.applicationInfo != null) { - pkg.applicationInfo.hiddenUntilInstalled = hidden; + if (pkg != null) { + pkg.mutate().setHiddenUntilInstalled(hidden); } } } @@ -12575,7 +12420,7 @@ public class PackageManagerService extends IPackageManager.Stub if (installed) { if ((installFlags & PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS) != 0 && pkgSetting.pkg != null) { - whiteListedPermissions = pkgSetting.pkg.requestedPermissions; + whiteListedPermissions = pkgSetting.pkg.getRequestedPermissions(); } mPermissionManager.setWhitelistedRestrictedPermissions(packageName, whiteListedPermissions, FLAG_PERMISSION_WHITELIST_INSTALLER, userId); @@ -13012,11 +12857,11 @@ public class PackageManagerService extends IPackageManager.Stub // Cannot suspend static shared libs as they are considered // a part of the using app (emulating static linking). Also // static libs are installed always on internal storage. - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) { + AndroidPackage pkg = mPackages.get(packageName); + if (pkg != null && pkg.isStaticSharedLibrary()) { Slog.w(TAG, "Cannot suspend package: " + packageName + " providing static shared library: " - + pkg.staticSharedLibName); + + pkg.getStaticSharedLibName()); continue; } } @@ -13161,10 +13006,10 @@ public class PackageManagerService extends IPackageManager.Stub private int getUidForVerifier(VerifierInfo verifierInfo) { synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(verifierInfo.packageName); + final AndroidPackage pkg = mPackages.get(verifierInfo.packageName); if (pkg == null) { return -1; - } else if (pkg.mSigningDetails.signatures.length != 1) { + } else if (pkg.getSigningDetails().signatures.length != 1) { Slog.i(TAG, "Verifier package " + verifierInfo.packageName + " has more than one signature; ignoring"); return -1; @@ -13178,7 +13023,7 @@ public class PackageManagerService extends IPackageManager.Stub final byte[] expectedPublicKey; try { - final Signature verifierSig = pkg.mSigningDetails.signatures[0]; + final Signature verifierSig = pkg.getSigningDetails().signatures[0]; final PublicKey publicKey = verifierSig.getPublicKey(); expectedPublicKey = publicKey.getEncoded(); } catch (CertificateException e) { @@ -13193,7 +13038,7 @@ public class PackageManagerService extends IPackageManager.Stub return -1; } - return pkg.applicationInfo.uid; + return pkg.getUid(); } } @@ -13381,26 +13226,33 @@ public class PackageManagerService extends IPackageManager.Stub final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); synchronized (mLock) { - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg == null || pkg.activities == null) { + AndroidPackage pkg = mPackages.get(packageName); + if (pkg == null || ArrayUtils.isEmpty(pkg.getActivities())) { return ParceledListSlice.emptyList(); } - if (pkg.mExtras == null) { + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); + if (ps == null) { return ParceledListSlice.emptyList(); } - final PackageSetting ps = (PackageSetting) pkg.mExtras; if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { return ParceledListSlice.emptyList(); } - final int count = pkg.activities.size(); + final int count = ArrayUtils.size(pkg.getActivities()); ArrayList<IntentFilter> result = new ArrayList<>(); for (int n=0; n<count; n++) { - PackageParser.Activity activity = pkg.activities.get(n); + ParsedActivity activity = pkg.getActivities().get(n); if (activity.intents != null && activity.intents.size() > 0) { result.addAll(activity.intents); } } - return new ParceledListSlice<>(result); + return new ParceledListSlice<IntentFilter>(result) { + @Override + protected void writeElement(IntentFilter parcelable, Parcel dest, int callFlags) { + // IntentFilter has final Parcelable methods, so redirect to the subclass + ((ParsedActivityIntentInfo) parcelable).writeIntentInfoToParcel(dest, + callFlags); + } + }; } } @@ -13581,7 +13433,7 @@ public class PackageManagerService extends IPackageManager.Stub // package has not opted out of backup participation. final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null; - final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags; + final int flags = (res.pkg == null) ? 0 : res.pkg.getFlags(); boolean doRestore = !update && ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0); @@ -13619,7 +13471,7 @@ public class PackageManagerService extends IPackageManager.Stub try { if (bm.isBackupServiceActive(userId)) { bm.restoreAtInstallForUser( - userId, res.pkg.applicationInfo.packageName, token); + userId, res.pkg.getAppInfoPackageName(), token); } else { doRestore = false; } @@ -13644,8 +13496,8 @@ public class PackageManagerService extends IPackageManager.Stub IRollbackManager rm = IRollbackManager.Stub.asInterface( ServiceManager.getService(Context.ROLLBACK_SERVICE)); - final String packageName = res.pkg.applicationInfo.packageName; - final String seInfo = res.pkg.applicationInfo.seInfo; + final String packageName = res.pkg.getAppInfoPackageName(); + final String seInfo = res.pkg.getSeInfo(); final int[] allUsers = mUserManager.getUserIds(); final int[] installedUsers; @@ -13714,7 +13566,7 @@ public class PackageManagerService extends IPackageManager.Stub if (data.res.returnCode != PackageManager.INSTALL_SUCCEEDED) { continue; } - if (packageName.equals(data.res.pkg.applicationInfo.packageName)) { + if (packageName.equals(data.res.pkg.getAppInfoPackageName())) { // right package; but is it for the right user? for (int uIndex = 0; uIndex < data.res.newUsers.length; uIndex++) { if (userId == data.res.newUsers[uIndex]) { @@ -14056,12 +13908,12 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { // Currently installed package which the new package is attempting to replace or // null if no such package is installed. - PackageParser.Package installedPkg = mPackages.get(packageName); + AndroidPackage installedPkg = mPackages.get(packageName); // Package which currently owns the data which the new package will own if installed. // If an app is unstalled while keeping data (e.g., adb uninstall -k), installedPkg // will be null whereas dataOwnerPkg will contain information about the package // which was uninstalled while keeping its data. - PackageParser.Package dataOwnerPkg = installedPkg; + AndroidPackage dataOwnerPkg = installedPkg; if (dataOwnerPkg == null) { PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { @@ -14088,7 +13940,7 @@ public class PackageManagerService extends IPackageManager.Stub if (dataOwnerPkg != null) { if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, - dataOwnerPkg.applicationInfo.flags)) { + dataOwnerPkg.getFlags())) { try { checkDowngrade(dataOwnerPkg, pkgLite); } catch (PackageManagerException e) { @@ -14101,7 +13953,7 @@ public class PackageManagerService extends IPackageManager.Stub if (installedPkg != null) { if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { // Check for updated system application. - if ((installedPkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if ((installedPkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0) { return PackageHelper.RECOMMEND_INSTALL_INTERNAL; } else { // If current upgrade specifies particular preference @@ -14564,7 +14416,7 @@ public class PackageManagerService extends IPackageManager.Stub * Rename package into final resting place. All paths on the given * scanned package should be updated to reflect the rename. */ - abstract boolean doRename(int status, PackageParser.Package pkg); + abstract boolean doRename(int status, ParsedPackage parsedPackage); abstract int doPostInstall(int status, int uid); /** @see PackageSettingBase#codePathString */ @@ -14712,7 +14564,8 @@ public class PackageManagerService extends IPackageManager.Stub return status; } - boolean doRename(int status, PackageParser.Package pkg) { + @Override + boolean doRename(int status, ParsedPackage parsedPackage) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); return false; @@ -14720,7 +14573,7 @@ public class PackageManagerService extends IPackageManager.Stub final File targetDir = codeFile.getParentFile(); final File beforeCodeFile = codeFile; - final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName); + final File afterCodeFile = getNextCodePath(targetDir, parsedPackage.getPackageName()); if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile); try { @@ -14741,24 +14594,23 @@ public class PackageManagerService extends IPackageManager.Stub // Reflect the rename in scanned details try { - pkg.setCodePath(afterCodeFile.getCanonicalPath()); + parsedPackage.setCodePath(afterCodeFile.getCanonicalPath()); } catch (IOException e) { Slog.e(TAG, "Failed to get path: " + afterCodeFile, e); return false; } - pkg.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile, - afterCodeFile, pkg.baseCodePath)); - pkg.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile, - afterCodeFile, pkg.splitCodePaths)); + parsedPackage.setBaseCodePath(FileUtils.rewriteAfterRename(beforeCodeFile, + afterCodeFile, parsedPackage.getBaseCodePath())); + parsedPackage.setSplitCodePaths(FileUtils.rewriteAfterRename(beforeCodeFile, + afterCodeFile, parsedPackage.getSplitCodePaths())); // Reflect the rename in app info - pkg.setApplicationVolumeUuid(pkg.volumeUuid); - pkg.setApplicationInfoCodePath(pkg.codePath); - pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths); - pkg.setApplicationInfoResourcePath(pkg.codePath); - pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths); + // TODO(b/135203078): Remove all of these application info calls + parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) + .setApplicationInfoCodePath(parsedPackage.getCodePath()) + .setApplicationInfoResourcePath(parsedPackage.getCodePath()) + .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) + .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); return true; } @@ -14861,20 +14713,20 @@ public class PackageManagerService extends IPackageManager.Stub return status; } - boolean doRename(int status, PackageParser.Package pkg) { + @Override + boolean doRename(int status, ParsedPackage parsedPackage) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(move.toUuid); return false; } // Reflect the move in app info - pkg.setApplicationVolumeUuid(pkg.volumeUuid); - pkg.setApplicationInfoCodePath(pkg.codePath); - pkg.setApplicationInfoBaseCodePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitCodePaths(pkg.splitCodePaths); - pkg.setApplicationInfoResourcePath(pkg.codePath); - pkg.setApplicationInfoBaseResourcePath(pkg.baseCodePath); - pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths); + // TODO(b/135203078): Remove all of these application info calls + parsedPackage.setApplicationVolumeUuid(parsedPackage.getVolumeUuid()) + .setApplicationInfoCodePath(parsedPackage.getCodePath()) + .setApplicationInfoResourcePath(parsedPackage.getCodePath()) + .setApplicationInfoBaseResourcePath(parsedPackage.getBaseCodePath()) + .setApplicationInfoSplitResourcePaths(parsedPackage.getSplitCodePaths()); return true; } @@ -14950,14 +14802,14 @@ public class PackageManagerService extends IPackageManager.Stub int[] origUsers; // The set of users that now have this package installed. int[] newUsers; - PackageParser.Package pkg; + AndroidPackage pkg; int returnCode; String returnMsg; String installerPackageName; PackageRemovedInfo removedInfo; ArrayMap<String, PackageInstalledInfo> addedChildPackages; // The set of packages consuming this shared library or null if no consumers exist. - ArrayList<PackageParser.Package> libraryConsumers; + ArrayList<AndroidPackage> libraryConsumers; public void setError(int code, String msg) { setReturnCode(code); @@ -15013,123 +14865,39 @@ public class PackageManagerService extends IPackageManager.Stub } } - /** - * Checks whether the parent or any of the child packages have a change shared - * user. For a package to be a valid update the shred users of the parent and - * the children should match. We may later support changing child shared users. - * @param oldPkg The updated package. - * @param newPkg The update package. - * @return The shared user that change between the versions. - */ - private String getParentOrChildPackageChangedSharedUser(PackageParser.Package oldPkg, - PackageParser.Package newPkg) { - // Check parent shared user - if (!Objects.equals(oldPkg.mSharedUserId, newPkg.mSharedUserId)) { - return newPkg.packageName; - } - // Check child shared users - final int oldChildCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0; - final int newChildCount = (newPkg.childPackages != null) ? newPkg.childPackages.size() : 0; - for (int i = 0; i < newChildCount; i++) { - PackageParser.Package newChildPkg = newPkg.childPackages.get(i); - // If this child was present, did it have the same shared user? - for (int j = 0; j < oldChildCount; j++) { - PackageParser.Package oldChildPkg = oldPkg.childPackages.get(j); - if (newChildPkg.packageName.equals(oldChildPkg.packageName) - && !Objects.equals(newChildPkg.mSharedUserId, oldChildPkg.mSharedUserId)) { - return newChildPkg.packageName; - } - } - } - return null; - } - private void removeNativeBinariesLI(PackageSetting ps) { - // Remove the lib path for the parent package if (ps != null) { NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString); - // Remove the lib path for the child packages - final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageSetting childPs = null; - synchronized (mLock) { - childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i)); - } - if (childPs != null) { - NativeLibraryHelper.removeNativeBinariesLI(childPs - .legacyNativeLibraryPathString); - } - } - } - } - - @GuardedBy("mLock") - private void enableSystemPackageLPw(PackageParser.Package pkg) { - // Enable the parent package - mSettings.enableSystemPackageLPw(pkg.packageName); - // Enable the child packages - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - mSettings.enableSystemPackageLPw(childPkg.packageName); } } @GuardedBy("mLock") - private boolean disableSystemPackageLPw(PackageParser.Package oldPkg, - PackageParser.Package newPkg) { - // Disable the parent package (parent always replaced) - boolean disabled = mSettings.disableSystemPackageLPw(oldPkg.packageName, true); - // Disable the child packages - final int childCount = (oldPkg.childPackages != null) ? oldPkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = oldPkg.childPackages.get(i); - final boolean replace = newPkg.hasChildPackage(childPkg.packageName); - disabled |= mSettings.disableSystemPackageLPw(childPkg.packageName, replace); - } - return disabled; + private void enableSystemPackageLPw(AndroidPackage pkg) { + mSettings.enableSystemPackageLPw(pkg.getPackageName()); } @GuardedBy("mLock") - private void setInstallerPackageNameLPw(PackageParser.Package pkg, - String installerPackageName) { - // Enable the parent package - mSettings.setInstallerPackageName(pkg.packageName, installerPackageName); - // Enable the child packages - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - mSettings.setInstallerPackageName(childPkg.packageName, installerPackageName); - } + private boolean disableSystemPackageLPw(AndroidPackage oldPkg) { + return mSettings.disableSystemPackageLPw(oldPkg.getPackageName(), true); } - private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName, + private void updateSettingsLI(AndroidPackage newPackage, String installerPackageName, int[] allUsers, PackageInstalledInfo res, UserHandle user, int installReason) { - // Update the parent package setting updateSettingsInternalLI(newPackage, installerPackageName, allUsers, res.origUsers, res, user, installReason); - // Update the child packages setting - final int childCount = (newPackage.childPackages != null) - ? newPackage.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPackage = newPackage.childPackages.get(i); - PackageInstalledInfo childRes = res.addedChildPackages.get(childPackage.packageName); - updateSettingsInternalLI(childPackage, installerPackageName, allUsers, - childRes.origUsers, childRes, user, installReason); - } } - private void updateSettingsInternalLI(PackageParser.Package pkg, + private void updateSettingsInternalLI(AndroidPackage pkg, String installerPackageName, int[] allUsers, int[] installedForUsers, PackageInstalledInfo res, UserHandle user, int installReason) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings"); - final String pkgName = pkg.packageName; + final String pkgName = pkg.getPackageName(); - if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath); + if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.getCodePath()); synchronized (mLock) { // NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions - mPermissionManager.updatePermissions(pkg.packageName, pkg); + mPermissionManager.updatePermissions(pkg.getPackageName(), pkg); // For system-bundled packages, we assume that installing an upgraded version // of the package implies that the user actually wants to run that new code, // so we enable the package. @@ -15196,7 +14964,7 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeKernelMappingLPr(ps); } res.name = pkgName; - res.uid = pkg.applicationInfo.uid; + res.uid = pkg.getUid(); res.pkg = pkg; mSettings.setInstallerPackageName(pkgName, installerPackageName); res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); @@ -15254,7 +15022,7 @@ public class PackageManagerService extends IPackageManager.Stub private static class ReconcileRequest { public final Map<String, ScanResult> scannedPackages; - public final Map<String, PackageParser.Package> allPackages; + public final Map<String, AndroidPackage> allPackages; public final Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource; public final Map<String, InstallArgs> installArgs; public final Map<String, PackageInstalledInfo> installResults; @@ -15267,7 +15035,7 @@ public class PackageManagerService extends IPackageManager.Stub Map<String, PackageInstalledInfo> installResults, Map<String, PrepareResult> preparedPackages, Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource, - Map<String, PackageParser.Package> allPackages, + Map<String, AndroidPackage> allPackages, Map<String, VersionInfo> versionInfos, Map<String, PackageSetting> lastStaticSharedLibSettings) { this.scannedPackages = scannedPackages; @@ -15282,7 +15050,7 @@ public class PackageManagerService extends IPackageManager.Stub private ReconcileRequest(Map<String, ScanResult> scannedPackages, Map<String, LongSparseArray<SharedLibraryInfo>> sharedLibrarySource, - Map<String, PackageParser.Package> allPackages, + Map<String, AndroidPackage> allPackages, Map<String, VersionInfo> versionInfos, Map<String, PackageSetting> lastStaticSharedLibSettings) { this(scannedPackages, Collections.emptyMap(), Collections.emptyMap(), @@ -15350,15 +15118,17 @@ public class PackageManagerService extends IPackageManager.Stub * with the package(s) currently being installed. The to-be installed packages take * precedence and may shadow already installed packages. */ - private Map<String, PackageParser.Package> getCombinedPackages() { - final ArrayMap<String, PackageParser.Package> combinedPackages = + private Map<String, AndroidPackage> getCombinedAvailablePackages() { + final ArrayMap<String, AndroidPackage> combined = new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size()); - combinedPackages.putAll(request.allPackages); + combined.putAll(request.allPackages); + for (ScanResult scanResult : request.scannedPackages.values()) { - combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg); + combined.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage); } - return combinedPackages; + + return combined; } } @@ -15371,8 +15141,9 @@ public class PackageManagerService extends IPackageManager.Stub final Map<String, ReconciledPackage> result = new ArrayMap<>(scannedPackages.size()); // make a copy of the existing set of packages so we can combine them with incoming packages - final ArrayMap<String, PackageParser.Package> combinedPackages = + final ArrayMap<String, AndroidPackage> combinedPackages = new ArrayMap<>(request.allPackages.size() + scannedPackages.size()); + combinedPackages.putAll(request.allPackages); final Map<String, LongSparseArray<SharedLibraryInfo>> incomingSharedLibraries = @@ -15382,7 +15153,7 @@ public class PackageManagerService extends IPackageManager.Stub final ScanResult scanResult = scannedPackages.get(installPackageName); // add / replace existing with incoming packages - combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg); + combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.parsedPackage); // in the first pass, we'll build up the set of incoming shared libraries final List<SharedLibraryInfo> allowedSharedLibInfos = @@ -15415,7 +15186,7 @@ public class PackageManagerService extends IPackageManager.Stub | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP); deletePackageAction = mayDeletePackageLocked(res.removedInfo, prepareResult.originalPs, prepareResult.disabledPs, - prepareResult.childPackageSettings, deleteFlags, null /* all users */); + deleteFlags, null /* all users */); if (deletePackageAction == null) { throw new ReconcileFailure( PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE, @@ -15427,7 +15198,7 @@ public class PackageManagerService extends IPackageManager.Stub final int scanFlags = scanResult.request.scanFlags; final int parseFlags = scanResult.request.parseFlags; - final PackageParser.Package pkg = scanResult.request.pkg; + final ParsedPackage parsedPackage = scanResult.request.parsedPackage; final PackageSetting disabledPkgSetting = scanResult.request.disabledPkgSetting; final PackageSetting lastStaticSharedLibSetting = @@ -15440,35 +15211,37 @@ public class PackageManagerService extends IPackageManager.Stub boolean sharedUserSignaturesChanged = false; SigningDetails signingDetails = null; if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { - if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) { + if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) { // We just determined the app is signed correctly, so bring // over the latest parsed certs. } else { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, - "Package " + pkg.packageName + " upgrade keys do not match the " - + "previously installed version"); + "Package " + parsedPackage.getPackageName() + + " upgrade keys do not match the previously installed" + + " version"); } else { - String msg = "System package " + pkg.packageName + String msg = "System package " + parsedPackage.getPackageName() + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } } - signingDetails = pkg.mSigningDetails; + signingDetails = parsedPackage.getSigningDetails(); } else { try { final VersionInfo versionInfo = request.versionInfos.get(installPackageName); final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo); final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo); final boolean compatMatch = verifySignatures(signatureCheckPs, - disabledPkgSetting, pkg.mSigningDetails, compareCompat, compareRecover); + disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat, + compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { removeAppKeySetData = true; } // We just determined the app is signed correctly, so bring // over the latest parsed certs. - signingDetails = pkg.mSigningDetails; + signingDetails = parsedPackage.getSigningDetails(); // if this is is a sharedUser, check to see if the new package is signed by a @@ -15476,10 +15249,10 @@ public class PackageManagerService extends IPackageManager.Stub // signing certificate than the existing one, and if so, copy over the new // details if (signatureCheckPs.sharedUser != null) { - if (pkg.mSigningDetails.hasAncestor( + if (parsedPackage.getSigningDetails().hasAncestor( signatureCheckPs.sharedUser.signatures.mSigningDetails)) { signatureCheckPs.sharedUser.signatures.mSigningDetails = - pkg.mSigningDetails; + parsedPackage.getSigningDetails(); } if (signatureCheckPs.sharedUser.signaturesChanged == null) { signatureCheckPs.sharedUser.signaturesChanged = Boolean.FALSE; @@ -15489,7 +15262,7 @@ public class PackageManagerService extends IPackageManager.Stub if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new ReconcileFailure(e); } - signingDetails = pkg.mSigningDetails; + signingDetails = parsedPackage.getSigningDetails(); // If the system app is part of a shared user we allow that shared user to // change @@ -15504,7 +15277,7 @@ public class PackageManagerService extends IPackageManager.Stub signatureCheckPs.sharedUser.signatures.mSigningDetails.signatures; if (signatureCheckPs.sharedUser.signaturesChanged != null && compareSignatures(sharedUserSignatures, - pkg.mSigningDetails.signatures) + parsedPackage.getSigningDetails().signatures) != PackageManager.SIGNATURE_MATCH) { if (SystemProperties.getInt("ro.product.first_api_level", 0) <= 29) { // Mismatched signatures is an error and silently skipping system @@ -15524,18 +15297,19 @@ public class PackageManagerService extends IPackageManager.Stub // whichever package happened to be scanned later. throw new IllegalStateException( "Signature mismatch on system package " - + pkg.packageName + " for shared user " + + parsedPackage.getPackageName() + + " for shared user " + scanResult.pkgSetting.sharedUser); } } sharedUserSignaturesChanged = true; signatureCheckPs.sharedUser.signatures.mSigningDetails = - pkg.mSigningDetails; + parsedPackage.getSigningDetails(); signatureCheckPs.sharedUser.signaturesChanged = Boolean.TRUE; } // File a report about this. - String msg = "System package " + pkg.packageName + String msg = "System package " + parsedPackage.getPackageName() + " signature changed; retaining data."; reportSettingsProblem(Log.WARN, msg); } catch (IllegalArgumentException e) { @@ -15569,8 +15343,9 @@ public class PackageManagerService extends IPackageManager.Stub } try { result.get(installPackageName).collectedSharedLibraryInfos = - collectSharedLibraryInfos(scanResult.request.pkg, combinedPackages, - request.sharedLibrarySource, incomingSharedLibraries); + collectSharedLibraryInfos(scanResult.request.parsedPackage, + combinedPackages, request.sharedLibrarySource, + incomingSharedLibraries); } catch (PackageManagerException e) { throw new ReconcileFailure(e.error, e.getMessage()); @@ -15588,7 +15363,7 @@ public class PackageManagerService extends IPackageManager.Stub ScanResult scanResult, Map<String, LongSparseArray<SharedLibraryInfo>> existingSharedLibraries) { // Let's used the parsed package as scanResult.pkgSetting may be null - final PackageParser.Package pkg = scanResult.request.pkg; + final ParsedPackage parsedPackage = scanResult.request.parsedPackage; if (scanResult.staticSharedLibraryInfo == null && scanResult.dynamicSharedLibraryInfos == null) { return null; @@ -15599,12 +15374,12 @@ public class PackageManagerService extends IPackageManager.Stub return Collections.singletonList(scanResult.staticSharedLibraryInfo); } final boolean hasDynamicLibraries = - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 + (parsedPackage.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0 && scanResult.dynamicSharedLibraryInfos != null; if (!hasDynamicLibraries) { return null; } - final boolean isUpdatedSystemApp = pkg.isUpdatedSystemApp(); + final boolean isUpdatedSystemApp = parsedPackage.isUpdatedSystemApp(); // We may not yet have disabled the updated package yet, so be sure to grab the // current setting if that's the case. final PackageSetting updatedSystemPs = isUpdatedSystemApp @@ -15613,9 +15388,9 @@ public class PackageManagerService extends IPackageManager.Stub : scanResult.request.disabledPkgSetting : null; if (isUpdatedSystemApp && (updatedSystemPs.pkg == null - || updatedSystemPs.pkg.libraryNames == null)) { - Slog.w(TAG, "Package " + pkg.packageName + " declares libraries that are not " - + "declared on the system image; skipping"); + || updatedSystemPs.pkg.getLibraryNames() == null)) { + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + + " declares libraries that are not declared on the system image; skipping"); return null; } final ArrayList<SharedLibraryInfo> infos = @@ -15633,16 +15408,17 @@ public class PackageManagerService extends IPackageManager.Stub // with it. Better to just have the restriction here, be // conservative, and create many fewer cases that can negatively // impact the user experience. - if (!updatedSystemPs.pkg.libraryNames.contains(name)) { - Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name + if (!updatedSystemPs.pkg.getLibraryNames().contains(name)) { + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + + " declares library " + name + " that is not declared on system image; skipping"); continue; } } if (sharedLibExists( name, SharedLibraryInfo.VERSION_UNDEFINED, existingSharedLibraries)) { - Slog.w(TAG, "Package " + pkg.packageName + " declares library " + name - + " that already exists; skipping"); + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares library " + + name + " that already exists; skipping"); continue; } infos.add(info); @@ -15680,68 +15456,38 @@ public class PackageManagerService extends IPackageManager.Stub for (ReconciledPackage reconciledPkg : request.reconciledPackages.values()) { final ScanResult scanResult = reconciledPkg.scanResult; final ScanRequest scanRequest = scanResult.request; - final PackageParser.Package pkg = scanRequest.pkg; - final String packageName = pkg.packageName; + final ParsedPackage parsedPackage = scanRequest.parsedPackage; + final String packageName = parsedPackage.getPackageName(); final PackageInstalledInfo res = reconciledPkg.installResult; if (reconciledPkg.prepareResult.replace) { - PackageParser.Package oldPackage = mPackages.get(packageName); + AndroidPackage oldPackage = mPackages.get(packageName); // Set the update and install times - PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras; - setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime, - System.currentTimeMillis()); + PackageSetting deletedPkgSetting = getPackageSetting(oldPackage.getPackageName()); + reconciledPkg.pkgSetting.firstInstallTime = deletedPkgSetting.firstInstallTime; + reconciledPkg.pkgSetting.lastUpdateTime = System.currentTimeMillis(); if (reconciledPkg.prepareResult.system) { // Remove existing system package removePackageLI(oldPackage, true); - if (!disableSystemPackageLPw(oldPackage, pkg)) { + if (!disableSystemPackageLPw(oldPackage)) { // We didn't need to disable the .apk as a current system package, // which means we are replacing another update that is already // installed. We need to make sure to delete the older one's .apk. res.removedInfo.args = createInstallArgsForExisting( - oldPackage.applicationInfo.getCodePath(), - oldPackage.applicationInfo.getResourcePath(), - getAppDexInstructionSets(oldPackage.applicationInfo)); + oldPackage.getAppInfoCodePath(), + oldPackage.getAppInfoResourcePath(), + getAppDexInstructionSets(oldPackage.getPrimaryCpuAbi(), + oldPackage.getSecondaryCpuAbi())); } else { res.removedInfo.args = null; } - - // Update the package dynamic state if succeeded - // Now that the install succeeded make sure we remove data - // directories for any child package the update removed. - final int deletedChildCount = (oldPackage.childPackages != null) - ? oldPackage.childPackages.size() : 0; - final int newChildCount = (pkg.childPackages != null) - ? pkg.childPackages.size() : 0; - for (int i = 0; i < deletedChildCount; i++) { - PackageParser.Package deletedChildPkg = oldPackage.childPackages.get(i); - boolean childPackageDeleted = true; - for (int j = 0; j < newChildCount; j++) { - PackageParser.Package newChildPkg = pkg.childPackages.get(j); - if (deletedChildPkg.packageName.equals(newChildPkg.packageName)) { - childPackageDeleted = false; - break; - } - } - if (childPackageDeleted) { - PackageSetting ps1 = mSettings.getDisabledSystemPkgLPr( - deletedChildPkg.packageName); - if (ps1 != null && res.removedInfo.removedChildPackages != null) { - PackageRemovedInfo removedChildRes = res.removedInfo - .removedChildPackages.get(deletedChildPkg.packageName); - removePackageDataLIF(ps1, request.mAllUsers, removedChildRes, 0, - false); - removedChildRes.removedForAllUsers = mPackages.get(ps1.name) - == null; - } - } - } } else { try { // Settings will be written during the call to updateSettingsLI(). executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName, - true, request.mAllUsers, false, pkg); + true, request.mAllUsers, false, parsedPackage); } catch (SystemDeleteException e) { if (Build.IS_ENG) { throw new RuntimeException("Unexpected failure", e); @@ -15757,62 +15503,40 @@ public class PackageManagerService extends IPackageManager.Stub Slog.i(TAG, "upgrading pkg " + oldPackage + " is ASEC-hosted -> UNAVAILABLE"); } - final int[] uidArray = new int[]{oldPackage.applicationInfo.uid}; + final int[] uidArray = new int[]{oldPackage.getUid()}; final ArrayList<String> pkgList = new ArrayList<>(1); - pkgList.add(oldPackage.applicationInfo.packageName); + pkgList.add(oldPackage.getAppInfoPackageName()); sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null); } // Update the in-memory copy of the previous code paths. PackageSetting ps1 = mSettings.mPackages.get( - reconciledPkg.prepareResult.existingPackage.packageName); + reconciledPkg.prepareResult.existingPackage.getPackageName()); if ((reconciledPkg.installArgs.installFlags & PackageManager.DONT_KILL_APP) == 0) { if (ps1.mOldCodePaths == null) { ps1.mOldCodePaths = new ArraySet<>(); } - Collections.addAll(ps1.mOldCodePaths, oldPackage.baseCodePath); - if (oldPackage.splitCodePaths != null) { - Collections.addAll(ps1.mOldCodePaths, oldPackage.splitCodePaths); + Collections.addAll(ps1.mOldCodePaths, oldPackage.getBaseCodePath()); + if (oldPackage.getSplitCodePaths() != null) { + Collections.addAll(ps1.mOldCodePaths, oldPackage.getSplitCodePaths()); } } else { ps1.mOldCodePaths = null; } - if (ps1.childPackageNames != null) { - for (int i = ps1.childPackageNames.size() - 1; i >= 0; --i) { - final String childPkgName = ps1.childPackageNames.get(i); - final PackageSetting childPs = mSettings.mPackages.get(childPkgName); - childPs.mOldCodePaths = ps1.mOldCodePaths; - } - } if (reconciledPkg.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) { - PackageSetting ps2 = mSettings.getPackageLPr(pkg.packageName); + PackageSetting ps2 = mSettings.getPackageLPr( + parsedPackage.getPackageName()); if (ps2 != null) { res.removedInfo.removedForAllUsers = mPackages.get(ps2.name) == null; - if (res.removedInfo.removedChildPackages != null) { - final int childCount1 = res.removedInfo.removedChildPackages.size(); - // Iterate in reverse as we may modify the collection - for (int i = childCount1 - 1; i >= 0; i--) { - String childPackageName = - res.removedInfo.removedChildPackages.keyAt(i); - if (res.addedChildPackages.containsKey(childPackageName)) { - res.removedInfo.removedChildPackages.removeAt(i); - } else { - PackageRemovedInfo childInfo = res.removedInfo - .removedChildPackages.valueAt(i); - childInfo.removedForAllUsers = mPackages.get( - childInfo.removedPackage) == null; - } - } - } } } } } - commitReconciledScanResultLocked(reconciledPkg); + AndroidPackage pkg = commitReconciledScanResultLocked(reconciledPkg); updateSettingsLI(pkg, reconciledPkg.installArgs.installerPackageName, request.mAllUsers, res, reconciledPkg.installArgs.user, reconciledPkg.installArgs.installReason); @@ -15821,17 +15545,6 @@ public class PackageManagerService extends IPackageManager.Stub res.newUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); ps.setUpdateAvailable(false /*updateAvailable*/); } - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - PackageInstalledInfo childRes = res.addedChildPackages.get( - childPkg.packageName); - PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName); - if (childPs != null) { - childRes.newUsers = childPs.queryInstalledUsers( - mUserManager.getUserIds(), true); - } - } if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { updateSequenceNumberLP(ps, res.newUsers); updateInstantAppInstallerLocked(packageName); @@ -15891,33 +15604,31 @@ public class PackageManagerService extends IPackageManager.Stub request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED); request.installResult.installerPackageName = request.args.installerPackageName; - final String packageName = prepareResult.packageToScan.packageName; + final String packageName = prepareResult.packageToScan.getPackageName(); prepareResults.put(packageName, prepareResult); installResults.put(packageName, request.installResult); installArgs.put(packageName, request.args); try { - final List<ScanResult> scanResults = scanPackageTracedLI( + final ScanResult result = scanPackageTracedLI( prepareResult.packageToScan, prepareResult.parseFlags, prepareResult.scanFlags, System.currentTimeMillis(), request.args.user); - for (ScanResult result : scanResults) { - if (null != preparedScans.put(result.pkgSetting.pkg.packageName, result)) { - request.installResult.setError( - PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE, - "Duplicate package " + result.pkgSetting.pkg.packageName - + " in multi-package install request."); - return; - } - createdAppId.put(packageName, optimisticallyRegisterAppId(result)); - versionInfos.put(result.pkgSetting.pkg.packageName, - getSettingsVersionForPackage(result.pkgSetting.pkg)); - if (result.staticSharedLibraryInfo != null) { - final PackageSetting sharedLibLatestVersionSetting = - getSharedLibLatestVersionSetting(result); - if (sharedLibLatestVersionSetting != null) { - lastStaticSharedLibSettings.put(result.pkgSetting.pkg.packageName, - sharedLibLatestVersionSetting); - } + if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) { + request.installResult.setError( + PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE, + "Duplicate package " + result.pkgSetting.pkg.getPackageName() + + " in multi-package install request."); + return; + } + createdAppId.put(packageName, optimisticallyRegisterAppId(result)); + versionInfos.put(result.pkgSetting.pkg.getPackageName(), + getSettingsVersionForPackage(result.pkgSetting.pkg)); + if (result.staticSharedLibraryInfo != null) { + final PackageSetting sharedLibLatestVersionSetting = + getSharedLibLatestVersionSetting(result); + if (sharedLibLatestVersionSetting != null) { + lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(), + sharedLibLatestVersionSetting); } } } catch (PackageManagerException e) { @@ -15960,7 +15671,8 @@ public class PackageManagerService extends IPackageManager.Stub } finally { if (!success) { for (ScanResult result : preparedScans.values()) { - if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) { + if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(), + false)) { cleanUpAppIdCreation(result); } } @@ -15990,16 +15702,16 @@ public class PackageManagerService extends IPackageManager.Stub for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags & PackageManagerService.SCAN_AS_INSTANT_APP) != 0); - final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg; - final String packageName = pkg.packageName; + final AndroidPackage pkg = reconciledPkg.pkgSetting.pkg; + final String packageName = pkg.getPackageName(); prepareAppDataAfterInstallLIF(pkg); if (reconciledPkg.prepareResult.clearCodeCache) { clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); } if (reconciledPkg.prepareResult.replace) { - mDexManager.notifyPackageUpdated(pkg.packageName, - pkg.baseCodePath, pkg.splitCodePaths); + mDexManager.notifyPackageUpdated(pkg.getPackageName(), + pkg.getBaseCodePath(), pkg.getSplitCodePaths()); } // Prepare the application profiles for the new code paths. @@ -16013,7 +15725,7 @@ public class PackageManagerService extends IPackageManager.Stub // Check whether we need to dexopt the app. // // NOTE: it is IMPORTANT to call dexopt: - // - after doRename which will sync the package data from PackageParser.Package and + // - after doRename which will sync the package data from AndroidPackage and // its corresponding ApplicationInfo. // - after installNewPackageLIF or replacePackageLIF which will update result with the // uid of the application (pkg.applicationInfo.uid). @@ -16032,7 +15744,7 @@ public class PackageManagerService extends IPackageManager.Stub final boolean performDexopt = (!instantApp || Global.getInt(mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) - && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0); + && ((pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) == 0); if (performDexopt) { // Compile the layout resources. @@ -16080,8 +15792,8 @@ public class PackageManagerService extends IPackageManager.Stub public final int scanFlags; public final int parseFlags; @Nullable /* The original Package if it is being replaced, otherwise {@code null} */ - public final PackageParser.Package existingPackage; - public final PackageParser.Package packageToScan; + public final AndroidPackage existingPackage; + public final ParsedPackage packageToScan; public final boolean clearCodeCache; public final boolean system; /* The original package name if it was changed during an update, otherwise {@code null}. */ @@ -16090,14 +15802,13 @@ public class PackageManagerService extends IPackageManager.Stub public final PackageFreezer freezer; public final PackageSetting originalPs; public final PackageSetting disabledPs; - public final PackageSetting[] childPackageSettings; private PrepareResult(int installReason, String volumeUuid, String installerPackageName, UserHandle user, boolean replace, int scanFlags, - int parseFlags, PackageParser.Package existingPackage, - PackageParser.Package packageToScan, boolean clearCodeCache, boolean system, + int parseFlags, AndroidPackage existingPackage, + ParsedPackage packageToScan, boolean clearCodeCache, boolean system, String renamedPackage, PackageFreezer freezer, PackageSetting originalPs, - PackageSetting disabledPs, PackageSetting[] childPackageSettings) { + PackageSetting disabledPs) { this.installReason = installReason; this.volumeUuid = volumeUuid; this.installerPackageName = installerPackageName; @@ -16113,7 +15824,6 @@ public class PackageManagerService extends IPackageManager.Stub this.freezer = freezer; this.originalPs = originalPs; this.disabledPs = disabledPs; - this.childPackageSettings = childPackageSettings; } } @@ -16194,10 +15904,10 @@ public class PackageManagerService extends IPackageManager.Stub pp.setCallback(mPackageParserCallback); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); - final PackageParser.Package pkg; + ParsedPackage parsedPackage; try { - pkg = pp.parsePackage(tmpPackageFile, parseFlags); - DexMetadataHelper.validatePackageDexMetadata(pkg); + parsedPackage = pp.parseParsedPackage(tmpPackageFile, parseFlags, false); + DexMetadataHelper.validatePackageDexMetadata(parsedPackage); } catch (PackageParserException e) { throw new PrepareFailure("Failed parse during installPackageLI", e); } finally { @@ -16206,23 +15916,23 @@ public class PackageManagerService extends IPackageManager.Stub // Instant apps have several additional install-time checks. if (instantApp) { - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) { - Slog.w(TAG, - "Instant app package " + pkg.packageName + " does not target at least O"); + if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) { + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + + " does not target at least O"); throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID, "Instant app package must target at least O"); } - if (pkg.mSharedUserId != null) { - Slog.w(TAG, "Instant app package " + pkg.packageName + if (parsedPackage.getSharedUserId() != null) { + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + " may not declare sharedUserId."); throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID, "Instant app package may not declare a sharedUserId"); } } - if (pkg.applicationInfo.isStaticSharedLibrary()) { + if (parsedPackage.isStaticSharedLibrary()) { // Static shared libraries have synthetic package names - renameStaticSharedLibraryPackage(pkg); + renameStaticSharedLibraryPackage(parsedPackage); // No static shared libs on external storage if (onExternal) { @@ -16232,42 +15942,16 @@ public class PackageManagerService extends IPackageManager.Stub } } - // If we are installing a clustered package add results for the children - if (pkg.childPackages != null) { - synchronized (mLock) { - final int childCount = pkg.childPackages.size(); - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - PackageInstalledInfo childRes = new PackageInstalledInfo(); - childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED); - childRes.pkg = childPkg; - childRes.name = childPkg.packageName; - PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName); - if (childPs != null) { - childRes.origUsers = childPs.queryInstalledUsers( - mUserManager.getUserIds(), true); - } - if ((mPackages.containsKey(childPkg.packageName))) { - childRes.removedInfo = new PackageRemovedInfo(this); - childRes.removedInfo.removedPackage = childPkg.packageName; - childRes.removedInfo.installerPackageName = childPs.installerPackageName; - } - if (res.addedChildPackages == null) { - res.addedChildPackages = new ArrayMap<>(); - } - res.addedChildPackages.put(childPkg.packageName, childRes); - } - } - } - // If package doesn't declare API override, mark that we have an install // time CPU ABI override. - if (TextUtils.isEmpty(pkg.cpuAbiOverride)) { - pkg.cpuAbiOverride = args.abiOverride; + // TODO(b/135203078): Isn't this always true because cpuAbiOverride isn't assigned during + // parsing? + if (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride())) { + parsedPackage.setCpuAbiOverride(args.abiOverride); } - String pkgName = res.name = pkg.packageName; - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) { + String pkgName = res.name = parsedPackage.getPackageName(); + if ((parsedPackage.getFlags() & ApplicationInfo.FLAG_TEST_ONLY) != 0) { if ((installFlags & PackageManager.INSTALL_ALLOW_TEST) == 0) { throw new PrepareFailure(INSTALL_FAILED_TEST_ONLY, "installPackageLI"); } @@ -16276,17 +15960,17 @@ public class PackageManagerService extends IPackageManager.Stub try { // either use what we've been given or parse directly from the APK if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) { - pkg.setSigningDetails(args.signingDetails); + parsedPackage.setSigningDetails(args.signingDetails); } else { - PackageParser.collectCertificates(pkg, false /* skipVerify */); + ApkParseUtils.collectCertificates(parsedPackage, false /* skipVerify */); } } catch (PackageParserException e) { throw new PrepareFailure("Failed collect during installPackageLI", e); } - if (instantApp && pkg.mSigningDetails.signatureSchemeVersion + if (instantApp && parsedPackage.getSigningDetails().signatureSchemeVersion < SignatureSchemeVersion.SIGNING_BLOCK_V2) { - Slog.w(TAG, "Instant app package " + pkg.packageName + Slog.w(TAG, "Instant app package " + parsedPackage.getPackageName() + " is not signed with at least APK Signature Scheme v2"); throw new PrepareFailure(INSTALL_FAILED_INSTANT_APP_INVALID, "Instant app package must be signed with APK Signature Scheme v2 or greater"); @@ -16300,15 +15984,15 @@ public class PackageManagerService extends IPackageManager.Stub // Check if installing already existing package if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { String oldName = mSettings.getRenamedPackageLPr(pkgName); - if (pkg.mOriginalPackages != null - && pkg.mOriginalPackages.contains(oldName) + if (parsedPackage.getOriginalPackages() != null + && parsedPackage.getOriginalPackages().contains(oldName) && mPackages.containsKey(oldName)) { // This package is derived from an original package, // and this device has been updating from that original // name. We must continue using the original name, so // rename the new package here. - pkg.setPackageName(oldName); - pkgName = pkg.packageName; + parsedPackage.setPackageName(oldName); + pkgName = parsedPackage.getPackageName(); replace = true; if (DEBUG_INSTALL) { Slog.d(TAG, "Replacing existing renamed package: oldName=" @@ -16321,43 +16005,27 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); } - // Child packages are installed through the parent package - if (pkg.parentPackage != null) { - throw new PrepareFailure( - PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, - "Package " + pkg.packageName + " is child of package " - + pkg.parentPackage.parentPackage + ". Child packages " - + "can be updated only through the parent package."); - } - if (replace) { // Prevent apps opting out from runtime permissions - PackageParser.Package oldPackage = mPackages.get(pkgName); - final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion; - final int newTargetSdk = pkg.applicationInfo.targetSdkVersion; + AndroidPackage oldPackage = mPackages.get(pkgName); + final int oldTargetSdk = oldPackage.getTargetSdkVersion(); + final int newTargetSdk = parsedPackage.getTargetSdkVersion(); if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1 && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) { throw new PrepareFailure( PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE, - "Package " + pkg.packageName + " new target SDK " + newTargetSdk + "Package " + parsedPackage.getPackageName() + + " new target SDK " + newTargetSdk + " doesn't support runtime permissions but the old" + " target SDK " + oldTargetSdk + " does."); } // Prevent persistent apps from being updated - if (((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0) + if (((oldPackage.getFlags() & ApplicationInfo.FLAG_PERSISTENT) != 0) && ((installFlags & PackageManager.INSTALL_STAGED) == 0)) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_INVALID_APK, - "Package " + oldPackage.packageName + " is a persistent app. " + "Package " + oldPackage.getPackageName() + " is a persistent app. " + "Persistent apps are not updateable."); } - // Prevent installing of child packages - if (oldPackage.parentPackage != null) { - throw new PrepareFailure( - PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME, - "Package " + pkg.packageName + " is child of package " - + oldPackage.parentPackage + ". Child packages " - + "can be updated only through the parent package."); - } } } @@ -16370,8 +16038,8 @@ public class PackageManagerService extends IPackageManager.Stub // of the same package, therefore we need to compare signatures against // the package setting for the latest library version. PackageSetting signatureCheckPs = ps; - if (pkg.applicationInfo.isStaticSharedLibrary()) { - SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(pkg); + if (parsedPackage.isStaticSharedLibrary()) { + SharedLibraryInfo libraryInfo = getLatestSharedLibraVersionLPr(parsedPackage); if (libraryInfo != null) { signatureCheckPs = mSettings.getPackageLPr(libraryInfo.getPackageName()); } @@ -16382,23 +16050,23 @@ public class PackageManagerService extends IPackageManager.Stub // bail early here before tripping over redefined permissions. final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) { - if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) { + if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " - + pkg.packageName + " upgrade keys do not match the " + + parsedPackage.getPackageName() + " upgrade keys do not match the " + "previously installed version"); } } else { try { - final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg); - final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg); + final boolean compareCompat = isCompatSignatureUpdateNeeded(parsedPackage); + final boolean compareRecover = isRecoverSignatureUpdateNeeded( + parsedPackage); // We don't care about disabledPkgSetting on install for now. - final boolean compatMatch = verifySignatures( - signatureCheckPs, null, pkg.mSigningDetails, compareCompat, - compareRecover); + final boolean compatMatch = verifySignatures(signatureCheckPs, null, + parsedPackage.getSigningDetails(), compareCompat, compareRecover); // The new KeySets will be re-added later in the scanning process. if (compatMatch) { synchronized (mLock) { - ksms.removeAppKeySetDataLPw(pkg.packageName); + ksms.removeAppKeySetDataLPw(parsedPackage.getPackageName()); } } } catch (PackageManagerException e) { @@ -16406,27 +16074,25 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (ps.pkg != null && ps.pkg.applicationInfo != null) { - systemApp = (ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_SYSTEM) != 0; + if (ps.pkg != null) { + systemApp = (ps.pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0; } res.origUsers = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } - int N = pkg.permissions.size(); + int N = ArrayUtils.size(parsedPackage.getPermissions()); for (int i = N - 1; i >= 0; i--) { - final PackageParser.Permission perm = pkg.permissions.get(i); - final BasePermission bp = - (BasePermission) mPermissionManager.getPermissionTEMP(perm.info.name); + final ParsedPermission perm = parsedPackage.getPermissions().get(i); + final BasePermission bp = mPermissionManager.getPermissionTEMP(perm.getName()); // Don't allow anyone but the system to define ephemeral permissions. - if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 + if ((perm.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0 && !systemApp) { - Slog.w(TAG, "Non-System package " + pkg.packageName + Slog.w(TAG, "Non-System package " + parsedPackage.getPackageName() + " attempting to delcare ephemeral permission " - + perm.info.name + "; Removing ephemeral."); - perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT; + + perm.getName() + "; Removing ephemeral."); + perm.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_INSTANT; } // Check whether the newly-scanned package wants to define an already-defined perm @@ -16438,26 +16104,27 @@ public class PackageManagerService extends IPackageManager.Stub final String sourcePackageName = bp.getSourcePackageName(); final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting(); final KeySetManagerService ksms = mSettings.mKeySetManagerService; - if (sourcePackageName.equals(pkg.packageName) + if (sourcePackageName.equals(parsedPackage.getPackageName()) && (ksms.shouldCheckUpgradeKeySetLocked( sourcePackageSetting, scanFlags))) { - sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg); + sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, parsedPackage); } else { // in the event of signing certificate rotation, we need to see if the // package's certificate has rotated from the current one, or if it is an // older certificate with which the current is ok with sharing permissions if (sourcePackageSetting.signatures.mSigningDetails.checkCapability( - pkg.mSigningDetails, + parsedPackage.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION)) { sigsOk = true; - } else if (pkg.mSigningDetails.checkCapability( + } else if (parsedPackage.getSigningDetails().checkCapability( sourcePackageSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.PERMISSION)) { // the scanned package checks out, has signing certificate rotation // history, and is newer; bring it over - sourcePackageSetting.signatures.mSigningDetails = pkg.mSigningDetails; + sourcePackageSetting.signatures.mSigningDetails = + parsedPackage.getSigningDetails(); sigsOk = true; } else { sigsOk = false; @@ -16469,30 +16136,31 @@ public class PackageManagerService extends IPackageManager.Stub // redefinitions. if (!sourcePackageName.equals("android")) { throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PERMISSION, "Package " - + pkg.packageName + + parsedPackage.getPackageName() + " attempting to redeclare permission " - + perm.info.name + " already owned by " + + perm.getName() + " already owned by " + sourcePackageName) - .conflictsWithExistingPermission(perm.info.name, + .conflictsWithExistingPermission(perm.getName(), sourcePackageName); } else { - Slog.w(TAG, "Package " + pkg.packageName + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " attempting to redeclare system permission " - + perm.info.name + "; ignoring new declaration"); - pkg.permissions.remove(i); + + perm.getName() + "; ignoring new declaration"); + parsedPackage.removePermission(i); } - } else if (!PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) { + } else if (!PLATFORM_PACKAGE_NAME.equals(parsedPackage.getPackageName())) { // Prevent apps to change protection level to dangerous from any other // type as this would allow a privilege escalation where an app adds a // normal/signature permission in other app's group and later redefines // it as dangerous leading to the group auto-grant. - if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) + if ((perm.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) == PermissionInfo.PROTECTION_DANGEROUS) { if (bp != null && !bp.isRuntime()) { - Slog.w(TAG, "Package " + pkg.packageName + " trying to change a " - + "non-runtime permission " + perm.info.name + Slog.w(TAG, "Package " + parsedPackage.getPackageName() + + " trying to change a non-runtime permission " + + perm.getName() + " to runtime; keeping old protection level"); - perm.info.protectionLevel = bp.getProtectionLevel(); + perm.protectionLevel = bp.getProtectionLevel(); } } } @@ -16526,8 +16194,8 @@ public class PackageManagerService extends IPackageManager.Stub // We moved the entire application as-is, so bring over the // previously derived ABI information. - pkg.applicationInfo.primaryCpuAbi = ps.primaryCpuAbiString; - pkg.applicationInfo.secondaryCpuAbi = ps.secondaryCpuAbiString; + parsedPackage.setPrimaryCpuAbi(ps.primaryCpuAbiString) + .setSecondaryCpuAbi(ps.secondaryCpuAbiString); } } else { @@ -16535,14 +16203,14 @@ public class PackageManagerService extends IPackageManager.Stub scanFlags |= SCAN_NO_DEX; try { - String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ? - args.abiOverride : pkg.cpuAbiOverride); - final boolean extractNativeLibs = !pkg.isLibrary(); + String abiOverride = (TextUtils.isEmpty(parsedPackage.getCpuAbiOverride()) + ? args.abiOverride : parsedPackage.getCpuAbiOverride()); + final boolean extractNativeLibs = !parsedPackage.isLibrary(); final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi = mInjector.getAbiHelper().derivePackageAbi( - pkg, abiOverride, extractNativeLibs); - derivedAbi.first.applyTo(pkg); - derivedAbi.second.applyTo(pkg); + parsedPackage, abiOverride, extractNativeLibs); + derivedAbi.first.applyTo(parsedPackage); + derivedAbi.second.applyTo(parsedPackage); } catch (PackageManagerException pme) { Slog.e(TAG, "Error deriving application ABI", pme); throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, @@ -16550,19 +16218,19 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (!args.doRename(res.returnCode, pkg)) { + if (!args.doRename(res.returnCode, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename"); } try { - setUpFsVerityIfPossible(pkg); + setUpFsVerityIfPossible(parsedPackage); } catch (InstallerException | IOException | DigestException | NoSuchAlgorithmException e) { throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR, "Failed to set up verity: " + e); } if (!instantApp) { - startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg); + startIntentFilterVerifications(args.user.getIdentifier(), replace, parsedPackage); } else { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, "Not verifying instant app install for app links: " + pkgName); @@ -16572,7 +16240,7 @@ public class PackageManagerService extends IPackageManager.Stub freezePackageForInstall(pkgName, installFlags, "installPackageLI"); boolean shouldCloseFreezerBeforeReturn = true; try { - final PackageParser.Package existingPackage; + final AndroidPackage existingPackage; String renamedPackage = null; boolean sysPkg = false; String targetVolumeUuid = volumeUuid; @@ -16583,14 +16251,15 @@ public class PackageManagerService extends IPackageManager.Stub final PackageSetting[] childPackages; if (replace) { targetVolumeUuid = null; - if (pkg.applicationInfo.isStaticSharedLibrary()) { + if (parsedPackage.isStaticSharedLibrary()) { // Static libs have a synthetic package name containing the version // and cannot be updated as an update would get a new package name, // unless this is the exact same version code which is useful for // development. - PackageParser.Package existingPkg = mPackages.get(pkg.packageName); + AndroidPackage existingPkg = mPackages.get(parsedPackage.getPackageName()); if (existingPkg != null - && existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) { + && existingPkg.getLongVersionCode() + != parsedPackage.getLongVersionCode()) { throw new PrepareFailure(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring " + "static-shared libs cannot be updated"); @@ -16599,8 +16268,8 @@ public class PackageManagerService extends IPackageManager.Stub final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0; - final PackageParser.Package oldPackage; - final String pkgName11 = pkg.packageName; + final AndroidPackage oldPackage; + final String pkgName11 = parsedPackage.getPackageName(); final int[] allUsers; final int[] installedUsers; @@ -16608,8 +16277,9 @@ public class PackageManagerService extends IPackageManager.Stub oldPackage = mPackages.get(pkgName11); existingPackage = oldPackage; if (DEBUG_INSTALL) { + // TODO(b/135203078): PackageImpl.toString() Slog.d(TAG, - "replacePackageLI: new=" + pkg + ", old=" + oldPackage); + "replacePackageLI: new=" + parsedPackage + ", old=" + oldPackage); } ps = mSettings.mPackages.get(pkgName11); @@ -16618,17 +16288,18 @@ public class PackageManagerService extends IPackageManager.Stub // verify signatures are valid final KeySetManagerService ksms = mSettings.mKeySetManagerService; if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) { - if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) { + if (!ksms.checkUpgradeKeySetLocked(ps, parsedPackage)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "New package not signed by keys specified by upgrade-keysets: " + pkgName11); } } else { // default to original signature matching - if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails, + if (!parsedPackage.getSigningDetails().checkCapability( + oldPackage.getSigningDetails(), SigningDetails.CertCapabilities.INSTALLED_DATA) - && !oldPackage.mSigningDetails.checkCapability( - pkg.mSigningDetails, + && !oldPackage.getSigningDetails().checkCapability( + parsedPackage.getSigningDetails(), SigningDetails.CertCapabilities.ROLLBACK)) { throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "New package has a different signature: " + pkgName11); @@ -16636,13 +16307,13 @@ public class PackageManagerService extends IPackageManager.Stub } // don't allow a system upgrade unless the upgrade hash matches - if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) { + if (oldPackage.getRestrictUpdateHash() != null && oldPackage.isSystem()) { final byte[] digestBytes; try { final MessageDigest digest = MessageDigest.getInstance("SHA-512"); - updateDigest(digest, new File(pkg.baseCodePath)); - if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { - for (String path : pkg.splitCodePaths) { + updateDigest(digest, new File(parsedPackage.getBaseCodePath())); + if (!ArrayUtils.isEmpty(parsedPackage.getSplitCodePaths())) { + for (String path : parsedPackage.getSplitCodePaths()) { updateDigest(digest, new File(path)); } } @@ -16651,21 +16322,25 @@ public class PackageManagerService extends IPackageManager.Stub throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, "Could not compute hash: " + pkgName11); } - if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) { + if (!Arrays.equals(oldPackage.getRestrictUpdateHash(), digestBytes)) { throw new PrepareFailure(INSTALL_FAILED_INVALID_APK, "New package fails restrict-update check: " + pkgName11); } // retain upgrade restriction - pkg.restrictUpdateHash = oldPackage.restrictUpdateHash; + parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash()); } // Check for shared user id changes - String invalidPackageName = - getParentOrChildPackageChangedSharedUser(oldPackage, pkg); + String invalidPackageName = null; + if (!Objects.equals(oldPackage.getSharedUserId(), + parsedPackage.getSharedUserId())) { + invalidPackageName = parsedPackage.getPackageName(); + } + if (invalidPackageName != null) { throw new PrepareFailure(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, "Package " + invalidPackageName + " tried to change user " - + oldPackage.mSharedUserId); + + oldPackage.getSharedUserId()); } // In case of rollback, remember per-user/profile install state @@ -16698,10 +16373,10 @@ public class PackageManagerService extends IPackageManager.Stub // Update what is removed res.removedInfo = new PackageRemovedInfo(this); - res.removedInfo.uid = oldPackage.applicationInfo.uid; - res.removedInfo.removedPackage = oldPackage.packageName; + res.removedInfo.uid = oldPackage.getUid(); + res.removedInfo.removedPackage = oldPackage.getPackageName(); res.removedInfo.installerPackageName = ps.installerPackageName; - res.removedInfo.isStaticSharedLib = pkg.staticSharedLibName != null; + res.removedInfo.isStaticSharedLib = parsedPackage.getStaticSharedLibName() != null; res.removedInfo.isUpdate = true; res.removedInfo.origUsers = installedUsers; res.removedInfo.installReasons = new SparseArray<>(installedUsers.length); @@ -16710,52 +16385,6 @@ public class PackageManagerService extends IPackageManager.Stub res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId)); } - childPackages = mSettings.getChildSettingsLPr(ps); - if (childPackages != null) { - for (PackageSetting childPs : childPackages) { - boolean childPackageUpdated = false; - PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg; - if (res.addedChildPackages != null) { - PackageInstalledInfo childRes = res.addedChildPackages.get( - childPkg.packageName); - if (childRes != null) { - childRes.removedInfo.uid = childPkg.applicationInfo.uid; - childRes.removedInfo.removedPackage = childPkg.packageName; - if (childPs != null) { - childRes.removedInfo.installerPackageName = - childPs.installerPackageName; - } - childRes.removedInfo.isUpdate = true; - childRes.removedInfo.installReasons = - res.removedInfo.installReasons; - childPackageUpdated = true; - } - } - if (!childPackageUpdated) { - PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this); - childRemovedRes.removedPackage = childPkg.packageName; - if (childPs != null) { - childRemovedRes.installerPackageName = childPs.installerPackageName; - } - childRemovedRes.isUpdate = false; - childRemovedRes.dataRemoved = true; - synchronized (mLock) { - if (childPs != null) { - childRemovedRes.origUsers = childPs.queryInstalledUsers( - allUsers, - true); - } - } - if (res.removedInfo.removedChildPackages == null) { - res.removedInfo.removedChildPackages = new ArrayMap<>(); - } - res.removedInfo.removedChildPackages.put(childPkg.packageName, - childRemovedRes); - } - } - } - - sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { // Set the system/privileged/oem/vendor/product flags as needed @@ -16774,41 +16403,30 @@ public class PackageManagerService extends IPackageManager.Stub | (odm ? SCAN_AS_ODM : 0); if (DEBUG_INSTALL) { - Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg + Slog.d(TAG, "replaceSystemPackageLI: new=" + parsedPackage + ", old=" + oldPackage); } res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); - pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, - ApplicationInfo.FLAG_UPDATED_SYSTEM_APP); + parsedPackage.setUpdatedSystemApp(true); targetParseFlags = systemParseFlags; targetScanFlags = systemScanFlags; } else { // non system replace replace = true; if (DEBUG_INSTALL) { Slog.d(TAG, - "replaceNonSystemPackageLI: new=" + pkg + ", old=" + "replaceNonSystemPackageLI: new=" + parsedPackage + ", old=" + oldPackage); } - - String pkgName1 = oldPackage.packageName; - boolean deletedPkg = true; - boolean addedPkg = false; - boolean updatedSettings = false; - - final long origUpdateTime = (pkg.mExtras != null) - ? ((PackageSetting) pkg.mExtras).lastUpdateTime : 0; - } } else { // new package install ps = null; - childPackages = null; disabledPs = null; replace = false; existingPackage = null; // Remember this for later, in case we need to rollback this install - String pkgName1 = pkg.packageName; + String pkgName1 = parsedPackage.getPackageName(); - if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg); + if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + parsedPackage); // TODO(patb): MOVE TO RECONCILE synchronized (mLock) { @@ -16835,9 +16453,9 @@ public class PackageManagerService extends IPackageManager.Stub shouldCloseFreezerBeforeReturn = false; return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName, - args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg, - replace /* clearCodeCache */, sysPkg, renamedPackage, freezer, - ps, disabledPs, childPackages); + args.user, replace, targetScanFlags, targetParseFlags, existingPackage, + parsedPackage, replace /* clearCodeCache */, sysPkg, renamedPackage, freezer, + ps, disabledPs); } finally { if (shouldCloseFreezerBeforeReturn) { freezer.close(); @@ -16852,7 +16470,7 @@ public class PackageManagerService extends IPackageManager.Stub * <p>When the feature flag is set to legacy mode, only APK is supported (with some experimental * kernel patches). In normal mode, all file format can be supported. */ - private void setUpFsVerityIfPossible(PackageParser.Package pkg) throws InstallerException, + private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException, PrepareFailure, IOException, DigestException, NoSuchAlgorithmException { final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled(); final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled(); @@ -16864,11 +16482,11 @@ public class PackageManagerService extends IPackageManager.Stub ArrayMap<String, String> fsverityCandidates = new ArrayMap<>(); if (legacyMode) { synchronized (mLock) { - final PackageSetting ps = mSettings.mPackages.get(pkg.packageName); + final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); if (ps != null && ps.isPrivileged()) { - fsverityCandidates.put(pkg.baseCodePath, null); - if (pkg.splitCodePaths != null) { - for (String splitPath : pkg.splitCodePaths) { + fsverityCandidates.put(pkg.getBaseCodePath(), null); + if (pkg.getSplitCodePaths() != null) { + for (String splitPath : pkg.getSplitCodePaths()) { fsverityCandidates.put(splitPath, null); } } @@ -16877,16 +16495,17 @@ public class PackageManagerService extends IPackageManager.Stub } else { // NB: These files will become only accessible if the signing key is loaded in kernel's // .fs-verity keyring. - fsverityCandidates.put(pkg.baseCodePath, - VerityUtils.getFsveritySignatureFilePath(pkg.baseCodePath)); + fsverityCandidates.put(pkg.getBaseCodePath(), + VerityUtils.getFsveritySignatureFilePath(pkg.getBaseCodePath())); - final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk(pkg.baseCodePath); + final String dmPath = DexMetadataHelper.buildDexMetadataPathForApk( + pkg.getBaseCodePath()); if (new File(dmPath).exists()) { fsverityCandidates.put(dmPath, VerityUtils.getFsveritySignatureFilePath(dmPath)); } - if (pkg.splitCodePaths != null) { - for (String path : pkg.splitCodePaths) { + if (pkg.getSplitCodePaths() != null) { + for (String path : pkg.getSplitCodePaths()) { fsverityCandidates.put(path, VerityUtils.getFsveritySignatureFilePath(path)); final String splitDmPath = DexMetadataHelper.buildDexMetadataPathForApk(path); @@ -16940,8 +16559,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void startIntentFilterVerifications(int userId, boolean replacing, - PackageParser.Package pkg) { + private void startIntentFilterVerifications(int userId, boolean replacing, AndroidPackage pkg) { if (mIntentFilterVerifierComponent == null) { Slog.w(TAG, "No IntentFilter verification will not be done as " + "there is no IntentFilterVerifier available!"); @@ -16954,29 +16572,29 @@ public class PackageManagerService extends IPackageManager.Stub (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId); Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS); - msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid); + msg.obj = new IFVerificationParams( + pkg.getPackageName(), + hasDomainURLs(pkg), + pkg.getActivities(), + replacing, + userId, + verifierUid + ); mHandler.sendMessage(msg); - - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS); - msg.obj = new IFVerificationParams(childPkg, replacing, userId, verifierUid); - mHandler.sendMessage(msg); - } } private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean replacing, - PackageParser.Package pkg) { - int size = pkg.activities.size(); + String packageName, + boolean hasDomainUrls, + List<ParsedActivity> activities) { + int size = activities.size(); if (size == 0) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "No activity, so no need to verify any IntentFilter!"); return; } - final boolean hasDomainURLs = hasDomainURLs(pkg); - if (!hasDomainURLs) { + if (!hasDomainUrls) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "No domain URLs, so no need to verify any IntentFilter!"); return; @@ -16987,7 +16605,6 @@ public class PackageManagerService extends IPackageManager.Stub + " Activities needs verification ..."); int count = 0; - final String packageName = pkg.packageName; synchronized (mLock) { // If this is a new install and we see that we've already run verification for this @@ -17006,8 +16623,8 @@ public class PackageManagerService extends IPackageManager.Stub // If any filters need to be verified, then all need to be. boolean needToVerify = false; - for (PackageParser.Activity a : pkg.activities) { - for (ActivityIntentInfo filter : a.intents) { + for (ParsedActivity a : activities) { + for (ParsedActivityIntentInfo filter : a.intents) { if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) { Slog.d(TAG, @@ -17021,8 +16638,8 @@ public class PackageManagerService extends IPackageManager.Stub if (needToVerify) { final int verificationId = mIntentFilterVerificationToken++; - for (PackageParser.Activity a : pkg.activities) { - for (ActivityIntentInfo filter : a.intents) { + for (ParsedActivity a : activities) { + for (ParsedActivityIntentInfo filter : a.intents) { if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) { if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Verification needed for IntentFilter:" + filter.toString()); @@ -17048,9 +16665,8 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mLock") - private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) { - final ComponentName cn = filter.activity.getComponentName(); - final String packageName = cn.getPackageName(); + private boolean needsNetworkVerificationLPr(ParsedActivityIntentInfo filter) { + final String packageName = filter.getPackageName(); IntentFilterVerificationInfo ivi = mSettings.getIntentFilterVerificationLPr( packageName); @@ -17070,45 +16686,45 @@ public class PackageManagerService extends IPackageManager.Stub } } - private static boolean isExternal(PackageParser.Package pkg) { - return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; + private static boolean isExternal(AndroidPackage pkg) { + return (pkg.getFlags() & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } private static boolean isExternal(PackageSetting ps) { return (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } - static boolean isSystemApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + static boolean isSystemApp(AndroidPackage pkg) { + return (pkg.getFlags() & ApplicationInfo.FLAG_SYSTEM) != 0; } - private static boolean isPrivilegedApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + private static boolean isPrivilegedApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } - private static boolean isOemApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; + private static boolean isOemApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_OEM) != 0; } - private static boolean isVendorApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; + private static boolean isVendorApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0; } - private static boolean isProductApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; + private static boolean isProductApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0; } - private static boolean isSystemExtApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags + private static boolean isSystemExtApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT) != 0; } - private static boolean isOdmApp(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; + private static boolean isOdmApp(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; } - private static boolean hasDomainURLs(PackageParser.Package pkg) { - return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; + private static boolean hasDomainURLs(AndroidPackage pkg) { + return (pkg.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; } private static boolean isSystemApp(PackageSetting ps) { @@ -17119,12 +16735,12 @@ public class PackageManagerService extends IPackageManager.Stub return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } - private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) { + private VersionInfo getSettingsVersionForPackage(AndroidPackage pkg) { if (isExternal(pkg)) { - if (TextUtils.isEmpty(pkg.volumeUuid)) { + if (TextUtils.isEmpty(pkg.getVolumeUuid())) { return mSettings.getExternalVersion(); } else { - return mSettings.findOrCreateVersion(pkg.volumeUuid); + return mSettings.findOrCreateVersion(pkg.getVolumeUuid()); } } else { return mSettings.getInternalVersion(); @@ -17132,6 +16748,7 @@ public class PackageManagerService extends IPackageManager.Stub } private void deleteTempPackageFiles() { + // TODO: Is this used? final FilenameFilter filter = (dir, name) -> name.startsWith("vmdl") && name.endsWith(".tmp"); } @@ -17265,11 +16882,11 @@ public class PackageManagerService extends IPackageManager.Stub }); } - private String resolveExternalPackageNameLPr(PackageParser.Package pkg) { - if (pkg.staticSharedLibName != null) { - return pkg.manifestPackageName; + private String resolveExternalPackageNameLPr(AndroidPackage pkg) { + if (pkg.getStaticSharedLibName() != null) { + return pkg.getManifestPackageName(); } - return pkg.packageName; + return pkg.getPackageName(); } @GuardedBy("mLock") @@ -17476,7 +17093,7 @@ public class PackageManagerService extends IPackageManager.Stub final PackageSetting uninstalledPs; final PackageSetting disabledSystemPs; - final PackageParser.Package pkg; + final AndroidPackage pkg; // for the uninstall-updates case and restricted profiles, remember the per- // user handle installed state @@ -17508,9 +17125,9 @@ public class PackageManagerService extends IPackageManager.Stub allUsers = mUserManager.getUserIds(); - if (pkg != null && pkg.staticSharedLibName != null) { - SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(pkg.staticSharedLibName, - pkg.staticSharedLibVersion); + if (pkg != null && pkg.getStaticSharedLibName() != null) { + SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr( + pkg.getStaticSharedLibName(), pkg.getStaticSharedLibVersion()); if (libraryInfo != null) { for (int currUserId : allUsers) { if (removeUser != UserHandle.USER_ALL && removeUser != currUserId) { @@ -17519,7 +17136,7 @@ public class PackageManagerService extends IPackageManager.Stub List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr( libraryInfo, 0, currUserId); if (!ArrayUtils.isEmpty(libClientPackages)) { - Slog.w(TAG, "Not removing package " + pkg.manifestPackageName + Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName() + " hosting lib " + libraryInfo.getName() + " version " + libraryInfo.getLongVersion() + " used by " + libClientPackages + " for user " + currUserId); @@ -17574,13 +17191,13 @@ public class PackageManagerService extends IPackageManager.Stub if (info.args != null) { info.args.doPostDeleteLI(true); } - final PackageParser.Package stubPkg = + final AndroidPackage stubPkg = (disabledSystemPs == null) ? null : disabledSystemPs.pkg; - if (stubPkg != null && stubPkg.isStub) { + if (stubPkg != null && stubPkg.isStub()) { synchronized (mLock) { // restore the enabled state of the stub; the state is overwritten when // the stub is uninstalled - final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName); + final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.getPackageName()); if (stubPs != null) { stubPs.setEnabled(origEnabledState, userId, "android"); } @@ -17589,7 +17206,7 @@ public class PackageManagerService extends IPackageManager.Stub || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) { if (DEBUG_COMPRESSION) { Slog.i(TAG, "Enabling system stub after removal; pkg: " - + stubPkg.packageName); + + stubPkg.getPackageName()); } enableCompressedPackage(stubPkg); } @@ -17617,7 +17234,6 @@ public class PackageManagerService extends IPackageManager.Stub boolean isStaticSharedLib; // Clean up resources deleted packages. InstallArgs args = null; - ArrayMap<String, PackageRemovedInfo> removedChildPackages; ArrayMap<String, PackageInstalledInfo> appearedChildPackages; PackageRemovedInfo(PackageSender packageSender) { @@ -17626,24 +17242,11 @@ public class PackageManagerService extends IPackageManager.Stub void sendPackageRemovedBroadcasts(boolean killApp) { sendPackageRemovedBroadcastInternal(killApp); - final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageRemovedInfo childInfo = removedChildPackages.valueAt(i); - childInfo.sendPackageRemovedBroadcastInternal(killApp); - } } void sendSystemPackageUpdatedBroadcasts() { if (isRemovedPackageSystemUpdate) { sendSystemPackageUpdatedBroadcastsInternal(); - final int childCount = (removedChildPackages != null) - ? removedChildPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageRemovedInfo childInfo = removedChildPackages.valueAt(i); - if (childInfo.isRemovedPackageSystemUpdate) { - childInfo.sendSystemPackageUpdatedBroadcastsInternal(); - } - } } } @@ -17755,12 +17358,12 @@ public class PackageManagerService extends IPackageManager.Stub String packageName = deletedPs.name; if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs); // Retrieve object to delete permissions for shared user later on - final PackageParser.Package deletedPkg = deletedPs.pkg; + final AndroidPackage deletedPkg = deletedPs.pkg; if (outInfo != null) { outInfo.removedPackage = packageName; outInfo.installerPackageName = deletedPs.installerPackageName; outInfo.isStaticSharedLib = deletedPkg != null - && deletedPkg.staticSharedLibName != null; + && deletedPkg.getStaticSharedLibName() != null; outInfo.populateUsers(deletedPs == null ? null : deletedPs.queryInstalledUsers(mUserManager.getUserIds(), true), deletedPs); } @@ -17768,14 +17371,14 @@ public class PackageManagerService extends IPackageManager.Stub removePackageLI(deletedPs.name, (flags & PackageManager.DELETE_CHATTY) != 0); if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) { - final PackageParser.Package resolvedPkg; + final AndroidPackage resolvedPkg; if (deletedPkg != null) { resolvedPkg = deletedPkg; } else { // We don't have a parsed package when it lives on an ejected // adopted storage device, so fake something together - resolvedPkg = new PackageParser.Package(deletedPs.name); - resolvedPkg.setVolumeUuid(deletedPs.volumeUuid); + resolvedPkg = PackageImpl.buildFakeForDeletion(deletedPs.name, + deletedPs.volumeUuid); } destroyAppDataLIF(resolvedPkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); @@ -17887,13 +17490,13 @@ public class PackageManagerService extends IPackageManager.Stub throws SystemDeleteException { final boolean applyUserRestrictions = (allUserHandles != null) && outInfo != null && (outInfo.origUsers != null); - final PackageParser.Package deletedPkg = deletedPs.pkg; + final AndroidPackage deletedPkg = deletedPs.pkg; // Confirm if the system package has been updated // An updated system app can be deleted. This will also have to restore // the system pkg from system partition // reader final PackageSetting disabledPs = action.disabledPs; - if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName + if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.getPackageName() + " disabledPs=" + disabledPs); Slog.d(TAG, "Deleting system pkg from data partition"); @@ -17910,21 +17513,6 @@ public class PackageManagerService extends IPackageManager.Stub if (outInfo != null) { // Delete the updated package outInfo.isRemovedPackageSystemUpdate = true; - if (outInfo.removedChildPackages != null) { - final int childCount = (deletedPs.childPackageNames != null) - ? deletedPs.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - String childPackageName = deletedPs.childPackageNames.get(i); - if (disabledPs.childPackageNames != null && disabledPs.childPackageNames - .contains(childPackageName)) { - PackageRemovedInfo childInfo = outInfo.removedChildPackages.get( - childPackageName); - if (childInfo != null) { - childInfo.isRemovedPackageSystemUpdate = true; - } - } - } - } } if (disabledPs.versionCode < deletedPs.versionCode) { @@ -17936,7 +17524,7 @@ public class PackageManagerService extends IPackageManager.Stub } deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles, - outInfo, writeSettings, disabledPs.pkg); + outInfo, writeSettings); // writer synchronized (mLock) { @@ -17957,16 +17545,16 @@ public class PackageManagerService extends IPackageManager.Stub outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings); } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": " + Slog.w(TAG, "Failed to restore system package:" + deletedPkg.getPackageName() + ": " + e.getMessage()); // TODO(patb): can we avoid this; throw would come from scan... throw new SystemDeleteException(e); } finally { - if (disabledPs.pkg.isStub) { + if (disabledPs.pkg.isStub()) { // We've re-installed the stub; make sure it's disabled here. If package was // originally enabled, we'll install the compressed version of the application // and re-enable it afterward. - final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.packageName); + final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName()); if (stubPs != null) { stubPs.setEnabled( COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android"); @@ -17978,7 +17566,7 @@ public class PackageManagerService extends IPackageManager.Stub /** * Installs a package that's already on the system partition. */ - private PackageParser.Package installPackageFromSystemLIF(@NonNull String codePathString, + private AndroidPackage installPackageFromSystemLIF(@NonNull String codePathString, @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, @Nullable PermissionsState origPermissionState, boolean writeSettings) throws PackageManagerException { @@ -17999,7 +17587,7 @@ public class PackageManagerService extends IPackageManager.Stub } final File codePath = new File(codePathString); - final PackageParser.Package pkg = + final AndroidPackage pkg = scanPackageTracedLI(codePath, parseFlags, scanFlags, 0 /*currentTime*/, null); try { @@ -18013,7 +17601,7 @@ public class PackageManagerService extends IPackageManager.Stub // writer synchronized (mLock) { - PackageSetting ps = mSettings.mPackages.get(pkg.packageName); + PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); // Propagate the permissions state as we do not want to drop on the floor // runtime permissions. The update permissions method below will take @@ -18021,7 +17609,7 @@ public class PackageManagerService extends IPackageManager.Stub if (origPermissionState != null) { ps.getPermissionsState().copyFrom(origPermissionState); } - mPermissionManager.updatePermissions(pkg.packageName, pkg); + mPermissionManager.updatePermissions(pkg.getPackageName(), pkg); final boolean applyUserRestrictions = (allUserHandles != null) && (origUserHandles != null); @@ -18059,58 +17647,22 @@ public class PackageManagerService extends IPackageManager.Stub private void deleteInstalledPackageLIF(PackageSetting ps, boolean deleteCodeAndResources, int flags, int[] allUserHandles, - PackageRemovedInfo outInfo, boolean writeSettings, - PackageParser.Package replacingPackage) { + PackageRemovedInfo outInfo, boolean writeSettings) { synchronized (mLock) { if (outInfo != null) { outInfo.uid = ps.appId; } - - if (outInfo != null && outInfo.removedChildPackages != null) { - final int childCount = (ps.childPackageNames != null) - ? ps.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - String childPackageName = ps.childPackageNames.get(i); - PackageSetting childPs = mSettings.mPackages.get(childPackageName); - PackageRemovedInfo childInfo = outInfo.removedChildPackages.get( - childPackageName); - if (childInfo != null) { - childInfo.uid = childPs.appId; - } - } - } } // Delete package data from internal structures and also remove data if flag is set removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings); - // Delete the child packages data - final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageSetting childPs; - synchronized (mLock) { - childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i)); - } - if (childPs != null) { - PackageRemovedInfo childOutInfo = (outInfo != null - && outInfo.removedChildPackages != null) - ? outInfo.removedChildPackages.get(childPs.name) : null; - final int deleteFlags = (flags & DELETE_KEEP_DATA) != 0 - && (replacingPackage != null - && !replacingPackage.hasChildPackage(childPs.name)) - ? flags & ~DELETE_KEEP_DATA : flags; - removePackageDataLIF(childPs, allUserHandles, childOutInfo, - deleteFlags, writeSettings); - } - } - // Delete application code and resources only for parent packages - if (ps.parentPackageName == null) { - if (deleteCodeAndResources && (outInfo != null)) { - outInfo.args = createInstallArgsForExisting( - ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps)); - if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); - } + if (deleteCodeAndResources && (outInfo != null)) { + outInfo.args = createInstallArgsForExisting( + ps.codePathString, ps.resourcePathString, getAppDexInstructionSets( + ps.primaryCpuAbiString, ps.secondaryCpuAbiString)); + if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args); } } @@ -18123,10 +17675,10 @@ public class PackageManagerService extends IPackageManager.Stub // Cannot block uninstall of static shared libs as they are // considered a part of the using app (emulating static linking). // Also static libs are installed always on internal storage. - PackageParser.Package pkg = mPackages.get(packageName); - if (pkg != null && pkg.staticSharedLibName != null) { + AndroidPackage pkg = mPackages.get(packageName); + if (pkg != null && pkg.getStaticSharedLibName() != null) { Slog.w(TAG, "Cannot block uninstall of package: " + packageName - + " providing static shared library: " + pkg.staticSharedLibName); + + " providing static shared library: " + pkg.getStaticSharedLibName()); return false; } mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall); @@ -18190,40 +17742,22 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private static DeletePackageAction mayDeletePackageLocked( PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs, - @Nullable PackageSetting[] children, int flags, UserHandle user) { + int flags, UserHandle user) { if (ps == null) { return null; } if (isSystemApp(ps)) { - if (ps.parentPackageName != null) { - Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName); - return null; - } - final boolean deleteSystem = (flags & PackageManager.DELETE_SYSTEM_APP) != 0; final boolean deleteAllUsers = user == null || user.getIdentifier() == UserHandle.USER_ALL; if ((!deleteSystem || deleteAllUsers) && disabledPs == null) { - Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.packageName); + Slog.w(TAG, "Attempt to delete unknown system package " + ps.pkg.getPackageName()); return null; } // Confirmed if the system package has been updated // An updated system app can be deleted. This will also have to restore // the system pkg from system partition reader } - final int parentReferenceCount = - (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0; - final int childCount = children != null ? children.length : 0; - if (childCount != parentReferenceCount) { - return null; - } - if (childCount != 0 && outInfo != null && outInfo.removedChildPackages != null) { - for (PackageSetting child : children) { - if (child == null || !ps.childPackageNames.contains(child.name)) { - return null; - } - } - } return new DeletePackageAction(ps, disabledPs, outInfo, flags, user); } @@ -18233,13 +17767,12 @@ public class PackageManagerService extends IPackageManager.Stub private boolean deletePackageLIF(@NonNull String packageName, UserHandle user, boolean deleteCodeAndResources, int[] allUserHandles, int flags, PackageRemovedInfo outInfo, boolean writeSettings, - PackageParser.Package replacingPackage) { + ParsedPackage replacingPackage) { final DeletePackageAction action; synchronized (mLock) { final PackageSetting ps = mSettings.mPackages.get(packageName); final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps); - PackageSetting[] children = mSettings.getChildSettingsLPr(ps); - action = mayDeletePackageLocked(outInfo, ps, disabledPs, children, flags, user); + action = mayDeletePackageLocked(outInfo, ps, disabledPs, flags, user); } if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user); if (null == action) { @@ -18270,30 +17803,13 @@ public class PackageManagerService extends IPackageManager.Stub private void executeDeletePackageLIF(DeletePackageAction action, String packageName, boolean deleteCodeAndResources, int[] allUserHandles, boolean writeSettings, - PackageParser.Package replacingPackage) throws SystemDeleteException { + ParsedPackage replacingPackage) throws SystemDeleteException { final PackageSetting ps = action.deletingPs; final PackageRemovedInfo outInfo = action.outInfo; final UserHandle user = action.user; final int flags = action.flags; final boolean systemApp = isSystemApp(ps); - if (ps.parentPackageName != null - && (!systemApp || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) { - if (DEBUG_REMOVE) { - Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:" - + ((user == null) ? UserHandle.USER_ALL : user)); - } - final int removedUserId = (user != null) ? user.getIdentifier() - : UserHandle.USER_ALL; - - clearPackageStateForUserLIF(ps, removedUserId, outInfo, flags); - synchronized (mLock) { - markPackageUninstalledForUserLPw(ps, user); - scheduleWritePackageRestrictionsLocked(user); - } - return; - } - final int userId = user == null ? UserHandle.USER_ALL : user.getIdentifier(); if (ps.getPermissionsState().hasPermission(Manifest.permission.SUSPEND_APPS, userId)) { unsuspendForSuspendingPackage(packageName, userId); @@ -18343,26 +17859,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - // If we are deleting a composite package for all users, keep track - // of result for each child. - if (ps.childPackageNames != null && outInfo != null) { - synchronized (mLock) { - final int childCount = ps.childPackageNames.size(); - outInfo.removedChildPackages = new ArrayMap<>(childCount); - for (int i = 0; i < childCount; i++) { - String childPackageName = ps.childPackageNames.get(i); - PackageRemovedInfo childInfo = new PackageRemovedInfo(this); - childInfo.removedPackage = childPackageName; - childInfo.installerPackageName = ps.installerPackageName; - outInfo.removedChildPackages.put(childPackageName, childInfo); - PackageSetting childPs = mSettings.getPackageLPr(childPackageName); - if (childPs != null) { - childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true); - } - } - } - } - // TODO(b/109941548): break reasons for ret = false out into mayDelete method if (systemApp) { if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name); @@ -18372,53 +17868,12 @@ public class PackageManagerService extends IPackageManager.Stub } else { if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name); deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles, - outInfo, writeSettings, replacingPackage); + outInfo, writeSettings); } // Take a note whether we deleted the package for all users if (outInfo != null) { outInfo.removedForAllUsers = mPackages.get(ps.name) == null; - if (outInfo.removedChildPackages != null) { - synchronized (mLock) { - final int childCount = outInfo.removedChildPackages.size(); - for (int i = 0; i < childCount; i++) { - PackageRemovedInfo childInfo = outInfo.removedChildPackages.valueAt(i); - if (childInfo != null) { - childInfo.removedForAllUsers = mPackages.get( - childInfo.removedPackage) == null; - } - } - } - } - // If we uninstalled an update to a system app there may be some - // child packages that appeared as they are declared in the system - // app but were not declared in the update. - if (systemApp) { - synchronized (mLock) { - PackageSetting updatedPs = mSettings.getPackageLPr(ps.name); - final int childCount = (updatedPs.childPackageNames != null) - ? updatedPs.childPackageNames.size() : 0; - for (int i = 0; i < childCount; i++) { - String childPackageName = updatedPs.childPackageNames.get(i); - if (outInfo.removedChildPackages == null - || outInfo.removedChildPackages.indexOfKey(childPackageName) < 0) { - PackageSetting childPs = mSettings.getPackageLPr(childPackageName); - if (childPs == null) { - continue; - } - PackageInstalledInfo installRes = new PackageInstalledInfo(); - installRes.name = childPackageName; - installRes.newUsers = childPs.queryInstalledUsers(allUserHandles, true); - installRes.pkg = mPackages.get(childPackageName); - installRes.uid = childPs.pkg.applicationInfo.uid; - if (outInfo.appearedChildPackages == null) { - outInfo.appearedChildPackages = new ArrayMap<>(); - } - outInfo.appearedChildPackages.put(childPackageName, installRes); - } - } - } - } } } @@ -18455,7 +17910,7 @@ public class PackageManagerService extends IPackageManager.Stub private void clearPackageStateForUserLIF(PackageSetting ps, int userId, PackageRemovedInfo outInfo, int flags) { - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(ps.name); } @@ -18497,7 +17952,7 @@ public class PackageManagerService extends IPackageManager.Stub if (outInfo != null) { outInfo.removedPackage = ps.name; outInfo.installerPackageName = ps.installerPackageName; - outInfo.isStaticSharedLib = pkg != null && pkg.staticSharedLibName != null; + outInfo.isStaticSharedLib = pkg != null && pkg.getStaticSharedLibName() != null; outInfo.removedAppId = ps.appId; outInfo.removedUsers = userIds; outInfo.broadcastUsers = userIds; @@ -18508,7 +17963,7 @@ public class PackageManagerService extends IPackageManager.Stub public void clearApplicationProfileData(String packageName) { enforceSystemOrRoot("Only the system can clear all profile data"); - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } @@ -18586,7 +18041,7 @@ public class PackageManagerService extends IPackageManager.Stub } // Try finding details about the requested package - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -18605,7 +18060,7 @@ public class PackageManagerService extends IPackageManager.Stub clearAppDataLIF(pkg, userId, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL); - final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); + final int appId = UserHandle.getAppId(pkg.getUid()); removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId); UserManagerInternal umInternal = mInjector.getUserManagerInternal(); @@ -18682,14 +18137,14 @@ public class PackageManagerService extends IPackageManager.Stub final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_INSTANT_APPS); - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } // Queue up an async operation since the package deletion may take a little while. mHandler.post(() -> { - final PackageSetting ps = pkg == null ? null : (PackageSetting) pkg.mExtras; + final PackageSetting ps = pkg == null ? null : getPackageSetting(pkg.getPackageName()); boolean doClearData = true; if (ps != null) { final boolean targetIsInstantApp = @@ -18769,7 +18224,7 @@ public class PackageManagerService extends IPackageManager.Stub while (it.hasNext()) { final PackageSetting ps = it.next(); if (ps.pkg != null) { - int v = ps.pkg.applicationInfo.targetSdkVersion; + int v = ps.pkg.getTargetSdkVersion(); if (v < vers) vers = v; } } @@ -18777,7 +18232,7 @@ public class PackageManagerService extends IPackageManager.Stub } else if (obj instanceof PackageSetting) { final PackageSetting ps = (PackageSetting) obj; if (ps.pkg != null) { - return ps.pkg.applicationInfo.targetSdkVersion; + return ps.pkg.getTargetSdkVersion(); } } return Build.VERSION_CODES.CUR_DEVELOPMENT; @@ -18785,9 +18240,9 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mLock") private int getPackageTargetSdkVersionLockedLPr(String packageName) { - final PackageParser.Package p = mPackages.get(packageName); + final AndroidPackage p = mPackages.get(packageName); if (p != null) { - return p.applicationInfo.targetSdkVersion; + return p.getTargetSdkVersion(); } return Build.VERSION_CODES.CUR_DEVELOPMENT; } @@ -18956,7 +18411,7 @@ public class PackageManagerService extends IPackageManager.Stub } // writer synchronized (mLock) { - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); if (pkg == null || !isCallerSameApp(packageName, callingUid)) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) @@ -19030,8 +18485,8 @@ public class PackageManagerService extends IPackageManager.Stub private void clearIntentFilterVerificationsLPw(int userId) { final int packageCount = mPackages.size(); for (int i = 0; i < packageCount; i++) { - PackageParser.Package pkg = mPackages.valueAt(i); - clearIntentFilterVerificationsLPw(pkg.packageName, userId); + AndroidPackage pkg = mPackages.valueAt(i); + clearIntentFilterVerificationsLPw(pkg.getPackageName(), userId); } } @@ -19938,8 +19393,8 @@ public class PackageManagerService extends IPackageManager.Stub // If we're enabling a system stub, there's a little more work to do. // Prior to enabling the package, we need to decompress the APK(s) to the // data partition and then replace the version on the system partition. - final PackageParser.Package deletedPkg = pkgSetting.pkg; - final boolean isSystemStub = deletedPkg.isStub + final AndroidPackage deletedPkg = pkgSetting.pkg; + final boolean isSystemStub = deletedPkg.isStub() && deletedPkg.isSystem(); if (isSystemStub && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT @@ -19960,10 +19415,10 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { // We're dealing with a component level state change // First, verify that this is a valid class name. - PackageParser.Package pkg = pkgSetting.pkg; + AndroidPackage pkg = pkgSetting.pkg; if (pkg == null || !pkg.hasComponentClassName(className)) { if (pkg != null && - pkg.applicationInfo.targetSdkVersion >= + pkg.getTargetSdkVersion() >= Build.VERSION_CODES.JELLY_BEAN) { throw new IllegalArgumentException("Component class " + className + " does not exist in " + packageName); @@ -20903,7 +20358,7 @@ public class PackageManagerService extends IPackageManager.Stub if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS) && packageName == null) { - mComponentResolver.dumpServicePermissions(pw, dumpState, packageName); + mComponentResolver.dumpServicePermissions(pw, dumpState); } if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) { @@ -21046,9 +20501,9 @@ public class PackageManagerService extends IPackageManager.Stub ipw.println(); ipw.println("Dexopt state:"); ipw.increaseIndent(); - Collection<PackageParser.Package> packages; + Collection<AndroidPackage> packages; if (packageName != null) { - PackageParser.Package targetPackage = mPackages.get(packageName); + AndroidPackage targetPackage = mPackages.get(packageName); if (targetPackage != null) { packages = Collections.singletonList(targetPackage); } else { @@ -21059,11 +20514,11 @@ public class PackageManagerService extends IPackageManager.Stub packages = mPackages.values(); } - for (PackageParser.Package pkg : packages) { - ipw.println("[" + pkg.packageName + "]"); + for (AndroidPackage pkg : packages) { + ipw.println("[" + pkg.getPackageName() + "]"); ipw.increaseIndent(); mPackageDexOptimizer.dumpDexoptState(ipw, pkg, - mDexManager.getPackageUseInfoOrDefault(pkg.packageName)); + mDexManager.getPackageUseInfoOrDefault(pkg.getPackageName())); ipw.decreaseIndent(); } } @@ -21075,9 +20530,9 @@ public class PackageManagerService extends IPackageManager.Stub ipw.println(); ipw.println("Compiler stats:"); ipw.increaseIndent(); - Collection<PackageParser.Package> packages; + Collection<AndroidPackage> packages; if (packageName != null) { - PackageParser.Package targetPackage = mPackages.get(packageName); + AndroidPackage targetPackage = mPackages.get(packageName); if (targetPackage != null) { packages = Collections.singletonList(targetPackage); } else { @@ -21088,11 +20543,11 @@ public class PackageManagerService extends IPackageManager.Stub packages = mPackages.values(); } - for (PackageParser.Package pkg : packages) { - ipw.println("[" + pkg.packageName + "]"); + for (AndroidPackage pkg : packages) { + ipw.println("[" + pkg.getPackageName() + "]"); ipw.increaseIndent(); - CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.packageName); + CompilerStats.PackageStats stats = getCompilerPackageStats(pkg.getPackageName()); if (stats == null) { ipw.println("(No recorded stats)"); } else { @@ -21163,14 +20618,14 @@ public class PackageManagerService extends IPackageManager.Stub } private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing, - ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) { - final int size = infos.size(); + ArrayList<AndroidPackage> packages, IIntentReceiver finishedReceiver) { + final int size = packages.size(); final String[] packageNames = new String[size]; final int[] packageUids = new int[size]; for (int i = 0; i < size; i++) { - final ApplicationInfo info = infos.get(i); - packageNames[i] = info.packageName; - packageUids[i] = info.uid; + final AndroidPackage pkg = packages.get(i); + packageNames[i] = pkg.getAppInfoPackageName(); + packageUids[i] = pkg.getUid(); } sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids, finishedReceiver); @@ -21213,7 +20668,7 @@ public class PackageManagerService extends IPackageManager.Stub } final ArrayList<PackageFreezer> freezers = new ArrayList<>(); - final ArrayList<ApplicationInfo> loaded = new ArrayList<>(); + final ArrayList<AndroidPackage> loaded = new ArrayList<>(); final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE; final VersionInfo ver; @@ -21226,10 +20681,10 @@ public class PackageManagerService extends IPackageManager.Stub for (PackageSetting ps : packages) { freezers.add(freezePackage(ps.name, "loadPrivatePackagesInner")); synchronized (mInstallLock) { - final PackageParser.Package pkg; + final AndroidPackage pkg; try { pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null); - loaded.add(pkg.applicationInfo); + loaded.add(pkg); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage()); @@ -21301,14 +20756,14 @@ public class PackageManagerService extends IPackageManager.Stub return; } - final ArrayList<ApplicationInfo> unloaded = new ArrayList<>(); + final ArrayList<AndroidPackage> unloaded = new ArrayList<>(); synchronized (mInstallLock) { synchronized (mLock) { final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid); for (PackageSetting ps : packages) { if (ps.pkg == null) continue; - final ApplicationInfo info = ps.pkg.applicationInfo; + final AndroidPackage pkg = ps.pkg; final int deleteFlags = PackageManager.DELETE_KEEP_DATA; final PackageRemovedInfo outInfo = new PackageRemovedInfo(this); @@ -21316,7 +20771,7 @@ public class PackageManagerService extends IPackageManager.Stub "unloadPrivatePackagesInner")) { if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo, false, null)) { - unloaded.add(info); + unloaded.add(pkg); } else { Slog.w(TAG, "Failed to unload " + ps.codePath); } @@ -21531,7 +20986,7 @@ public class PackageManagerService extends IPackageManager.Stub continue; } // Skip non-core apps if requested - if (onlyCoreApps && !ps.pkg.coreApp) { + if (onlyCoreApps && !ps.pkg.isCoreApp()) { result.add(packageName); continue; } @@ -21558,10 +21013,10 @@ public class PackageManagerService extends IPackageManager.Stub * <p> * <em>Note: To avoid a deadlock, do not call this method with {@code mLock} lock held</em> */ - private void prepareAppDataAfterInstallLIF(PackageParser.Package pkg) { + private void prepareAppDataAfterInstallLIF(AndroidPackage pkg) { final PackageSetting ps; synchronized (mLock) { - ps = mSettings.mPackages.get(pkg.packageName); + ps = mSettings.mPackages.get(pkg.getPackageName()); mSettings.writeKernelMappingLPr(ps); } @@ -21591,19 +21046,15 @@ public class PackageManagerService extends IPackageManager.Stub * will try recovering system apps by wiping data; third-party app data is * left intact. */ - private void prepareAppDataLIF(PackageParser.Package pkg, int userId, int flags) { + private void prepareAppDataLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } prepareAppDataLeafLIF(pkg, userId, flags); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - prepareAppDataLeafLIF(pkg.childPackages.get(i), userId, flags); - } } - private void prepareAppDataAndMigrateLIF(PackageParser.Package pkg, int userId, int flags, + private void prepareAppDataAndMigrateLIF(AndroidPackage pkg, int userId, int flags, boolean maybeMigrateAppData) { prepareAppDataLIF(pkg, userId, flags); @@ -21614,43 +21065,37 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void prepareAppDataLeafLIF(PackageParser.Package pkg, int userId, int flags) { + private void prepareAppDataLeafLIF(AndroidPackage pkg, int userId, int flags) { if (DEBUG_APP_DATA) { - Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x" + Slog.v(TAG, "prepareAppData for " + pkg.getPackageName() + " u" + userId + " 0x" + Integer.toHexString(flags)); } final PackageSetting ps; synchronized (mLock) { - ps = mSettings.mPackages.get(pkg.packageName); - } - final String volumeUuid = pkg.volumeUuid; - final String packageName = pkg.packageName; - - ApplicationInfo app = (ps == null) - ? pkg.applicationInfo - : PackageParser.generateApplicationInfo(pkg, 0, ps.readUserState(userId), userId); - if (app == null) { - app = pkg.applicationInfo; + ps = mSettings.mPackages.get(pkg.getPackageName()); } + final String volumeUuid = pkg.getVolumeUuid(); + final String packageName = pkg.getPackageName(); - final int appId = UserHandle.getAppId(app.uid); + final int appId = UserHandle.getAppId(pkg.getUid()); - Preconditions.checkNotNull(app.seInfo); + Preconditions.checkNotNull(pkg.getSeInfo()); - final String seInfo = app.seInfo + (app.seInfoUser != null ? app.seInfoUser : ""); + final String seInfo = + pkg.getSeInfo() + (pkg.getSeInfoUser() != null ? pkg.getSeInfoUser() : ""); long ceDataInode = -1; try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, - appId, seInfo, app.targetSdkVersion); + appId, seInfo, pkg.getTargetSdkVersion()); } catch (InstallerException e) { - if (app.isSystemApp()) { + if (pkg.isSystemApp()) { logCriticalInfo(Log.ERROR, "Failed to create app data for " + packageName + ", but trying to recover: " + e); destroyAppDataLeafLIF(pkg, userId, flags); try { ceDataInode = mInstaller.createAppData(volumeUuid, packageName, userId, flags, - appId, seInfo, app.targetSdkVersion); + appId, seInfo, pkg.getTargetSdkVersion()); logCriticalInfo(Log.DEBUG, "Recovery succeeded!"); } catch (InstallerException e2) { logCriticalInfo(Log.DEBUG, "Recovery failed!"); @@ -21692,29 +21137,24 @@ public class PackageManagerService extends IPackageManager.Stub prepareAppDataContentsLeafLIF(pkg, userId, flags); } - private void prepareAppDataContentsLIF(PackageParser.Package pkg, int userId, int flags) { + private void prepareAppDataContentsLIF(AndroidPackage pkg, int userId, int flags) { if (pkg == null) { Slog.wtf(TAG, "Package was null!", new Throwable()); return; } prepareAppDataContentsLeafLIF(pkg, userId, flags); - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - prepareAppDataContentsLeafLIF(pkg.childPackages.get(i), userId, flags); - } } - private void prepareAppDataContentsLeafLIF(PackageParser.Package pkg, int userId, int flags) { - final String volumeUuid = pkg.volumeUuid; - final String packageName = pkg.packageName; - final ApplicationInfo app = pkg.applicationInfo; + private void prepareAppDataContentsLeafLIF(AndroidPackage pkg, int userId, int flags) { + final String volumeUuid = pkg.getVolumeUuid(); + final String packageName = pkg.getPackageName(); if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { // Create a native library symlink only if we have native libraries // and if the native libraries are 32 bit libraries. We do not provide // this symlink for 64 bit libraries. - if (app.primaryCpuAbi != null && !VMRuntime.is64BitAbi(app.primaryCpuAbi)) { - final String nativeLibPath = app.nativeLibraryDir; + if (pkg.getPrimaryCpuAbi() != null && !VMRuntime.is64BitAbi(pkg.getPrimaryCpuAbi())) { + final String nativeLibPath = pkg.getNativeLibraryDir(); try { mInstaller.linkNativeLibraryDirectory(volumeUuid, packageName, nativeLibPath, userId); @@ -21730,17 +21170,17 @@ public class PackageManagerService extends IPackageManager.Stub * CE/DE data to match the {@code defaultToDeviceProtectedStorage} flag * requested by the app. */ - private boolean maybeMigrateAppDataLIF(PackageParser.Package pkg, int userId) { + private boolean maybeMigrateAppDataLIF(AndroidPackage pkg, int userId) { if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated() && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { - final int storageTarget = pkg.applicationInfo.isDefaultToDeviceProtectedStorage() + final int storageTarget = pkg.isDefaultToDeviceProtectedStorage() ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE; try { - mInstaller.migrateAppData(pkg.volumeUuid, pkg.packageName, userId, + mInstaller.migrateAppData(pkg.getVolumeUuid(), pkg.getPackageName(), userId, storageTarget); } catch (InstallerException e) { logCriticalInfo(Log.WARN, - "Failed to migrate " + pkg.packageName + ": " + e.getMessage()); + "Failed to migrate " + pkg.getPackageName() + ": " + e.getMessage()); } return true; } else { @@ -21791,7 +21231,6 @@ public class PackageManagerService extends IPackageManager.Stub */ private class PackageFreezer implements AutoCloseable { private final String mPackageName; - private final PackageFreezer[] mChildren; private final boolean mWeFroze; @@ -21806,7 +21245,6 @@ public class PackageManagerService extends IPackageManager.Stub */ public PackageFreezer() { mPackageName = null; - mChildren = null; mWeFroze = false; mCloseGuard.open("close"); } @@ -21820,18 +21258,6 @@ public class PackageManagerService extends IPackageManager.Stub if (ps != null) { killApplication(ps.name, ps.appId, userId, killReason); } - - final PackageParser.Package p = mPackages.get(packageName); - if (p != null && p.childPackages != null) { - final int N = p.childPackages.size(); - mChildren = new PackageFreezer[N]; - for (int i = 0; i < N; i++) { - mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName, - userId, killReason); - } - } else { - mChildren = null; - } } mCloseGuard.open("close"); } @@ -21854,12 +21280,6 @@ public class PackageManagerService extends IPackageManager.Stub if (mWeFroze) { mFrozenPackages.remove(mPackageName); } - - if (mChildren != null) { - for (PackageFreezer freezer : mChildren) { - freezer.close(); - } - } } } } @@ -21914,14 +21334,14 @@ public class PackageManagerService extends IPackageManager.Stub // reader synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); final PackageSetting ps = mSettings.mPackages.get(packageName); if (pkg == null || ps == null || shouldFilterApplicationLocked(ps, callingUid, user.getIdentifier())) { throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package"); } - if (pkg.applicationInfo.isSystemApp()) { + if (pkg.isSystemApp()) { throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE, "Cannot move system application"); } @@ -21936,7 +21356,7 @@ public class PackageManagerService extends IPackageManager.Stub currentVolumeUuid = ps.volumeUuid; - final File probe = new File(pkg.codePath); + final File probe = new File(pkg.getCodePath()); final File probeOat = new File(probe, "oat"); if (!probe.isDirectory() || !probeOat.isDirectory()) { throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, @@ -21947,7 +21367,7 @@ public class PackageManagerService extends IPackageManager.Stub throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR, "Package already moved to " + volumeUuid); } - if (pkg.applicationInfo.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) { + if (pkg.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) { throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN, "Device admin cannot be moved"); } @@ -21958,13 +21378,13 @@ public class PackageManagerService extends IPackageManager.Stub } isCurrentLocationExternal = isExternal(pkg); - codeFile = new File(pkg.codePath); + codeFile = new File(pkg.getCodePath()); installerPackageName = ps.installerPackageName; packageAbiOverride = ps.cpuAbiOverrideString; - appId = UserHandle.getAppId(pkg.applicationInfo.uid); - seinfo = pkg.applicationInfo.seInfo; - label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo)); - targetSdkVersion = pkg.applicationInfo.targetSdkVersion; + appId = UserHandle.getAppId(pkg.getUid()); + seinfo = pkg.getSeInfo(); + label = String.valueOf(pm.getApplicationLabel(pkg.toAppInfo())); + targetSdkVersion = pkg.getTargetSdkVersion(); freezer = freezePackage(packageName, "movePackageInternal"); installedUserIds = ps.queryInstalledUsers(mUserManager.getUserIds(), true); } @@ -22125,7 +21545,7 @@ public class PackageManagerService extends IPackageManager.Stub * @param packageName The package that was moved. */ private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) { - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } @@ -22133,8 +21553,8 @@ public class PackageManagerService extends IPackageManager.Stub return; } - final StorageManager storage = mInjector.getStorageManager(); - VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString()); + final StorageManager storage = mInjector.getStorageManager();; + VolumeInfo volume = storage.findVolumeByUuid(pkg.getStorageUuid().toString()); int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg)); if (!isPreviousLocationExternal && isExternal(pkg)) { @@ -22248,7 +21668,7 @@ public class PackageManagerService extends IPackageManager.Stub if (ps.pkg == null) { continue; } - final String packageName = ps.pkg.packageName; + final String packageName = ps.pkg.getPackageName(); // Skip over if system app if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) { continue; @@ -22377,13 +21797,13 @@ public class PackageManagerService extends IPackageManager.Stub if (packageName == null || alias == null) { return null; } - synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + synchronized(mLock) { + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (shouldFilterApplicationLocked( ps, Binder.getCallingUid(), UserHandle.getCallingUserId())) { Slog.w(TAG, "KeySet requested for filtered package: " + packageName); @@ -22402,19 +21822,19 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); if (shouldFilterApplicationLocked(ps, callingUid, callingUserId)) { // filter and pretend the package doesn't exist Slog.w(TAG, "KeySet requested for filtered package: " + packageName + ", uid:" + callingUid); throw new IllegalArgumentException("Unknown package: " + packageName); } - if (pkg.applicationInfo.uid != callingUid + if (pkg.getUid() != callingUid && Process.SYSTEM_UID != callingUid) { throw new SecurityException("May not access signing KeySet of other apps."); } @@ -22432,11 +21852,11 @@ public class PackageManagerService extends IPackageManager.Stub if (packageName == null || ks == null) { return false; } - synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + synchronized(mLock) { + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null - || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid, - UserHandle.getUserId(callingUid))) { + || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()), + callingUid, UserHandle.getUserId(callingUid))) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } @@ -22459,10 +21879,10 @@ public class PackageManagerService extends IPackageManager.Stub return false; } synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null - || shouldFilterApplicationLocked((PackageSetting) pkg.mExtras, callingUid, - UserHandle.getUserId(callingUid))) { + || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()), + callingUid, UserHandle.getUserId(callingUid))) { Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } @@ -22494,29 +21914,29 @@ public class PackageManagerService extends IPackageManager.Stub * Check and throw if the given before/after packages would be considered a * downgrade. */ - private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after) + private static void checkDowngrade(AndroidPackage before, PackageInfoLite after) throws PackageManagerException { if (after.getLongVersionCode() < before.getLongVersionCode()) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update version code " + after.versionCode + " is older than current " + before.getLongVersionCode()); } else if (after.getLongVersionCode() == before.getLongVersionCode()) { - if (after.baseRevisionCode < before.baseRevisionCode) { + if (after.baseRevisionCode < before.getBaseRevisionCode()) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update base revision code " + after.baseRevisionCode - + " is older than current " + before.baseRevisionCode); + + " is older than current " + before.getBaseRevisionCode()); } if (!ArrayUtils.isEmpty(after.splitNames)) { for (int i = 0; i < after.splitNames.length; i++) { final String splitName = after.splitNames[i]; - final int j = ArrayUtils.indexOf(before.splitNames, splitName); + final int j = ArrayUtils.indexOf(before.getSplitNames(), splitName); if (j != -1) { - if (after.splitRevisionCodes[i] < before.splitRevisionCodes[j]) { + if (after.splitRevisionCodes[i] < before.getSplitRevisionCodes()[j]) { throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE, "Update split " + splitName + " revision code " + after.splitRevisionCodes[i] + " is older than current " - + before.splitRevisionCodes[j]); + + before.getSplitRevisionCodes()[j]); } } } @@ -22706,13 +22126,13 @@ public class PackageManagerService extends IPackageManager.Stub if (packageSetting == null) { return false; } - PackageParser.Package pkg = packageSetting.pkg; + AndroidPackage pkg = packageSetting.pkg; if (pkg == null) { // May happen if package in on a removable sd card return false; } - return pkg.mSigningDetails.hasAncestorOrSelf(mPlatformPackage.mSigningDetails) - || mPlatformPackage.mSigningDetails.checkCapability(pkg.mSigningDetails, + return pkg.getSigningDetails().hasAncestorOrSelf(mPlatformPackage.getSigningDetails()) + || mPlatformPackage.getSigningDetails().checkCapability(pkg.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION); } @@ -22748,11 +22168,11 @@ public class PackageManagerService extends IPackageManager.Stub private SigningDetails getSigningDetails(@NonNull String packageName) { synchronized (mLock) { - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (p == null) { return null; } - return p.mSigningDetails; + return p.getSigningDetails(); } } @@ -22783,28 +22203,25 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean filterAppAccess(PackageParser.Package pkg, int callingUid, int userId) { + public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) { synchronized (mLock) { - return PackageManagerService.this.shouldFilterApplicationLocked( - (PackageSetting) pkg.mExtras, callingUid, userId); + PackageSetting ps = getPackageSetting(pkg.getPackageName()); + return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid, + userId); } } @Override public boolean filterAppAccess(String packageName, int callingUid, int userId) { synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); - if (pkg == null) { - return false; - } - return PackageManagerService.this - .shouldFilterApplicationLocked( - (PackageSetting) pkg.mExtras, callingUid, userId); + PackageSetting ps = getPackageSetting(packageName); + return PackageManagerService.this.shouldFilterApplicationLocked(ps, callingUid, + userId); } } @Override - public PackageParser.Package getPackage(String packageName) { + public AndroidPackage getPackage(String packageName) { synchronized (mLock) { packageName = resolveInternalPackageNameLPr( packageName, PackageManager.VERSION_CODE_HIGHEST); @@ -22813,10 +22230,10 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public PackageParser.Package getPackage(int uid) { + public AndroidPackage getPackage(int uid) { synchronized (mLock) { final String[] packageNames = getPackagesForUid(uid); - PackageParser.Package pkg = null; + AndroidPackage pkg = null; final int numPackages = packageNames == null ? 0 : packageNames.length; for (int i = 0; pkg == null && i < numPackages; i++) { pkg = mPackages.get(packageNames[i]); @@ -22825,6 +22242,12 @@ public class PackageManagerService extends IPackageManager.Stub } } + @Nullable + @Override + public PackageSetting getPackageSetting(String packageName) { + return PackageManagerService.this.getPackageSetting(packageName); + } + @Override public PackageList getPackageList(PackageListObserver observer) { synchronized (mLock) { @@ -22849,17 +22272,19 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public PackageParser.Package getDisabledSystemPackage(String packageName) { + public Object getDisabledSystemPackage(@NonNull String packageName) { synchronized (mLock) { - final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName); - return (ps != null) ? ps.pkg : null; + return mSettings.getDisabledSystemPkgLPr(packageName); } } @Override - public @Nullable String getDisabledSystemPackageName(@NonNull String packageName) { - PackageParser.Package pkg = getDisabledSystemPackage(packageName); - return pkg == null ? null : pkg.packageName; + public @Nullable + String getDisabledSystemPackageName(@NonNull String packageName) { + PackageSetting disabledPkgSetting = (PackageSetting) getDisabledSystemPackage( + packageName); + AndroidPackage disabledPkg = disabledPkgSetting == null ? null : disabledPkgSetting.pkg; + return disabledPkg == null ? null : disabledPkg.getPackageName(); } @Override @@ -22930,7 +22355,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isPermissionsReviewRequired(String packageName, int userId) { synchronized (mLock) { - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { return false; } @@ -23086,9 +22511,10 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean isEnabledAndMatches(ComponentInfo info, int flags, int userId) { + public boolean isEnabledAndMatches(ParsedComponent component, int flags, int userId) { synchronized (mLock) { - return mSettings.isEnabledAndMatchLPr(info, flags, userId); + AndroidPackage pkg = getPackage(component.getPackageName()); + return mSettings.isEnabledAndMatchLPr(pkg, component, flags, userId); } } @@ -23105,10 +22531,10 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean setInstalled(PackageParser.Package pkg, @UserIdInt int userId, + public boolean setInstalled(AndroidPackage pkg, @UserIdInt int userId, boolean installed) { synchronized (mLock) { - final PackageSetting ps = mSettings.mPackages.get(pkg.packageName); + final PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); if (ps.getInstalled(userId) != installed) { ps.setInstalled(installed, userId); return true; @@ -23130,21 +22556,21 @@ public class PackageManagerService extends IPackageManager.Stub public void grantImplicitAccess(int userId, Intent intent, int callingUid, int targetAppId) { synchronized (mLock) { - final PackageParser.Package callingPackage = getPackage(callingUid); - final PackageParser.Package targetPackage = + final AndroidPackage callingPackage = getPackage(callingUid); + final AndroidPackage targetPackage = getPackage(UserHandle.getUid(userId, targetAppId)); if (callingPackage == null || targetPackage == null) { return; } - final boolean instantApp = isInstantAppInternal(callingPackage.packageName, userId, - callingUid); + final boolean instantApp = isInstantAppInternal(callingPackage.getPackageName(), + userId, callingUid); if (instantApp) { mInstantAppRegistry.grantInstantAccessLPw(userId, intent, UserHandle.getAppId(callingUid), targetAppId); } else { - mAppsFilter.grantImplicitAccess( - callingPackage.packageName, targetPackage.packageName, userId); + mAppsFilter.grantImplicitAccess(callingPackage.getPackageName(), + targetPackage.getPackageName(), userId); } } } @@ -23176,9 +22602,9 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isPackagePersistent(String packageName) { synchronized (mLock) { - PackageParser.Package pkg = mPackages.get(packageName); + AndroidPackage pkg = mPackages.get(packageName); return pkg != null - ? ((pkg.applicationInfo.flags&(ApplicationInfo.FLAG_SYSTEM + ? ((pkg.getFlags() & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT)) == (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT)) : false; @@ -23186,9 +22612,9 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public boolean isLegacySystemApp(PackageParser.Package pkg) { + public boolean isLegacySystemApp(AndroidPackage pkg) { synchronized (mLock) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); return mPromoteSystemApps && ps.isSystem() && mExistingSystemPackages.contains(ps.name); @@ -23199,9 +22625,10 @@ public class PackageManagerService extends IPackageManager.Stub public List<PackageInfo> getOverlayPackages(int userId) { final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>(); synchronized (mLock) { - for (PackageParser.Package p : mPackages.values()) { - if (p.mOverlayTarget != null) { - PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId); + for (AndroidPackage p : mPackages.values()) { + if (p.getOverlayTarget() != null) { + PackageInfo pkg = generatePackageInfo(getPackageSetting(p.getPackageName()), + 0, userId); if (pkg != null) { overlayPackages.add(pkg); } @@ -23215,9 +22642,9 @@ public class PackageManagerService extends IPackageManager.Stub public List<String> getTargetPackageNames(int userId) { List<String> targetPackages = new ArrayList<>(); synchronized (mLock) { - for (PackageParser.Package p : mPackages.values()) { - if (p.mOverlayTarget == null) { - targetPackages.add(p.packageName); + for (AndroidPackage p : mPackages.values()) { + if (p.getOverlayTarget() == null) { + targetPackages.add(p.getPackageName()); } } } @@ -23238,12 +22665,12 @@ public class PackageManagerService extends IPackageManager.Stub overlayPaths = new ArrayList<>(N); for (int i = 0; i < N; i++) { final String packageName = overlayPackageNames.get(i); - final PackageParser.Package pkg = mPackages.get(packageName); + final AndroidPackage pkg = mPackages.get(packageName); if (pkg == null) { Slog.e(TAG, "failed to find package " + packageName); return false; } - overlayPaths.add(pkg.baseCodePath); + overlayPaths.add(pkg.getBaseCodePath()); } } @@ -23361,12 +22788,12 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public void forEachPackage(Consumer<PackageParser.Package> actionLocked) { + public void forEachPackage(Consumer<AndroidPackage> actionLocked) { PackageManagerService.this.forEachPackage(actionLocked); } @Override - public void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked, + public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId) { PackageManagerService.this.forEachInstalledPackage(actionLocked, userId); } @@ -23415,7 +22842,7 @@ public class PackageManagerService extends IPackageManager.Stub */ @Override public boolean compileLayouts(String packageName) { - PackageParser.Package pkg; + AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); if (pkg == null) { @@ -23522,12 +22949,12 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isCallerInstallerOfRecord( - @NonNull PackageParser.Package pkg, int callingUid) { + @NonNull AndroidPackage pkg, int callingUid) { synchronized (mLock) { if (pkg == null) { return false; } - final PackageSetting packageSetting = (PackageSetting) pkg.mExtras; + final PackageSetting packageSetting = getPackageSetting(pkg.getPackageName()); if (packageSetting == null) { return false; } @@ -23624,7 +23051,16 @@ public class PackageManagerService extends IPackageManager.Stub } } - void forEachPackage(Consumer<PackageParser.Package> actionLocked) { + @Nullable + public PackageSetting getPackageSetting(String packageName) { + synchronized (mPackages) { + packageName = resolveInternalPackageNameLPr( + packageName, PackageManager.VERSION_CODE_HIGHEST); + return mSettings.mPackages.get(packageName); + } + } + + void forEachPackage(Consumer<AndroidPackage> actionLocked) { synchronized (mLock) { int numPackages = mPackages.size(); for (int i = 0; i < numPackages; i++) { @@ -23633,13 +23069,13 @@ public class PackageManagerService extends IPackageManager.Stub } } - void forEachInstalledPackage(@NonNull Consumer<PackageParser.Package> actionLocked, + void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> actionLocked, @UserIdInt int userId) { synchronized (mLock) { int numPackages = mPackages.size(); for (int i = 0; i < numPackages; i++) { - PackageParser.Package pkg = mPackages.valueAt(i); - PackageSetting setting = mSettings.getPackageLPr(pkg.packageName); + AndroidPackage pkg = mPackages.valueAt(i); + PackageSetting setting = mSettings.getPackageLPr(pkg.getPackageName()); if (setting == null || !setting.getInstalled(userId)) { continue; } @@ -23656,7 +23092,7 @@ public class PackageManagerService extends IPackageManager.Stub * Return a <b>copy</b> of the collection of packages known to the package manager. * @return A copy of the values of mPackages. */ - Collection<PackageParser.Package> getPackages() { + Collection<AndroidPackage> getPackages() { synchronized (mLock) { return new ArrayList<>(mPackages.values()); } @@ -23692,8 +23128,8 @@ public class PackageManagerService extends IPackageManager.Stub return mCompilerStats.getPackageStats(pkgName); } - public CompilerStats.PackageStats getOrCreateCompilerPackageStats(PackageParser.Package pkg) { - return getOrCreateCompilerPackageStats(pkg.packageName); + public CompilerStats.PackageStats getOrCreateCompilerPackageStats(AndroidPackage pkg) { + return getOrCreateCompilerPackageStats(pkg.getPackageName()); } public CompilerStats.PackageStats getOrCreateCompilerPackageStats(String pkgName) { @@ -23803,7 +23239,7 @@ public class PackageManagerService extends IPackageManager.Stub boolean canHaveOatDir(String packageName) { synchronized (mLock) { - PackageParser.Package p = mPackages.get(packageName); + AndroidPackage p = mPackages.get(packageName); if (p == null) { return false; } @@ -23811,11 +23247,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - private String getOatDir(PackageParser.Package pkg) { + private String getOatDir(AndroidPackage pkg) { if (!pkg.canHaveOatDir()) { return null; } - File codePath = new File(pkg.codePath); + File codePath = new File(pkg.getCodePath()); if (codePath.isDirectory()) { return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath(); } @@ -23826,11 +23262,12 @@ public class PackageManagerService extends IPackageManager.Stub final String[] instructionSets; final List<String> codePaths; final String oatDir; - final PackageParser.Package pkg; + final AndroidPackage pkg; synchronized (mLock) { pkg = mPackages.get(packageName); } - instructionSets = getAppDexInstructionSets(pkg.applicationInfo); + instructionSets = getAppDexInstructionSets(pkg.getPrimaryCpuAbi(), + pkg.getSecondaryCpuAbi()); codePaths = pkg.getAllCodePaths(); oatDir = getOatDir(pkg); @@ -23849,19 +23286,19 @@ public class PackageManagerService extends IPackageManager.Stub Set<String> unusedPackages = new HashSet<>(); long currentTimeInMillis = System.currentTimeMillis(); synchronized (mLock) { - for (PackageParser.Package pkg : mPackages.values()) { - PackageSetting ps = mSettings.mPackages.get(pkg.packageName); + for (AndroidPackage pkg : mPackages.values()) { + PackageSetting ps = mSettings.mPackages.get(pkg.getPackageName()); if (ps == null) { continue; } PackageDexUsage.PackageUseInfo packageUseInfo = - getDexManager().getPackageUseInfoOrDefault(pkg.packageName); + getDexManager().getPackageUseInfoOrDefault(pkg.getPackageName()); if (PackageManagerServiceUtils .isUnusedSinceTimeInMillis(ps.firstInstallTime, currentTimeInMillis, downgradeTimeThresholdMillis, packageUseInfo, pkg.getLatestPackageUseTimeInMills(), pkg.getLatestForegroundPackageUseTimeInMills())) { - unusedPackages.add(pkg.packageName); + unusedPackages.add(pkg.getPackageName()); } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index ef47410ded8c..ded9a9c58c5e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -35,10 +35,13 @@ import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.ResolveInfo; import android.content.pm.Signature; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ApkParseUtils; import android.os.Build; import android.os.Debug; import android.os.Environment; @@ -120,7 +123,7 @@ public class PackageManagerServiceUtils { // Sort a list of apps by their last usage, most recently used apps first. The order of // packages without usage data is undefined (but they will be sorted after the packages // that do have usage data). - public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs, + public static void sortPackagesByUsageDate(List<AndroidPackage> pkgs, PackageManagerService packageManagerService) { if (!packageManagerService.isHistoricalPackageUsageAvailable()) { return; @@ -135,12 +138,12 @@ public class PackageManagerServiceUtils { // package will be removed from {@code packages} and added to {@code result} with its // dependencies. If usage data is available, the positive packages will be sorted by usage // data (with {@code sortTemp} as temporary storage). - private static void applyPackageFilter(Predicate<PackageParser.Package> filter, - Collection<PackageParser.Package> result, - Collection<PackageParser.Package> packages, - @NonNull List<PackageParser.Package> sortTemp, + private static void applyPackageFilter(Predicate<AndroidPackage> filter, + Collection<AndroidPackage> result, + Collection<AndroidPackage> packages, + @NonNull List<AndroidPackage> sortTemp, PackageManagerService packageManagerService) { - for (PackageParser.Package pkg : packages) { + for (AndroidPackage pkg : packages) { if (filter.test(pkg)) { sortTemp.add(pkg); } @@ -149,10 +152,10 @@ public class PackageManagerServiceUtils { sortPackagesByUsageDate(sortTemp, packageManagerService); packages.removeAll(sortTemp); - for (PackageParser.Package pkg : sortTemp) { + for (AndroidPackage pkg : sortTemp) { result.add(pkg); - Collection<PackageParser.Package> deps = + Collection<AndroidPackage> deps = packageManagerService.findSharedNonSystemLibraries(pkg); if (!deps.isEmpty()) { deps.removeAll(result); @@ -166,50 +169,51 @@ public class PackageManagerServiceUtils { // Sort apps by importance for dexopt ordering. Important apps are given // more priority in case the device runs out of space. - public static List<PackageParser.Package> getPackagesForDexopt( - Collection<PackageParser.Package> packages, + public static List<AndroidPackage> getPackagesForDexopt( + Collection<AndroidPackage> packages, PackageManagerService packageManagerService) { return getPackagesForDexopt(packages, packageManagerService, DEBUG_DEXOPT); } - public static List<PackageParser.Package> getPackagesForDexopt( - Collection<PackageParser.Package> packages, + public static List<AndroidPackage> getPackagesForDexopt( + Collection<AndroidPackage> packages, PackageManagerService packageManagerService, boolean debug) { - ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages); - LinkedList<PackageParser.Package> result = new LinkedList<>(); - ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size()); + ArrayList<AndroidPackage> remainingPkgs = new ArrayList<>(packages); + LinkedList<AndroidPackage> result = new LinkedList<>(); + ArrayList<AndroidPackage> sortTemp = new ArrayList<>(remainingPkgs.size()); // Give priority to core apps. - applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp, + applyPackageFilter((pkg) -> pkg.isCoreApp(), result, remainingPkgs, sortTemp, packageManagerService); // Give priority to system apps that listen for pre boot complete. Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); - applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs, + applyPackageFilter((pkg) -> pkgNames.contains(pkg.getPackageName()), result, remainingPkgs, sortTemp, packageManagerService); // Give priority to apps used by other apps. DexManager dexManager = packageManagerService.getDexManager(); applyPackageFilter((pkg) -> - dexManager.getPackageUseInfoOrDefault(pkg.packageName) + dexManager.getPackageUseInfoOrDefault(pkg.getPackageName()) .isAnyCodePathUsedByOtherApps(), result, remainingPkgs, sortTemp, packageManagerService); // Filter out packages that aren't recently used, add all remaining apps. // TODO: add a property to control this? - Predicate<PackageParser.Package> remainingPredicate; + Predicate<AndroidPackage> remainingPredicate; if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) { if (debug) { Log.i(TAG, "Looking at historical package use"); } // Get the package that was used last. - PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) -> + AndroidPackage lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) -> Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(), pkg2.getLatestForegroundPackageUseTimeInMills())); if (debug) { - Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use"); + Log.i(TAG, "Taking package " + lastUsed.getPackageName() + + " as reference in time use"); } long estimatedPreviousSystemUseTime = lastUsed.getLatestForegroundPackageUseTimeInMills(); @@ -285,13 +289,13 @@ public class PackageManagerServiceUtils { } } - public static String packagesToString(Collection<PackageParser.Package> c) { + public static String packagesToString(Collection<AndroidPackage> c) { StringBuilder sb = new StringBuilder(); - for (PackageParser.Package pkg : c) { + for (AndroidPackage pkg : c) { if (sb.length() > 0) { sb.append(", "); } - sb.append(pkg.packageName); + sb.append(pkg.getPackageName()); } return sb.toString(); } @@ -309,16 +313,16 @@ public class PackageManagerServiceUtils { return false; } - public static long getLastModifiedTime(PackageParser.Package pkg) { - final File srcFile = new File(pkg.codePath); + public static long getLastModifiedTime(AndroidPackage pkg) { + final File srcFile = new File(pkg.getCodePath()); if (!srcFile.isDirectory()) { return srcFile.lastModified(); } - final File baseFile = new File(pkg.baseCodePath); + final File baseFile = new File(pkg.getBaseCodePath()); long maxModifiedTime = baseFile.lastModified(); - if (pkg.splitCodePaths != null) { - for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) { - final File splitFile = new File(pkg.splitCodePaths[i]); + if (pkg.getSplitCodePaths() != null) { + for (int i = pkg.getSplitCodePaths().length - 1; i >=0; --i) { + final File splitFile = new File(pkg.getSplitCodePaths()[i]); maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified()); } } @@ -539,7 +543,7 @@ public class PackageManagerServiceUtils { private static boolean matchSignatureInSystem(PackageSetting pkgSetting, PackageSetting disabledPkgSetting) { try { - PackageParser.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */); + ApkParseUtils.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */); if (pkgSetting.signatures.mSigningDetails.checkCapability( disabledPkgSetting.signatures.mSigningDetails, PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA) @@ -905,8 +909,10 @@ public class PackageManagerServiceUtils { * Returns the {@link PermissionsState} for the given package. If the {@link PermissionsState} * could not be found, {@code null} will be returned. */ - public static PermissionsState getPermissionsState(PackageParser.Package pkg) { - final PackageSetting packageSetting = (PackageSetting) pkg.mExtras; + public static PermissionsState getPermissionsState( + PackageManagerInternal packageManagerInternal, AndroidPackage pkg) { + final PackageSetting packageSetting = + (PackageSetting) packageManagerInternal.getPackageSetting(pkg.getPackageName()); if (packageSetting == null) { return null; } diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 3f32f3dde3ae..121d709cc037 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -48,7 +48,6 @@ import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.ApkLite; import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; @@ -62,6 +61,7 @@ import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; +import android.content.pm.parsing.ApkLiteParseUtils; import android.content.res.AssetManager; import android.content.res.Resources; import android.content.rollback.IRollbackManager; @@ -446,7 +446,7 @@ class PackageManagerShellCommand extends ShellCommand { throw new IllegalArgumentException("Error: Can't open file: " + inPath); } try { - ApkLite baseApk = PackageParser.parseApkLite(fd.getFileDescriptor(), inPath, 0); + ApkLite baseApk = ApkLiteParseUtils.parseApkLite(fd.getFileDescriptor(), inPath, 0); PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, null, null); params.sessionParams.setSize(PackageHelper.calculateInstalledSize( diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 4ea8a30fa206..44928fbd48c0 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -18,8 +18,9 @@ package com.android.server.pm; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.UserInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.service.pm.PackageProto; import android.util.proto.ProtoOutputStream; @@ -31,9 +32,11 @@ import java.util.List; /** * Settings data for a particular package we know about. */ -public final class PackageSetting extends PackageSettingBase { +public final class PackageSetting extends PackageSettingBase implements + ParsedPackage.PackageSettingCallback { int appId; - PackageParser.Package pkg; + + public AndroidPackage pkg; /** * WARNING. The object reference is important. We perform integer equality and NOT * object equality to check whether shared user settings are the same. @@ -50,12 +53,12 @@ public final class PackageSetting extends PackageSettingBase { PackageSetting(String name, String realName, File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, - long pVersionCode, int pkgFlags, int privateFlags, String parentPackageName, - List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries, + long pVersionCode, int pkgFlags, int privateFlags, + int sharedUserId, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) { super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, - pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames, + pVersionCode, pkgFlags, privateFlags, usesStaticLibraries, usesStaticLibrariesVersions); this.sharedUserId = sharedUserId; } @@ -116,10 +119,6 @@ public final class PackageSetting extends PackageSettingBase { : super.getPermissionsState(); } - public PackageParser.Package getPackage() { - return pkg; - } - public int getAppId() { return appId; } @@ -132,6 +131,7 @@ public final class PackageSetting extends PackageSettingBase { return installPermissionsFixed; } + // TODO(b/135203078): Remove these in favor of reading from the package directly public boolean isPrivileged() { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } @@ -176,10 +176,6 @@ public final class PackageSetting extends PackageSettingBase { return true; } - public boolean hasChildPackages() { - return childPackageNames != null && !childPackageNames.isEmpty(); - } - public void writeToProto(ProtoOutputStream proto, long fieldId, List<UserInfo> users) { final long packageToken = proto.start(fieldId); proto.write(PackageProto.NAME, (realName != null ? realName : name)); @@ -190,18 +186,19 @@ public final class PackageSetting extends PackageSettingBase { proto.write(PackageProto.INSTALLER_NAME, installerPackageName); if (pkg != null) { - proto.write(PackageProto.VERSION_STRING, pkg.mVersionName); + proto.write(PackageProto.VERSION_STRING, pkg.getVersionName()); long splitToken = proto.start(PackageProto.SPLITS); proto.write(PackageProto.SplitProto.NAME, "base"); - proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.baseRevisionCode); + proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.getBaseRevisionCode()); proto.end(splitToken); - if (pkg.splitNames != null) { - for (int i = 0; i < pkg.splitNames.length; i++) { + if (pkg.getSplitNames() != null) { + for (int i = 0; i < pkg.getSplitNames().length; i++) { splitToken = proto.start(PackageProto.SPLITS); - proto.write(PackageProto.SplitProto.NAME, pkg.splitNames[i]); - proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.splitRevisionCodes[i]); + proto.write(PackageProto.SplitProto.NAME, pkg.getSplitNames()[i]); + proto.write(PackageProto.SplitProto.REVISION_CODE, + pkg.getSplitRevisionCodes()[i]); proto.end(splitToken); } } @@ -218,4 +215,10 @@ public final class PackageSetting extends PackageSettingBase { sharedUserId = other.sharedUserId; sharedUser = other.sharedUser; } + + // TODO(b/135203078): Move to constructor + @Override + public void setAndroidPackage(AndroidPackage pkg) { + this.pkg = pkg; + } } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 029673ffd87b..09c1789cf445 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -36,7 +36,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import java.io.File; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; @@ -51,9 +50,6 @@ public abstract class PackageSettingBase extends SettingBase { public final String name; final String realName; - String parentPackageName; - List<String> childPackageNames; - /** * Path where this package was found on disk. For monolithic packages * this is path to single base APK file; for cluster packages this is @@ -137,14 +133,10 @@ public abstract class PackageSettingBase extends SettingBase { String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, long pVersionCode, int pkgFlags, int pkgPrivateFlags, - String parentPackageName, List<String> childPackageNames, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) { super(pkgFlags, pkgPrivateFlags); this.name = name; this.realName = realName; - this.parentPackageName = parentPackageName; - this.childPackageNames = (childPackageNames != null) - ? new ArrayList<>(childPackageNames) : null; this.usesStaticLibraries = usesStaticLibraries; this.usesStaticLibrariesVersions = usesStaticLibrariesVersions; init(codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, @@ -232,8 +224,6 @@ public abstract class PackageSettingBase extends SettingBase { } private void doCopy(PackageSettingBase orig) { - childPackageNames = (orig.childPackageNames != null) - ? new ArrayList<>(orig.childPackageNames) : null; codePath = orig.codePath; codePathString = orig.codePathString; cpuAbiOverrideString = orig.cpuAbiOverrideString; @@ -245,7 +235,6 @@ public abstract class PackageSettingBase extends SettingBase { lastUpdateTime = orig.lastUpdateTime; legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString; // Intentionally skip mOldCodePaths; it's not relevant for copies - parentPackageName = orig.parentPackageName; primaryCpuAbiString = orig.primaryCpuAbiString; resourcePath = orig.resourcePath; resourcePathString = orig.resourcePathString; @@ -657,8 +646,6 @@ public abstract class PackageSettingBase extends SettingBase { protected PackageSettingBase updateFrom(PackageSettingBase other) { super.copyFrom(other); - this.parentPackageName = other.parentPackageName; - this.childPackageNames = other.childPackageNames; this.codePath = other.codePath; this.codePathString = other.codePathString; this.resourcePath = other.resourcePath; diff --git a/services/core/java/com/android/server/pm/PackageUsage.java b/services/core/java/com/android/server/pm/PackageUsage.java index ac1f739cd9f8..ce2c9e767d5e 100644 --- a/services/core/java/com/android/server/pm/PackageUsage.java +++ b/services/core/java/com/android/server/pm/PackageUsage.java @@ -20,7 +20,7 @@ import static android.os.Process.PACKAGE_INFO_GID; import static android.os.Process.SYSTEM_UID; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.os.FileUtils; import android.util.AtomicFile; import android.util.Log; @@ -36,7 +36,7 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Map; -class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> { +class PackageUsage extends AbstractStatsBase<Map<String, AndroidPackage>> { private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_"; private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1"; @@ -52,7 +52,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } @Override - protected void writeInternal(Map<String, PackageParser.Package> packages) { + protected void writeInternal(Map<String, AndroidPackage> packages) { AtomicFile file = getFile(); FileOutputStream f = null; try { @@ -66,13 +66,13 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> sb.append('\n'); out.write(sb.toString().getBytes(StandardCharsets.US_ASCII)); - for (PackageParser.Package pkg : packages.values()) { + for (AndroidPackage pkg : packages.values()) { if (pkg.getLatestPackageUseTimeInMills() == 0L) { continue; } sb.setLength(0); - sb.append(pkg.packageName); - for (long usageTimeInMillis : pkg.mLastPackageUsageTimeInMills) { + sb.append(pkg.getPackageName()); + for (long usageTimeInMillis : pkg.getLastPackageUsageTimeInMills()) { sb.append(' '); sb.append(usageTimeInMillis); } @@ -90,7 +90,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } @Override - protected void readInternal(Map<String, PackageParser.Package> packages) { + protected void readInternal(Map<String, AndroidPackage> packages) { AtomicFile file = getFile(); BufferedInputStream in = null; try { @@ -114,7 +114,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } } - private void readVersion0LP(Map<String, PackageParser.Package> packages, InputStream in, + private void readVersion0LP(Map<String, AndroidPackage> packages, InputStream in, StringBuffer sb, String firstLine) throws IOException { // Initial version of the file had no version number and stored one @@ -128,7 +128,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } String packageName = tokens[0]; - PackageParser.Package pkg = packages.get(packageName); + AndroidPackage pkg = packages.get(packageName); if (pkg == null) { continue; } @@ -137,12 +137,12 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> for (int reason = 0; reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT; reason++) { - pkg.mLastPackageUsageTimeInMills[reason] = timestamp; + pkg.mutate().setLastPackageUsageTimeInMills(reason, timestamp); } } } - private void readVersion1LP(Map<String, PackageParser.Package> packages, InputStream in, + private void readVersion1LP(Map<String, AndroidPackage> packages, InputStream in, StringBuffer sb) throws IOException { // Version 1 of the file started with the corresponding version // number and then stored a package name and eight timestamps per line. @@ -154,7 +154,7 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> } String packageName = tokens[0]; - PackageParser.Package pkg = packages.get(packageName); + AndroidPackage pkg = packages.get(packageName); if (pkg == null) { continue; } @@ -162,7 +162,8 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> for (int reason = 0; reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT; reason++) { - pkg.mLastPackageUsageTimeInMills[reason] = parseAsLong(tokens[reason + 1]); + pkg.mutate().setLastPackageUsageTimeInMills(reason, + parseAsLong(tokens[reason + 1])); } } } @@ -196,4 +197,4 @@ class PackageUsage extends AbstractStatsBase<Map<String, PackageParser.Package>> sb.append((char)ch); } } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/pm/ParallelPackageParser.java b/services/core/java/com/android/server/pm/ParallelPackageParser.java index 4ff3e1218b53..a5065145cafd 100644 --- a/services/core/java/com/android/server/pm/ParallelPackageParser.java +++ b/services/core/java/com/android/server/pm/ParallelPackageParser.java @@ -16,7 +16,10 @@ package com.android.server.pm; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; + import android.content.pm.PackageParser; +import android.content.pm.parsing.ParsedPackage; import android.os.Process; import android.os.Trace; import android.util.DisplayMetrics; @@ -30,8 +33,6 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; -import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; - /** * Helper class for parallel parsing of packages using {@link PackageParser}. * <p>Parsing requests are processed by a thread-pool of {@link #MAX_THREADS}. @@ -65,14 +66,14 @@ class ParallelPackageParser implements AutoCloseable { static class ParseResult { - PackageParser.Package pkg; // Parsed package + ParsedPackage parsedPackage; // Parsed package File scanFile; // File that was parsed Throwable throwable; // Set if an error occurs during parsing @Override public String toString() { return "ParseResult{" + - "pkg=" + pkg + + "parsedPackage=" + parsedPackage + ", scanFile=" + scanFile + ", throwable=" + throwable + '}'; @@ -100,7 +101,7 @@ class ParallelPackageParser implements AutoCloseable { /** * Submits the file for parsing * @param scanFile file to scan - * @param parseFlags parse falgs + * @param parseFlags parse flags */ public void submit(File scanFile, int parseFlags) { mService.submit(() -> { @@ -114,7 +115,7 @@ class ParallelPackageParser implements AutoCloseable { pp.setCacheDir(mCacheDir); pp.setCallback(mPackageParserCallback); pr.scanFile = scanFile; - pr.pkg = parsePackage(pp, scanFile, parseFlags); + pr.parsedPackage = parsePackage(pp, scanFile, parseFlags); } catch (Throwable e) { pr.throwable = e; } finally { @@ -133,9 +134,9 @@ class ParallelPackageParser implements AutoCloseable { } @VisibleForTesting - protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile, + protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile, int parseFlags) throws PackageParser.PackageParserException { - return packageParser.parsePackage(scanFile, parseFlags, true /* useCaches */); + return packageParser.parseParsedPackage(scanFile, parseFlags, true); } @Override diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java index b94047e119d5..c404dad075cf 100644 --- a/services/core/java/com/android/server/pm/SELinuxMMAC.java +++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java @@ -16,9 +16,9 @@ package com.android.server.pm; -import android.content.pm.PackageParser; import android.content.pm.PackageParser.SigningDetails; import android.content.pm.Signature; +import android.content.pm.parsing.AndroidPackage; import android.os.Environment; import android.util.Slog; import android.util.Xml; @@ -78,6 +78,13 @@ public final class SELinuxMMAC { sMacPermissions.add(new File( Environment.getRootDirectory(), "/etc/selinux/plat_mac_permissions.xml")); + // SystemExt mac permissions (optional). + final File systemExtMacPermission = new File( + Environment.getSystemExtDirectory(), "/etc/selinux/system_ext_mac_permissions.xml"); + if (systemExtMacPermission.exists()) { + sMacPermissions.add(systemExtMacPermission); + } + // Product mac permissions (optional). final File productMacPermission = new File( Environment.getProductDirectory(), "/etc/selinux/product_mac_permissions.xml"); @@ -325,7 +332,7 @@ public final class SELinuxMMAC { * MINIMUM_TARGETSDKVERSION. * @return String representing the resulting seinfo. */ - public static String getSeInfo(PackageParser.Package pkg, boolean isPrivileged, + public static String getSeInfo(AndroidPackage pkg, boolean isPrivileged, int targetSdkVersion) { String seInfo = null; synchronized (sPolicies) { @@ -354,8 +361,8 @@ public final class SELinuxMMAC { seInfo += TARGETSDKVERSION_STR + targetSdkVersion; if (DEBUG_POLICY_INSTALL) { - Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " + - "seinfo=" + seInfo); + Slog.i(TAG, "package (" + pkg.getPackageName() + ") labeled with " + + "seinfo=" + seInfo); } return seInfo; } @@ -364,7 +371,7 @@ public final class SELinuxMMAC { /** * Holds valid policy representations of individual stanzas from a mac_permissions.xml * file. Each instance can further be used to assign seinfo values to apks using the - * {@link Policy#getMatchedSeinfo} method. To create an instance of this use the + * {@link Policy#getMatchedSeInfo(AndroidPackage)} method. To create an instance of this use the * {@link PolicyBuilder} pattern class, where each instance is validated against a set * of invariants before being built and returned. Each instance can be guaranteed to * hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml @@ -491,21 +498,21 @@ final class Policy { * @return A string representing the seinfo matched during policy lookup. * A value of null can also be returned if no match occured. */ - public String getMatchedSeInfo(PackageParser.Package pkg) { + public String getMatchedSeInfo(AndroidPackage pkg) { // Check for exact signature matches across all certs. Signature[] certs = mCerts.toArray(new Signature[0]); - if (pkg.mSigningDetails != SigningDetails.UNKNOWN - && !Signature.areExactMatch(certs, pkg.mSigningDetails.signatures)) { + if (pkg.getSigningDetails() != SigningDetails.UNKNOWN + && !Signature.areExactMatch(certs, pkg.getSigningDetails().signatures)) { // certs aren't exact match, but the package may have rotated from the known system cert - if (certs.length > 1 || !pkg.mSigningDetails.hasCertificate(certs[0])) { + if (certs.length > 1 || !pkg.getSigningDetails().hasCertificate(certs[0])) { return null; } } // Check for inner package name matches given that the // signature checks already passed. - String seinfoValue = mPkgMap.get(pkg.packageName); + String seinfoValue = mPkgMap.get(pkg.getPackageName()); if (seinfoValue != null) { return seinfoValue; } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 4349ea75809c..7d6c4824a520 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -42,7 +42,6 @@ import android.content.pm.ComponentInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; -import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.PermissionInfo; import android.content.pm.ResolveInfo; @@ -50,6 +49,10 @@ import android.content.pm.Signature; import android.content.pm.SuspendDialogInfo; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -466,8 +469,8 @@ public final class Settings { final PackageSetting dp = mDisabledSysPackages.get(name); // always make sure the system package code and resource paths dont change if (dp == null && p.pkg != null && p.pkg.isSystem() && !p.pkg.isUpdatedSystemApp()) { - if((p.pkg != null) && (p.pkg.applicationInfo != null)) { - p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + if(p.pkg != null) { + p.pkg.mutate().setUpdatedSystemApp(true); } final PackageSetting disabled; if (replaced) { @@ -493,14 +496,14 @@ public final class Settings { return null; } // Reset flag in ApplicationInfo object - if((p.pkg != null) && (p.pkg.applicationInfo != null)) { - p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + if(p.pkg != null) { + p.pkg.mutate().setUpdatedSystemApp(false); } PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, p.legacyNativeLibraryPathString, p.primaryCpuAbiString, p.secondaryCpuAbiString, p.cpuAbiOverrideString, p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags, - p.parentPackageName, p.childPackageNames, p.usesStaticLibraries, + p.usesStaticLibraries, p.usesStaticLibrariesVersions); mDisabledSysPackages.remove(name); return ret; @@ -517,8 +520,7 @@ public final class Settings { PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath, String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int - pkgFlags, int pkgPrivateFlags, String parentPackageName, - List<String> childPackageNames, String[] usesStaticLibraries, + pkgFlags, int pkgPrivateFlags, String[] usesStaticLibraries, long[] usesStaticLibraryNames) { PackageSetting p = mPackages.get(name); if (p != null) { @@ -531,8 +533,8 @@ public final class Settings { } p = new PackageSetting(name, realName, codePath, resourcePath, legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString, - cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, parentPackageName, - childPackageNames, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames); + cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags, + 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames); p.appId = uid; if (registerExistingAppIdLPw(uid, p, name)) { mPackages.put(name, p); @@ -598,19 +600,15 @@ public final class Settings { File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi, String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags, UserHandle installUser, boolean allowInstall, boolean instantApp, - boolean virtualPreload, String parentPkgName, List<String> childPkgNames, - UserManagerService userManager, + boolean virtualPreload, UserManagerService userManager, String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) { final PackageSetting pkgSetting; if (originalPkg != null) { if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + pkgName + " is adopting original package " + originalPkg.name); pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/); - pkgSetting.childPackageNames = - (childPkgNames != null) ? new ArrayList<>(childPkgNames) : null; pkgSetting.codePath = codePath; pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath; - pkgSetting.parentPackageName = parentPkgName; pkgSetting.pkgFlags = pkgFlags; pkgSetting.pkgPrivateFlags = pkgPrivateFlags; pkgSetting.primaryCpuAbiString = primaryCpuAbi; @@ -628,7 +626,7 @@ public final class Settings { pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath, legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi, null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags, - parentPkgName, childPkgNames, 0 /*sharedUserId*/, usesStaticLibraries, + 0 /*sharedUserId*/, usesStaticLibraries, usesStaticLibrariesVersions); pkgSetting.setTimeStamp(codePath.lastModified()); pkgSetting.sharedUser = sharedUser; @@ -715,7 +713,7 @@ public final class Settings { @NonNull File codePath, File resourcePath, @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags, - @Nullable List<String> childPkgNames, @NonNull UserManagerService userManager, + @NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions) throws PackageManagerException { final String pkgName = pkgSetting.name; @@ -793,9 +791,6 @@ public final class Settings { pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM; pkgSetting.primaryCpuAbiString = primaryCpuAbi; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; - if (childPkgNames != null) { - pkgSetting.childPackageNames = new ArrayList<>(childPkgNames); - } // Update static shared library dependencies if needed if (usesStaticLibraries != null && usesStaticLibrariesVersions != null && usesStaticLibraries.length == usesStaticLibrariesVersions.length) { @@ -864,15 +859,15 @@ public final class Settings { // TODO: Move to scanPackageOnlyLI() after verifying signatures are setup correctly // by that time. - void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) { + void insertPackageSettingLPw(PackageSetting p, AndroidPackage pkg) { // Update signatures if needed. if (p.signatures.mSigningDetails.signatures == null) { - p.signatures.mSigningDetails = pkg.mSigningDetails; + p.signatures.mSigningDetails = pkg.getSigningDetails(); } // If this app defines a shared user id initialize // the shared user signatures as well. if (p.sharedUser != null && p.sharedUser.signatures.mSigningDetails.signatures == null) { - p.sharedUser.signatures.mSigningDetails = pkg.mSigningDetails; + p.sharedUser.signatures.mSigningDetails = pkg.getSigningDetails(); } addPackageSettingLPw(p, p.sharedUser); } @@ -949,7 +944,7 @@ public final class Settings { int affectedUserId = UserHandle.USER_NULL; // Update permissions - for (String eachPerm : deletedPs.pkg.requestedPermissions) { + for (String eachPerm : deletedPs.pkg.getRequestedPermissions()) { BasePermission bp = mPermissions.getPermission(eachPerm); if (bp == null) { continue; @@ -959,8 +954,8 @@ public final class Settings { boolean used = false; for (PackageSetting pkg : sus.packages) { if (pkg.pkg != null - && !pkg.pkg.packageName.equals(deletedPs.pkg.packageName) - && pkg.pkg.requestedPermissions.contains(eachPerm)) { + && !pkg.pkg.getPackageName().equals(deletedPs.pkg.getPackageName()) + && pkg.pkg.getRequestedPermissions().contains(eachPerm)) { used = true; break; } @@ -970,13 +965,13 @@ public final class Settings { } PermissionsState permissionsState = sus.getPermissionsState(); - PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.packageName); + PackageSetting disabledPs = getDisabledSystemPkgLPr(deletedPs.pkg.getPackageName()); // If the package is shadowing is a disabled system package, // do not drop permissions that the shadowed package requests. if (disabledPs != null) { boolean reqByDisabledSysPkg = false; - for (String permission : disabledPs.pkg.requestedPermissions) { + for (String permission : disabledPs.pkg.getRequestedPermissions()) { if (permission.equals(eachPerm)) { reqByDisabledSysPkg = true; break; @@ -2207,20 +2202,6 @@ public final class Settings { serializer.endTag(null, TAG_PERMISSIONS); } - void writeChildPackagesLPw(XmlSerializer serializer, List<String> childPackageNames) - throws IOException { - if (childPackageNames == null) { - return; - } - final int childCount = childPackageNames.size(); - for (int i = 0; i < childCount; i++) { - String childPackageName = childPackageNames.get(i); - serializer.startTag(null, TAG_CHILD_PACKAGE); - serializer.attribute(null, ATTR_NAME, childPackageName); - serializer.endTag(null, TAG_CHILD_PACKAGE); - } - } - void readUsesStaticLibLPw(XmlPullParser parser, PackageSetting outPs) throws IOException, XmlPullParserException { int outerDepth = parser.getDepth(); @@ -2674,17 +2655,15 @@ public final class Settings { StringBuilder sb = new StringBuilder(); for (final PackageSetting pkg : mPackages.values()) { - if (pkg.pkg == null || pkg.pkg.applicationInfo == null - || pkg.pkg.applicationInfo.dataDir == null) { + if (pkg.pkg == null || pkg.pkg.getDataDir() == null) { if (!"android".equals(pkg.name)) { Slog.w(TAG, "Skipping " + pkg + " due to missing metadata"); } continue; } - final ApplicationInfo ai = pkg.pkg.applicationInfo; - final String dataPath = ai.dataDir; - final boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + final String dataPath = pkg.pkg.getDataDir(); + final boolean isDebug = (pkg.pkg.getFlags() & ApplicationInfo.FLAG_DEBUGGABLE) != 0; final int[] gids = pkg.getPermissionsState().computeGids(userIds); // Avoid any application that has a space in its path. @@ -2709,13 +2688,13 @@ public final class Settings { // system/core/libpackagelistparser // sb.setLength(0); - sb.append(ai.packageName); + sb.append(pkg.pkg.getPackageName()); sb.append(" "); - sb.append(ai.uid); + sb.append(pkg.pkg.getUid()); sb.append(isDebug ? " 1 " : " 0 "); sb.append(dataPath); sb.append(" "); - sb.append(ai.seInfo); + sb.append(pkg.pkg.getSeInfo()); sb.append(" "); if (gids != null && gids.length > 0) { sb.append(gids[0]); @@ -2727,9 +2706,9 @@ public final class Settings { sb.append("none"); } sb.append(" "); - sb.append(ai.isProfileableByShell() ? "1" : "0"); + sb.append(pkg.pkg.isProfileableByShell() ? "1" : "0"); sb.append(" "); - sb.append(String.valueOf(ai.longVersionCode)); + sb.append(pkg.pkg.getLongVersionCode()); sb.append("\n"); writer.append(sb); } @@ -2778,12 +2757,6 @@ public final class Settings { serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId)); } - if (pkg.parentPackageName != null) { - serializer.attribute(null, "parentPackageName", pkg.parentPackageName); - } - - writeChildPackagesLPw(serializer, pkg.childPackageNames); - writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); // If this is a shared user, the permissions will be written there. @@ -2847,15 +2820,10 @@ public final class Settings { serializer.attribute(null, "categoryHint", Integer.toString(pkg.categoryHint)); } - if (pkg.parentPackageName != null) { - serializer.attribute(null, "parentPackageName", pkg.parentPackageName); - } if (pkg.updateAvailable) { serializer.attribute(null, "updateAvailable", "true"); } - writeChildPackagesLPw(serializer, pkg.childPackageNames); - writeUsesStaticLibLPw(serializer, pkg.usesStaticLibraries, pkg.usesStaticLibrariesVersions); pkg.signatures.writeXml(serializer, "sigs", mPastSignatures); @@ -3148,13 +3116,13 @@ public final class Settings { LocalServices.getService(PackageManagerInternal.class); for (PackageSetting ps : mPackages.values()) { if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0 && ps.pkg != null - && ps.pkg.preferredActivityFilters != null) { - ArrayList<PackageParser.ActivityIntentInfo> intents - = ps.pkg.preferredActivityFilters; + && ps.pkg.getPreferredActivityFilters() != null) { + List<ComponentParseUtils.ParsedActivityIntentInfo> intents + = ps.pkg.getPreferredActivityFilters(); for (int i=0; i<intents.size(); i++) { - PackageParser.ActivityIntentInfo aii = intents.get(i); + ComponentParseUtils.ParsedActivityIntentInfo aii = intents.get(i); applyDefaultPreferredActivityLPw(pmInternal, aii, new ComponentName( - ps.name, aii.activity.className), userId); + ps.name, aii.getClassName()), userId); } } } @@ -3513,7 +3481,7 @@ public final class Settings { PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr, secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags, - parentPackageName, null /*childPackageNames*/, 0 /*sharedUserId*/, null, null); + 0 /*sharedUserId*/, null, null); String timeStampStr = parser.getAttributeValue(null, "ft"); if (timeStampStr != null) { try { @@ -3562,12 +3530,6 @@ public final class Settings { if (parser.getName().equals(TAG_PERMISSIONS)) { readInstallPermissionsLPr(parser, ps.getPermissionsState()); - } else if (parser.getName().equals(TAG_CHILD_PACKAGE)) { - String childPackageName = parser.getAttributeValue(null, ATTR_NAME); - if (ps.childPackageNames == null) { - ps.childPackageNames = new ArrayList<>(); - } - ps.childPackageNames.add(childPackageName); } else if (parser.getName().equals(TAG_USES_STATIC_LIB)) { readUsesStaticLibLPw(parser, ps); } else { @@ -3612,7 +3574,6 @@ public final class Settings { PackageSetting packageSetting = null; String version = null; long versionCode = 0; - String parentPackageName; try { name = parser.getAttributeValue(null, ATTR_NAME); realName = parser.getAttributeValue(null, "realName"); @@ -3624,8 +3585,6 @@ public final class Settings { legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi"); - parentPackageName = parser.getAttributeValue(null, "parentPackageName"); - legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi"); secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi"); @@ -3752,7 +3711,7 @@ public final class Settings { packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags, - pkgPrivateFlags, parentPackageName, null /*childPackageNames*/, + pkgPrivateFlags, null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/); if (PackageManagerService.DEBUG_SETTINGS) Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId=" @@ -3771,8 +3730,8 @@ public final class Settings { packageSetting = new PackageSetting(name.intern(), realName, new File( codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, - versionCode, pkgFlags, pkgPrivateFlags, parentPackageName, - null /*childPackageNames*/, sharedUserId, + versionCode, pkgFlags, pkgPrivateFlags, + sharedUserId, null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/); packageSetting.setTimeStamp(timeStamp); packageSetting.firstInstallTime = firstInstallTime; @@ -3880,12 +3839,6 @@ public final class Settings { packageSetting.keySetData.addDefinedKeySet(id, alias); } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) { readDomainVerificationLPw(parser, packageSetting); - } else if (tagName.equals(TAG_CHILD_PACKAGE)) { - String childPackageName = parser.getAttributeValue(null, ATTR_NAME); - if (packageSetting.childPackageNames == null) { - packageSetting.childPackageNames = new ArrayList<>(); - } - packageSetting.childPackageNames.add(childPackageName); } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Unknown element under <package>: " + parser.getName()); @@ -4038,13 +3991,13 @@ public final class Settings { Iterator<PackageSetting> packagesIterator = packages.iterator(); for (int i = 0; i < packagesCount; i++) { PackageSetting ps = packagesIterator.next(); - if (ps.pkg == null || ps.pkg.applicationInfo == null) { + if (ps.pkg == null) { continue; } final boolean shouldInstall = ps.isSystem() && (skipPackageWhitelist || installablePackages.contains(ps.name)) && !ArrayUtils.contains(disallowedPackages, ps.name) && - !ps.pkg.applicationInfo.hiddenUntilInstalled; + !ps.pkg.isHiddenUntilInstalled(); // Only system apps are initially installed. ps.setInstalled(shouldInstall, userHandle); if (!shouldInstall) { @@ -4055,8 +4008,8 @@ public final class Settings { volumeUuids[i] = ps.volumeUuid; names[i] = ps.name; appIds[i] = ps.appId; - seinfos[i] = ps.pkg.applicationInfo.seInfo; - targetSdkVersions[i] = ps.pkg.applicationInfo.targetSdkVersion; + seinfos[i] = ps.pkg.getSeInfo(); + targetSdkVersions[i] = ps.pkg.getTargetSdkVersion(); } } t.traceBegin("createAppData"); @@ -4166,28 +4119,6 @@ public final class Settings { return mVerifierDeviceIdentity; } - boolean hasOtherDisabledSystemPkgWithChildLPr(String parentPackageName, - String childPackageName) { - final int packageCount = mDisabledSysPackages.size(); - for (int i = 0; i < packageCount; i++) { - PackageSetting disabledPs = mDisabledSysPackages.valueAt(i); - if (disabledPs.childPackageNames == null || disabledPs.childPackageNames.isEmpty()) { - continue; - } - if (disabledPs.name.equals(parentPackageName)) { - continue; - } - final int childCount = disabledPs.childPackageNames.size(); - for (int j = 0; j < childCount; j++) { - String currChildPackageName = disabledPs.childPackageNames.get(j); - if (currChildPackageName.equals(childPackageName)) { - return true; - } - } - } - return false; - } - /** * Returns the disabled {@link PackageSetting} for the provided package name if one exists, * {@code null} otherwise. @@ -4210,26 +4141,6 @@ public final class Settings { return getDisabledSystemPkgLPr(enabledPackageSetting.name); } - /** - * Fetches an array of the child {@link PackageSetting}s for all child package names referenced - * by the provided parent {@link PackageSetting} or {@code null} if no children are referenced. - * - * Note: Any child packages not found will be null in the returned array. - */ - @Nullable - public PackageSetting[] getChildSettingsLPr(PackageSetting parentPackageSetting) { - if (parentPackageSetting == null || !parentPackageSetting.hasChildPackages()) { - return null; - } - final int childCount = parentPackageSetting.childPackageNames.size(); - PackageSetting[] children = - new PackageSetting[childCount]; - for (int i = 0; i < childCount; i++) { - children[i] = mPackages.get(parentPackageSetting.childPackageNames.get(i)); - } - return children; - } - boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) { final PackageSetting ps = mPackages.get(componentInfo.packageName); if (ps == null) return false; @@ -4238,6 +4149,15 @@ public final class Settings { return userState.isMatch(componentInfo, flags); } + boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedComponent component, int flags, + int userId) { + final PackageSetting ps = mPackages.get(component.getPackageName()); + if (ps == null) return false; + + final PackageUserState userState = ps.readUserState(userId); + return userState.isMatch(pkg.isSystem(), pkg.isEnabled(), component, flags); + } + String getInstallerPackageNameLPr(String packageName) { final PackageSetting pkg = mPackages.get(packageName); if (pkg == null) { @@ -4455,6 +4375,7 @@ public final class Settings { void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf, Date date, List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) { + AndroidPackage pkg = ps.pkg; if (checkinTag != null) { pw.print(checkinTag); pw.print(","); @@ -4470,15 +4391,16 @@ public final class Settings { pw.print(","); pw.print(ps.installerPackageName != null ? ps.installerPackageName : "?"); pw.println(); - if (ps.pkg != null) { + if (pkg != null) { pw.print(checkinTag); pw.print("-"); pw.print("splt,"); pw.print("base,"); - pw.println(ps.pkg.baseRevisionCode); - if (ps.pkg.splitNames != null) { - for (int i = 0; i < ps.pkg.splitNames.length; i++) { + pw.println(pkg.getBaseRevisionCode()); + if (pkg.getSplitNames() != null) { + int[] splitRevisionCodes = pkg.getSplitRevisionCodes(); + for (int i = 0; i < pkg.getSplitNames().length; i++) { pw.print(checkinTag); pw.print("-"); pw.print("splt,"); - pw.print(ps.pkg.splitNames[i]); pw.print(","); - pw.println(ps.pkg.splitRevisionCodes[i]); + pw.print(pkg.getSplitNames()[i]); pw.print(","); + pw.println(splitRevisionCodes[i]); } } } @@ -4525,7 +4447,7 @@ public final class Settings { if (ps.sharedUser != null) { pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser); } - pw.print(prefix); pw.print(" pkg="); pw.println(ps.pkg); + pw.print(prefix); pw.print(" pkg="); pw.println(pkg); pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString); if (permissionNames == null) { pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString); @@ -4535,140 +4457,123 @@ public final class Settings { pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString); } pw.print(prefix); pw.print(" versionCode="); pw.print(ps.versionCode); - if (ps.pkg != null) { - pw.print(" minSdk="); pw.print(ps.pkg.applicationInfo.minSdkVersion); - pw.print(" targetSdk="); pw.print(ps.pkg.applicationInfo.targetSdkVersion); + if (pkg != null) { + pw.print(" minSdk="); pw.print(pkg.getMinSdkVersion()); + pw.print(" targetSdk="); pw.print(pkg.getTargetSdkVersion()); } pw.println(); - if (ps.pkg != null) { - if (ps.pkg.parentPackage != null) { - PackageParser.Package parentPkg = ps.pkg.parentPackage; - PackageSetting pps = mPackages.get(parentPkg.packageName); - if (pps == null || !pps.codePathString.equals(parentPkg.codePath)) { - pps = mDisabledSysPackages.get(parentPkg.packageName); - } - if (pps != null) { - pw.print(prefix); pw.print(" parentPackage="); - pw.println(pps.realName != null ? pps.realName : pps.name); - } - } else if (ps.pkg.childPackages != null) { - pw.print(prefix); pw.print(" childPackages=["); - final int childCount = ps.pkg.childPackages.size(); - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = ps.pkg.childPackages.get(i); - PackageSetting cps = mPackages.get(childPkg.packageName); - if (cps == null || !cps.codePathString.equals(childPkg.codePath)) { - cps = mDisabledSysPackages.get(childPkg.packageName); - } - if (cps != null) { - if (i > 0) { - pw.print(", "); - } - pw.print(cps.realName != null ? cps.realName : cps.name); - } - } - pw.println("]"); - } - pw.print(prefix); pw.print(" versionName="); pw.println(ps.pkg.mVersionName); - pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, ps.pkg); pw.println(); - final int apkSigningVersion = ps.pkg.mSigningDetails.signatureSchemeVersion; + if (pkg != null) { + pw.print(prefix); pw.print(" versionName="); pw.println(pkg.getVersionName()); + pw.print(prefix); pw.print(" splits="); dumpSplitNames(pw, pkg); pw.println(); + final int apkSigningVersion = pkg.getSigningDetails().signatureSchemeVersion; pw.print(prefix); pw.print(" apkSigningVersion="); pw.println(apkSigningVersion); + // TODO(b/135203078): Is there anything to print here with AppInfo removed? pw.print(prefix); pw.print(" applicationInfo="); - pw.println(ps.pkg.applicationInfo.toString()); - pw.print(prefix); pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags, + pw.println(pkg.toAppInfo().toString()); + pw.print(prefix); pw.print(" flags="); printFlags(pw, pkg.getFlags(), FLAG_DUMP_SPEC); pw.println(); - if (ps.pkg.applicationInfo.privateFlags != 0) { + if (pkg.getPrivateFlags() != 0) { pw.print(prefix); pw.print(" privateFlags="); printFlags(pw, - ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println(); + pkg.getPrivateFlags(), PRIVATE_FLAG_DUMP_SPEC); pw.println(); } - pw.print(prefix); pw.print(" forceQueryable="); pw.println(ps.pkg.mForceQueryable); - if (ps.pkg.mQueriesPackages != null) { - pw.append(prefix).append(" queriesPackages=").println(ps.pkg.mQueriesPackages); + pw.print(prefix); pw.print(" forceQueryable="); pw.println(ps.pkg.isForceQueryable()); + if (ps.pkg.getQueriesPackages() != null) { + pw.append(prefix).append(" queriesPackages=").println(ps.pkg.getQueriesPackages()); } - if (ps.pkg.mQueriesIntents != null) { - pw.append(prefix).append(" queriesIntents=").println(ps.pkg.mQueriesIntents); + if (ps.pkg.getQueriesIntents() != null) { + pw.append(prefix).append(" queriesIntents=").println(ps.pkg.getQueriesIntents()); } - pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); + pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.getDataDir()); pw.print(prefix); pw.print(" supportsScreens=["); boolean first = true; - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("small"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("medium"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("large"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("xlarge"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { if (!first) pw.print(", "); first = false; pw.print("resizeable"); } - if ((ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { + if ((pkg.getFlags() & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { if (!first) pw.print(", "); first = false; pw.print("anyDensity"); } pw.println("]"); - if (ps.pkg.libraryNames != null && ps.pkg.libraryNames.size() > 0) { + List<String> libraryNames = pkg.getLibraryNames(); + if (libraryNames != null && libraryNames.size() > 0) { pw.print(prefix); pw.println(" dynamic libraries:"); - for (int i = 0; i<ps.pkg.libraryNames.size(); i++) { + for (int i = 0; i< libraryNames.size(); i++) { pw.print(prefix); pw.print(" "); - pw.println(ps.pkg.libraryNames.get(i)); + pw.println(libraryNames.get(i)); } } - if (ps.pkg.staticSharedLibName != null) { + if (pkg.getStaticSharedLibName() != null) { pw.print(prefix); pw.println(" static library:"); pw.print(prefix); pw.print(" "); - pw.print("name:"); pw.print(ps.pkg.staticSharedLibName); - pw.print(" version:"); pw.println(ps.pkg.staticSharedLibVersion); + pw.print("name:"); pw.print(pkg.getStaticSharedLibName()); + pw.print(" version:"); pw.println(pkg.getStaticSharedLibVersion()); } - if (ps.pkg.usesLibraries != null && ps.pkg.usesLibraries.size() > 0) { + + List<String> usesLibraries = pkg.getUsesLibraries(); + if (usesLibraries != null && usesLibraries.size() > 0) { pw.print(prefix); pw.println(" usesLibraries:"); - for (int i=0; i<ps.pkg.usesLibraries.size(); i++) { - pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraries.get(i)); + for (int i=0; i< usesLibraries.size(); i++) { + pw.print(prefix); pw.print(" "); pw.println(usesLibraries.get(i)); } } - if (ps.pkg.usesStaticLibraries != null - && ps.pkg.usesStaticLibraries.size() > 0) { + + List<String> usesStaticLibraries = pkg.getUsesStaticLibraries(); + long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions(); + if (usesStaticLibraries != null + && usesStaticLibraries.size() > 0) { pw.print(prefix); pw.println(" usesStaticLibraries:"); - for (int i=0; i<ps.pkg.usesStaticLibraries.size(); i++) { + for (int i=0; i< usesStaticLibraries.size(); i++) { pw.print(prefix); pw.print(" "); - pw.print(ps.pkg.usesStaticLibraries.get(i)); pw.print(" version:"); - pw.println(ps.pkg.usesStaticLibrariesVersions[i]); + pw.print(usesStaticLibraries.get(i)); pw.print(" version:"); + pw.println(usesStaticLibrariesVersions[i]); } } - if (ps.pkg.usesOptionalLibraries != null - && ps.pkg.usesOptionalLibraries.size() > 0) { + + List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries(); + if (usesOptionalLibraries != null + && usesOptionalLibraries.size() > 0) { pw.print(prefix); pw.println(" usesOptionalLibraries:"); - for (int i=0; i<ps.pkg.usesOptionalLibraries.size(); i++) { + for (int i=0; i< usesOptionalLibraries.size(); i++) { pw.print(prefix); pw.print(" "); - pw.println(ps.pkg.usesOptionalLibraries.get(i)); + pw.println(usesOptionalLibraries.get(i)); } } - if (ps.pkg.usesLibraryFiles != null - && ps.pkg.usesLibraryFiles.length > 0) { + + String[] usesLibraryFiles = pkg.getUsesLibraryFiles(); + if (usesLibraryFiles != null + && usesLibraryFiles.length > 0) { pw.print(prefix); pw.println(" usesLibraryFiles:"); - for (int i=0; i<ps.pkg.usesLibraryFiles.length; i++) { - pw.print(prefix); pw.print(" "); pw.println(ps.pkg.usesLibraryFiles[i]); + for (int i=0; i< usesLibraryFiles.length; i++) { + pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles[i]); } } } @@ -4696,40 +4601,40 @@ public final class Settings { pw.print(prefix); pw.print(" pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC); pw.println(); - if (ps.pkg != null && ps.pkg.mOverlayTarget != null) { - pw.print(prefix); pw.print(" overlayTarget="); pw.println(ps.pkg.mOverlayTarget); - pw.print(prefix); pw.print(" overlayCategory="); pw.println(ps.pkg.mOverlayCategory); + if (pkg != null && pkg.getOverlayTarget() != null) { + pw.print(prefix); pw.print(" overlayTarget="); pw.println(pkg.getOverlayTarget()); + pw.print(prefix); pw.print(" overlayCategory="); pw.println(pkg.getOverlayCategory()); } - if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) { - final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions; + if (pkg != null && pkg.getPermissions() != null && pkg.getPermissions().size() > 0) { + final List<ParsedPermission> perms = pkg.getPermissions(); pw.print(prefix); pw.println(" declared permissions:"); for (int i=0; i<perms.size(); i++) { - PackageParser.Permission perm = perms.get(i); + ParsedPermission perm = perms.get(i); if (permissionNames != null - && !permissionNames.contains(perm.info.name)) { + && !permissionNames.contains(perm.getName())) { continue; } - pw.print(prefix); pw.print(" "); pw.print(perm.info.name); + pw.print(prefix); pw.print(" "); pw.print(perm.getName()); pw.print(": prot="); - pw.print(PermissionInfo.protectionToString(perm.info.protectionLevel)); - if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) { + pw.print(PermissionInfo.protectionToString(perm.protectionLevel)); + if ((perm.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) { pw.print(", COSTS_MONEY"); } - if ((perm.info.flags&PermissionInfo.FLAG_REMOVED) != 0) { + if ((perm.flags&PermissionInfo.FLAG_REMOVED) != 0) { pw.print(", HIDDEN"); } - if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) { + if ((perm.flags&PermissionInfo.FLAG_INSTALLED) != 0) { pw.print(", INSTALLED"); } pw.println(); } } - if ((permissionNames != null || dumpAll) && ps.pkg != null - && ps.pkg.requestedPermissions != null - && ps.pkg.requestedPermissions.size() > 0) { - final ArrayList<String> perms = ps.pkg.requestedPermissions; + if ((permissionNames != null || dumpAll) && pkg != null + && pkg.getRequestedPermissions() != null + && pkg.getRequestedPermissions().size() > 0) { + final List<String> perms = pkg.getRequestedPermissions(); pw.print(prefix); pw.println(" requested permissions:"); for (int i=0; i<perms.size(); i++) { String perm = perms.get(i); @@ -4996,22 +4901,24 @@ public final class Settings { pw.print(mReadMessages.toString()); } - private static void dumpSplitNames(PrintWriter pw, PackageParser.Package pkg) { + private static void dumpSplitNames(PrintWriter pw, AndroidPackage pkg) { if (pkg == null) { pw.print("unknown"); } else { // [base:10, config.mdpi, config.xhdpi:12] pw.print("["); pw.print("base"); - if (pkg.baseRevisionCode != 0) { - pw.print(":"); pw.print(pkg.baseRevisionCode); + if (pkg.getBaseRevisionCode() != 0) { + pw.print(":"); pw.print(pkg.getBaseRevisionCode()); } - if (pkg.splitNames != null) { - for (int i = 0; i < pkg.splitNames.length; i++) { + String[] splitNames = pkg.getSplitNames(); + int[] splitRevisionCodes = pkg.getSplitRevisionCodes(); + if (splitNames != null) { + for (int i = 0; i < splitNames.length; i++) { pw.print(", "); - pw.print(pkg.splitNames[i]); - if (pkg.splitRevisionCodes[i] != 0) { - pw.print(":"); pw.print(pkg.splitRevisionCodes[i]); + pw.print(splitNames[i]); + if (splitRevisionCodes[i] != 0) { + pw.print(":"); pw.print(splitRevisionCodes[i]); } } } @@ -5087,22 +4994,23 @@ public final class Settings { } void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps) { - dumpComponents(pw, prefix, ps, "activities:", ps.pkg.activities); - dumpComponents(pw, prefix, ps, "services:", ps.pkg.services); - dumpComponents(pw, prefix, ps, "receivers:", ps.pkg.receivers); - dumpComponents(pw, prefix, ps, "providers:", ps.pkg.providers); - dumpComponents(pw, prefix, ps, "instrumentations:", ps.pkg.instrumentation); + // TODO(b/135203078): ParsedComponent toString methods for dumping + dumpComponents(pw, prefix, "activities:", ps.pkg.getActivities()); + dumpComponents(pw, prefix, "services:", ps.pkg.getServices()); + dumpComponents(pw, prefix, "receivers:", ps.pkg.getReceivers()); + dumpComponents(pw, prefix, "providers:", ps.pkg.getProviders()); + dumpComponents(pw, prefix, "instrumentations:", ps.pkg.getInstrumentations()); } - void dumpComponents(PrintWriter pw, String prefix, PackageSetting ps, - String label, List<? extends PackageParser.Component<?>> list) { + void dumpComponents(PrintWriter pw, String prefix, String label, + List<? extends ParsedComponent> list) { final int size = CollectionUtils.size(list); if (size == 0) { return; } pw.print(prefix);pw.println(label); for (int i = 0; i < size; i++) { - final PackageParser.Component<?> component = list.get(i); + final ParsedComponent component = list.get(i); pw.print(prefix);pw.print(" "); pw.println(component.getComponentName().flattenToShortString()); } diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index 2ee07a2037c3..cff19443a79b 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -18,7 +18,7 @@ package com.android.server.pm; import android.annotation.Nullable; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.service.pm.PackageServiceDumpProto; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; @@ -46,7 +46,7 @@ public final class SharedUserSetting extends SettingBase { // that all apps within the sharedUser run in the same selinux context. int seInfoTargetSdkVersion; - final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>(); + final ArraySet<PackageSetting> packages = new ArraySet<>(); final PackageSignatures signatures = new PackageSignatures(); Boolean signaturesChanged; @@ -98,7 +98,7 @@ public final class SharedUserSetting extends SettingBase { // If this is the first package added to this shared user, temporarily (until next boot) use // its targetSdkVersion when assigning seInfo for the shared user. if ((packages.size() == 0) && (packageSetting.pkg != null)) { - seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion; + seInfoTargetSdkVersion = packageSetting.pkg.getTargetSdkVersion(); } if (packages.add(packageSetting)) { setFlags(this.pkgFlags | packageSetting.pkgFlags); @@ -106,11 +106,11 @@ public final class SharedUserSetting extends SettingBase { } } - public @Nullable List<PackageParser.Package> getPackages() { + public @Nullable List<AndroidPackage> getPackages() { if (packages == null || packages.size() == 0) { return null; } - final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size()); + final ArrayList<AndroidPackage> pkgList = new ArrayList<>(packages.size()); for (PackageSetting ps : packages) { if ((ps == null) || (ps.pkg == null)) { continue; @@ -131,20 +131,20 @@ public final class SharedUserSetting extends SettingBase { * restrictive selinux domain. */ public void fixSeInfoLocked() { - final List<PackageParser.Package> pkgList = getPackages(); + final List<AndroidPackage> pkgList = getPackages(); if (pkgList == null || pkgList.size() == 0) { return; } - for (PackageParser.Package pkg : pkgList) { - if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) { - seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion; + for (AndroidPackage pkg : pkgList) { + if (pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) { + seInfoTargetSdkVersion = pkg.getTargetSdkVersion(); } } - for (PackageParser.Package pkg : pkgList) { + for (AndroidPackage pkg : pkgList) { final boolean isPrivileged = isPrivileged() | pkg.isPrivileged(); - pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged, - seInfoTargetSdkVersion); + pkg.mutate().setSeInfo(SELinuxMMAC.getSeInfo(pkg, isPrivileged, + seInfoTargetSdkVersion)); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 5f8670809bfb..dace598a790b 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -3979,6 +3979,13 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public boolean isDeviceManaged() { + synchronized (mUsersLock) { + return mIsDeviceManaged; + } + } + + @Override public void setUserManaged(@UserIdInt int userId, boolean isManaged) { synchronized (mUsersLock) { mIsUserManaged.put(userId, isManaged); @@ -3986,6 +3993,13 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public boolean isUserManaged(@UserIdInt int userId) { + synchronized (mUsersLock) { + return mIsUserManaged.get(userId); + } + } + + @Override public void setUserIcon(@UserIdInt int userId, Bitmap bitmap) { long ident = Binder.clearCallingIdentity(); try { @@ -4205,6 +4219,7 @@ public class UserManagerService extends IUserManager.Stub { return restrictions != null && restrictions.getBoolean(restrictionKey); } + @Override public @Nullable UserInfo getUserInfo(@UserIdInt int userId) { UserData userData; synchronized (mUsersLock) { diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java index 036d1e807f97..793ea47bfd43 100644 --- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java +++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java @@ -23,6 +23,7 @@ import android.annotation.UserIdInt; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; import android.content.pm.UserInfo; +import android.content.pm.parsing.AndroidPackage; import android.content.res.Resources; import android.os.SystemProperties; import android.os.UserHandle; @@ -151,15 +152,15 @@ class UserSystemPackageInstaller { return; } final boolean install = - (userWhitelist == null || userWhitelist.contains(pkg.packageName)) - && !pkg.applicationInfo.hiddenUntilInstalled; + (userWhitelist == null || userWhitelist.contains(pkg.getPackageName())) + && !pkg.isHiddenUntilInstalled(); if (isUpgrade && !isFirstBoot && !install) { return; // To be careful, we don’t uninstall apps during OTAs } final boolean changed = pmInt.setInstalled(pkg, userId, install); if (changed) { Slog.i(TAG, (install ? "Installed " : "Uninstalled ") - + pkg.packageName + " for user " + userId); + + pkg.getPackageName() + " for user " + userId); } }); } @@ -180,7 +181,7 @@ class UserSystemPackageInstaller { // Check whether all whitelisted packages are indeed on the system. for (String pkgName : allWhitelistedPackages) { - PackageParser.Package pkg = pmInt.getPackage(pkgName); + AndroidPackage pkg = pmInt.getPackage(pkgName); if (pkg == null) { Slog.w(TAG, pkgName + " is whitelisted but not present."); } else if (!pkg.isSystem()) { @@ -194,8 +195,8 @@ class UserSystemPackageInstaller { } final boolean doWtf = isEnforceMode(mode); pmInt.forEachPackage(pkg -> { - if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.manifestPackageName)) { - final String msg = "System package " + pkg.manifestPackageName + if (pkg.isSystem() && !allWhitelistedPackages.contains(pkg.getManifestPackageName())) { + final String msg = "System package " + pkg.getManifestPackageName() + " is not whitelisted using 'install-in-user-type' in SystemConfig " + "for any user types!"; if (doWtf) { @@ -286,7 +287,7 @@ class UserSystemPackageInstaller { if (shouldInstallPackage(pkg, mWhitelitsedPackagesForUserTypes, whitelistedPackages, isImplicitWhitelistMode, isSystemUser)) { // Although the whitelist uses manifest names, this function returns packageNames. - installPackages.add(pkg.packageName); + installPackages.add(pkg.getPackageName()); } }); return installPackages; @@ -307,12 +308,12 @@ class UserSystemPackageInstaller { * @param isSystemUser whether the user is USER_SYSTEM (which gets special treatment). */ @VisibleForTesting - static boolean shouldInstallPackage(PackageParser.Package sysPkg, + static boolean shouldInstallPackage(AndroidPackage sysPkg, @NonNull ArrayMap<String, Integer> userTypeWhitelist, @NonNull Set<String> userWhitelist, boolean isImplicitWhitelistMode, boolean isSystemUser) { - final String pkgName = sysPkg.manifestPackageName; + final String pkgName = sysPkg.getManifestPackageName(); boolean install = (isImplicitWhitelistMode && !userTypeWhitelist.containsKey(pkgName)) || userWhitelist.contains(pkgName); diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java index b3f1867fdb06..661497cac332 100644 --- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -25,13 +25,13 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.dex.ArtManager; import android.content.pm.dex.ArtManager.ProfileType; import android.content.pm.dex.ArtManagerInternal; import android.content.pm.dex.DexMetadataHelper; import android.content.pm.dex.ISnapshotRuntimeProfileCallback; import android.content.pm.dex.PackageOptimizationInfo; +import android.content.pm.parsing.AndroidPackage; import android.os.Binder; import android.os.Build; import android.os.Handler; @@ -386,9 +386,10 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { * - create the current primary profile to save time at app startup time. * - copy the profiles from the associated dex metadata file to the reference profile. */ - public void prepareAppProfiles(PackageParser.Package pkg, @UserIdInt int user, + public void prepareAppProfiles( + AndroidPackage pkg, @UserIdInt int user, boolean updateReferenceProfileContent) { - final int appId = UserHandle.getAppId(pkg.applicationInfo.uid); + final int appId = UserHandle.getAppId(pkg.getUid()); if (user < 0) { Slog.wtf(TAG, "Invalid user id: " + user); return; @@ -411,23 +412,24 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { dexMetadataPath = dexMetadata == null ? null : dexMetadata.getAbsolutePath(); } synchronized (mInstaller) { - boolean result = mInstaller.prepareAppProfile(pkg.packageName, user, appId, + boolean result = mInstaller.prepareAppProfile(pkg.getPackageName(), user, appId, profileName, codePath, dexMetadataPath); if (!result) { Slog.e(TAG, "Failed to prepare profile for " + - pkg.packageName + ":" + codePath); + pkg.getPackageName() + ":" + codePath); } } } } catch (InstallerException e) { - Slog.e(TAG, "Failed to prepare profile for " + pkg.packageName, e); + Slog.e(TAG, "Failed to prepare profile for " + pkg.getPackageName(), e); } } /** * Prepares the app profiles for a set of users. {@see ArtManagerService#prepareAppProfiles}. */ - public void prepareAppProfiles(PackageParser.Package pkg, int[] user, + public void prepareAppProfiles( + AndroidPackage pkg, int[] user, boolean updateReferenceProfileContent) { for (int i = 0; i < user.length; i++) { prepareAppProfiles(pkg, user[i], updateReferenceProfileContent); @@ -437,12 +439,12 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { /** * Clear the profiles for the given package. */ - public void clearAppProfiles(PackageParser.Package pkg) { + public void clearAppProfiles(AndroidPackage pkg) { try { ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg); for (int i = packageProfileNames.size() - 1; i >= 0; i--) { String profileName = packageProfileNames.valueAt(i); - mInstaller.clearAppProfiles(pkg.packageName, profileName); + mInstaller.clearAppProfiles(pkg.getPackageName(), profileName); } } catch (InstallerException e) { Slog.w(TAG, String.valueOf(e)); @@ -452,15 +454,15 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { /** * Dumps the profiles for the given package. */ - public void dumpProfiles(PackageParser.Package pkg) { - final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + public void dumpProfiles(AndroidPackage pkg) { + final int sharedGid = UserHandle.getSharedAppGid(pkg.getUid()); try { ArrayMap<String, String> packageProfileNames = getPackageProfileNames(pkg); for (int i = packageProfileNames.size() - 1; i >= 0; i--) { String codePath = packageProfileNames.keyAt(i); String profileName = packageProfileNames.valueAt(i); synchronized (mInstallLock) { - mInstaller.dumpProfiles(sharedGid, pkg.packageName, profileName, codePath); + mInstaller.dumpProfiles(sharedGid, pkg.getPackageName(), profileName, codePath); } } } catch (InstallerException e) { @@ -471,14 +473,13 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { /** * Compile layout resources in a given package. */ - public boolean compileLayouts(PackageParser.Package pkg) { + public boolean compileLayouts(AndroidPackage pkg) { try { - final String packageName = pkg.packageName; - final String apkPath = pkg.baseCodePath; - final ApplicationInfo appInfo = pkg.applicationInfo; - final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex"; - if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed() - || appInfo.isDefaultToDeviceProtectedStorage()) { + final String packageName = pkg.getPackageName(); + final String apkPath = pkg.getBaseCodePath(); + final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex"; + if (pkg.isPrivileged() || pkg.isEmbeddedDexUsed() + || pkg.isDefaultToDeviceProtectedStorage()) { // Privileged apps prefer to load trusted code so they don't use compiled views. // If the app is not privileged but prefers code integrity, also avoid compiling // views. @@ -492,7 +493,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { try { synchronized (mInstallLock) { return mInstaller.compileLayouts(apkPath, packageName, outDexFile, - appInfo.uid); + pkg.getUid()); } } finally { Binder.restoreCallingIdentity(callingId); @@ -508,15 +509,19 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { * Build the profiles names for all the package code paths (excluding resource only paths). * Return the map [code path -> profile name]. */ - private ArrayMap<String, String> getPackageProfileNames(PackageParser.Package pkg) { + private ArrayMap<String, String> getPackageProfileNames(AndroidPackage pkg) { ArrayMap<String, String> result = new ArrayMap<>(); - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { - result.put(pkg.baseCodePath, ArtManager.getProfileName(null)); + if ((pkg.getFlags() & ApplicationInfo.FLAG_HAS_CODE) != 0) { + result.put(pkg.getBaseCodePath(), ArtManager.getProfileName(null)); } - if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) { - for (int i = 0; i < pkg.splitCodePaths.length; i++) { - if ((pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { - result.put(pkg.splitCodePaths[i], ArtManager.getProfileName(pkg.splitNames[i])); + + String[] splitCodePaths = pkg.getSplitCodePaths(); + int[] splitFlags = pkg.getSplitFlags(); + String[] splitNames = pkg.getSplitNames(); + if (!ArrayUtils.isEmpty(splitCodePaths)) { + for (int i = 0; i < splitCodePaths.length; i++) { + if ((splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0) { + result.put(splitCodePaths[i], ArtManager.getProfileName(splitNames[i])); } } } diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index f56231fc02af..5df5380ab8ab 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -595,7 +595,7 @@ public class DexManager { // We found the package. Now record the usage for all declared ISAs. boolean update = false; - for (String isa : getAppDexInstructionSets(info)) { + for (String isa : getAppDexInstructionSets(info.primaryCpuAbi, info.secondaryCpuAbi)) { boolean newUpdate = mPackageDexUsage.record(searchResult.mOwningPackageName, dexPath, userId, isa, isUsedByOtherApps, /*primaryOrSplit*/ false, searchResult.mOwningPackageName, diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java index 5a473c1819c1..6e6b137d23a2 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java +++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java @@ -18,10 +18,12 @@ package com.android.server.pm.dex; import android.content.pm.ApplicationInfo; import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.AndroidPackage; import android.util.Slog; import android.util.SparseArray; import com.android.internal.os.ClassLoaderFactory; +import com.android.internal.util.ArrayUtils; import java.io.File; import java.util.List; @@ -66,7 +68,7 @@ public final class DexoptUtils { * {@link android.app.LoadedApk#makePaths( * android.app.ActivityThread, boolean, ApplicationInfo, List, List)}. */ - public static String[] getClassLoaderContexts(ApplicationInfo info, + public static String[] getClassLoaderContexts(AndroidPackage pkg, List<SharedLibraryInfo> sharedLibraries, boolean[] pathsWithCode) { // The base class loader context contains only the shared library. String sharedLibrariesContext = ""; @@ -75,8 +77,8 @@ public final class DexoptUtils { } String baseApkContextClassLoader = encodeClassLoader( - "", info.classLoaderName, sharedLibrariesContext); - if (info.getSplitCodePaths() == null) { + "", pkg.getAppInfoClassLoaderName(), sharedLibrariesContext); + if (pkg.getSplitCodePaths() == null) { // The application has no splits. return new String[] {baseApkContextClassLoader}; } @@ -84,11 +86,11 @@ public final class DexoptUtils { // The application has splits. Compute their class loader contexts. // First, cache the relative paths of the splits and do some sanity checks - String[] splitRelativeCodePaths = getSplitRelativeCodePaths(info); + String[] splitRelativeCodePaths = getSplitRelativeCodePaths(pkg); // The splits have an implicit dependency on the base apk. // This means that we have to add the base apk file in addition to the shared libraries. - String baseApkName = new File(info.getBaseCodePath()).getName(); + String baseApkName = new File(pkg.getBaseCodePath()).getName(); String baseClassPath = baseApkName; // The result is stored in classLoaderContexts. @@ -97,7 +99,11 @@ public final class DexoptUtils { String[] classLoaderContexts = new String[/*base apk*/ 1 + splitRelativeCodePaths.length]; classLoaderContexts[0] = pathsWithCode[0] ? baseApkContextClassLoader : null; - if (!info.requestsIsolatedSplitLoading() || info.splitDependencies == null) { + SparseArray<int[]> splitDependencies = pkg.getSplitDependencies(); + + if (!pkg.requestsIsolatedSplitLoading() + || splitDependencies == null + || splitDependencies.size() == 0) { // If the app didn't request for the splits to be loaded in isolation or if it does not // declare inter-split dependencies, then all the splits will be loaded in the base // apk class loader (in the order of their definition). @@ -105,7 +111,7 @@ public final class DexoptUtils { for (int i = 1; i < classLoaderContexts.length; i++) { if (pathsWithCode[i]) { classLoaderContexts[i] = encodeClassLoader( - classpath, info.classLoaderName, sharedLibrariesContext); + classpath, pkg.getAppInfoClassLoaderName(), sharedLibrariesContext); } else { classLoaderContexts[i] = null; } @@ -132,11 +138,10 @@ public final class DexoptUtils { String[] splitClassLoaderEncodingCache = new String[splitRelativeCodePaths.length]; for (int i = 0; i < splitRelativeCodePaths.length; i++) { splitClassLoaderEncodingCache[i] = encodeClassLoader(splitRelativeCodePaths[i], - info.splitClassLoaderNames[i]); + pkg.getSplitClassLoaderNames()[i]); } String splitDependencyOnBase = encodeClassLoader( - baseClassPath, info.classLoaderName); - SparseArray<int[]> splitDependencies = info.splitDependencies; + baseClassPath, pkg.getClassLoaderName()); // Note that not all splits have dependencies (e.g. configuration splits) // The splits without dependencies will have classLoaderContexts[config_split_index] @@ -154,7 +159,8 @@ public final class DexoptUtils { // We also need to add the class loader of the current split which should // come first in the context. for (int i = 1; i < classLoaderContexts.length; i++) { - String splitClassLoader = encodeClassLoader("", info.splitClassLoaderNames[i - 1]); + String splitClassLoader = encodeClassLoader("", + pkg.getSplitClassLoaderNames()[i - 1]); if (pathsWithCode[i]) { // If classLoaderContexts[i] is null it means that the split does not have // any dependency. In this case its context equals its declared class loader. @@ -394,11 +400,11 @@ public final class DexoptUtils { * Returns the relative paths of the splits declared by the application {@code info}. * Assumes that the application declares a non-null array of splits. */ - private static String[] getSplitRelativeCodePaths(ApplicationInfo info) { - String baseCodePath = new File(info.getBaseCodePath()).getParent(); - String[] splitCodePaths = info.getSplitCodePaths(); - String[] splitRelativeCodePaths = new String[splitCodePaths.length]; - for (int i = 0; i < splitCodePaths.length; i++) { + private static String[] getSplitRelativeCodePaths(AndroidPackage pkg) { + String baseCodePath = new File(pkg.getBaseCodePath()).getParent(); + String[] splitCodePaths = pkg.getSplitCodePaths(); + String[] splitRelativeCodePaths = new String[ArrayUtils.size(splitCodePaths)]; + for (int i = 0; i < splitRelativeCodePaths.length; i++) { File pathFile = new File(splitCodePaths[i]); splitRelativeCodePaths[i] = pathFile.getName(); // Sanity check that the base paths of the splits are all the same. diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java index 8d8e17e92b3d..b7443f36e494 100644 --- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java +++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java @@ -16,10 +16,10 @@ package com.android.server.pm.dex; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; import android.os.Binder; import android.util.Log; + import com.android.internal.annotations.GuardedBy; import com.android.server.pm.Installer; @@ -33,19 +33,18 @@ public class ViewCompiler { mInstaller = installer; } - public boolean compileLayouts(PackageParser.Package pkg) { + public boolean compileLayouts(AndroidPackage pkg) { try { - final String packageName = pkg.packageName; - final String apkPath = pkg.baseCodePath; - final ApplicationInfo appInfo = pkg.applicationInfo; - final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex"; + final String packageName = pkg.getPackageName(); + final String apkPath = pkg.getBaseCodePath(); + final String outDexFile = pkg.getDataDir() + "/code_cache/compiled_view.dex"; Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath + ") to " + outDexFile); long callingId = Binder.clearCallingIdentity(); try { synchronized (mInstallLock) { return mInstaller.compileLayouts(apkPath, packageName, outDexFile, - appInfo.uid); + pkg.getUid()); } } finally { Binder.restoreCallingIdentity(callingId); diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java index 6d22faa7032e..29248b50830a 100644 --- a/services/core/java/com/android/server/pm/permission/BasePermission.java +++ b/services/core/java/com/android/server/pm/permission/BasePermission.java @@ -29,10 +29,12 @@ import static com.android.server.pm.Settings.TAG_ITEM; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Permission; +import android.content.pm.PackageManagerInternal; import android.content.pm.PermissionInfo; import android.content.pm.Signature; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.PackageInfoUtils; import android.os.UserHandle; import android.util.Log; import android.util.Slog; @@ -89,7 +91,7 @@ public final class BasePermission { int protectionLevel; - PackageParser.Permission perm; + ParsedPermission perm; PermissionInfo pendingPermissionInfo; @@ -113,12 +115,6 @@ public final class BasePermission { protectionLevel = PermissionInfo.PROTECTION_SIGNATURE; } - @Override - public String toString() { - return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name - + "}"; - } - public String getName() { return name; } @@ -144,7 +140,7 @@ public final class BasePermission { this.gids = gids; this.perUser = perUser; } - public void setPermission(@Nullable Permission perm) { + public void setPermission(@Nullable ParsedPermission perm) { this.perm = perm; } public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) { @@ -165,13 +161,13 @@ public final class BasePermission { public int calculateFootprint(BasePermission perm) { if (uid == perm.uid) { - return perm.name.length() + perm.perm.info.calculateFootprint(); + return perm.name.length() + perm.perm.calculateFootprint(); } return 0; } - public boolean isPermission(Permission perm) { - return this.perm == perm; + public boolean isPermission(ParsedPermission perm) { + return Objects.equals(this.perm.className, perm.className); } public boolean isDynamic() { @@ -189,29 +185,24 @@ public final class BasePermission { } public boolean isRemoved() { - return perm != null && perm.info != null - && (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0; + return perm != null && (perm.flags & PermissionInfo.FLAG_REMOVED) != 0; } public boolean isSoftRestricted() { - return perm != null && perm.info != null - && (perm.info.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0; + return perm != null && (perm.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0; } public boolean isHardRestricted() { - return perm != null && perm.info != null - && (perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; + return perm != null && (perm.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0; } public boolean isHardOrSoftRestricted() { - return perm != null && perm.info != null - && (perm.info.flags & (PermissionInfo.FLAG_HARD_RESTRICTED + return perm != null && (perm.flags & (PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0; } public boolean isImmutablyRestricted() { - return perm != null && perm.info != null - && (perm.info.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0; + return perm != null && (perm.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0; } public boolean isSignature() { @@ -297,13 +288,12 @@ public final class BasePermission { (this.protectionLevel != protectionLevel || perm == null || uid != tree.uid - || !perm.owner.equals(tree.perm.owner) - || !comparePermissionInfos(perm.info, info)); + || !Objects.equals(perm.getPackageName(), tree.perm.getPackageName()) + || !comparePermissionInfos(perm, info)); this.protectionLevel = protectionLevel; info = new PermissionInfo(info); info.protectionLevel = protectionLevel; - perm = new PackageParser.Permission(tree.perm.owner, info); - perm.info.packageName = tree.perm.info.packageName; + perm = new ParsedPermission(tree.perm); uid = tree.uid; return changed; } @@ -316,71 +306,89 @@ public final class BasePermission { final BasePermission tree = findPermissionTree(permissionTrees, name); if (tree != null && tree.perm != null) { sourcePackageSetting = tree.sourcePackageSetting; - perm = new PackageParser.Permission(tree.perm.owner, - new PermissionInfo(pendingPermissionInfo)); - perm.info.packageName = tree.perm.info.packageName; - perm.info.name = name; + perm = new ParsedPermission(tree.perm); + perm.protectionLevel = pendingPermissionInfo.protectionLevel; + perm.flags = pendingPermissionInfo.flags; + perm.setGroup(pendingPermissionInfo.group); + perm.backgroundPermission = pendingPermissionInfo.backgroundPermission; + perm.descriptionRes = pendingPermissionInfo.descriptionRes; + perm.requestRes = pendingPermissionInfo.requestRes; + perm.setPackageName(tree.perm.getPackageName()); + perm.setName(name); uid = tree.uid; } } } - static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p, - @NonNull PackageParser.Package pkg, Collection<BasePermission> permissionTrees, + static BasePermission createOrUpdate(PackageManagerInternal packageManagerInternal, + @Nullable BasePermission bp, @NonNull ParsedPermission p, + @NonNull AndroidPackage pkg, Collection<BasePermission> permissionTrees, boolean chatty) { - final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras; + final PackageSettingBase pkgSetting = + (PackageSettingBase) packageManagerInternal.getPackageSetting(pkg.getPackageName()); // Allow system apps to redefine non-system permissions - if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) { - final boolean currentOwnerIsSystem = (bp.perm != null - && bp.perm.owner.isSystem()); - if (p.owner.isSystem()) { + if (bp != null && !Objects.equals(bp.sourcePackageName, p.getPackageName())) { + final boolean currentOwnerIsSystem; + if (bp.perm == null) { + currentOwnerIsSystem = false; + } else { + AndroidPackage currentPackage = packageManagerInternal.getPackage( + bp.perm.getPackageName()); + if (currentPackage == null) { + currentOwnerIsSystem = false; + } else { + currentOwnerIsSystem = currentPackage.isSystem(); + } + } + + if (pkg.isSystem()) { if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) { // It's a built-in permission and no owner, take ownership now + p.flags |= PermissionInfo.FLAG_INSTALLED; bp.sourcePackageSetting = pkgSetting; bp.perm = p; - bp.uid = pkg.applicationInfo.uid; - bp.sourcePackageName = p.info.packageName; - p.info.flags |= PermissionInfo.FLAG_INSTALLED; + bp.uid = pkg.getUid(); + bp.sourcePackageName = p.getPackageName(); } else if (!currentOwnerIsSystem) { - String msg = "New decl " + p.owner + " of permission " - + p.info.name + " is system; overriding " + bp.sourcePackageName; + String msg = "New decl " + pkg + " of permission " + + p.getName() + " is system; overriding " + bp.sourcePackageName; PackageManagerService.reportSettingsProblem(Log.WARN, msg); bp = null; } } } if (bp == null) { - bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL); + bp = new BasePermission(p.getName(), p.getPackageName(), TYPE_NORMAL); } StringBuilder r = null; if (bp.perm == null) { if (bp.sourcePackageName == null - || bp.sourcePackageName.equals(p.info.packageName)) { - final BasePermission tree = findPermissionTree(permissionTrees, p.info.name); + || bp.sourcePackageName.equals(p.getPackageName())) { + final BasePermission tree = findPermissionTree(permissionTrees, p.getName()); if (tree == null - || tree.sourcePackageName.equals(p.info.packageName)) { + || tree.sourcePackageName.equals(p.getPackageName())) { + p.flags |= PermissionInfo.FLAG_INSTALLED; bp.sourcePackageSetting = pkgSetting; bp.perm = p; - bp.uid = pkg.applicationInfo.uid; - bp.sourcePackageName = p.info.packageName; - p.info.flags |= PermissionInfo.FLAG_INSTALLED; + bp.uid = pkg.getUid(); + bp.sourcePackageName = p.getPackageName(); if (chatty) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } - r.append(p.info.name); + r.append(p.getName()); } } else { - Slog.w(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " ignored: base tree " + Slog.w(TAG, "Permission " + p.getName() + " from package " + + p.getPackageName() + " ignored: base tree " + tree.name + " is from package " + tree.sourcePackageName); } } else { - Slog.w(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " ignored: original from " + Slog.w(TAG, "Permission " + p.getName() + " from package " + + p.getPackageName() + " ignored: original from " + bp.sourcePackageName); } } else if (chatty) { @@ -390,10 +398,10 @@ public final class BasePermission { r.append(' '); } r.append("DUP:"); - r.append(p.info.name); + r.append(p.getName()); } - if (bp.perm == p) { - bp.protectionLevel = p.info.protectionLevel; + if (bp.perm != null && Objects.equals(bp.perm.className, p.className)) { + bp.protectionLevel = p.protectionLevel; } if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { Log.d(TAG, " Permissions: " + r); @@ -417,17 +425,17 @@ public final class BasePermission { throw new SecurityException("No permission tree found for " + permName); } - public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) { - final PackageSetting pkgSetting = (PackageSetting) pkg.mExtras; + public void enforceDeclaredUsedAndRuntimeOrDevelopment(AndroidPackage pkg, + PackageSetting pkgSetting) { final PermissionsState permsState = pkgSetting.getPermissionsState(); - int index = pkg.requestedPermissions.indexOf(name); + int index = pkg.getRequestedPermissions().indexOf(name); if (!permsState.hasRequestedPermission(name) && index == -1) { - throw new SecurityException("Package " + pkg.packageName + throw new SecurityException("Package " + pkg.getPackageName() + " has not requested permission " + name); } if (!isRuntime() && !isDevelopment()) { - throw new SecurityException("Permission " + name - + " requested by " + pkg.packageName + " is not a changeable permission type"); + throw new SecurityException("Permission " + name + " requested by " + + pkg.getPackageName() + " is not a changeable permission type"); } } @@ -445,12 +453,12 @@ public final class BasePermission { public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) { if (groupName == null) { - if (perm == null || perm.info.group == null) { + if (perm == null || perm.getGroup() == null) { return generatePermissionInfo(protectionLevel, flags); } } else { - if (perm != null && groupName.equals(perm.info.group)) { - return PackageParser.generatePermissionInfo(perm, flags); + if (perm != null && groupName.equals(perm.getGroup())) { + return PackageInfoUtils.generatePermissionInfo(perm, flags); } } return null; @@ -460,8 +468,8 @@ public final class BasePermission { PermissionInfo permissionInfo; if (perm != null) { final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel; - permissionInfo = PackageParser.generatePermissionInfo(perm, flags); - if (protectionLevelChanged && permissionInfo == perm.info) { + permissionInfo = PackageInfoUtils.generatePermissionInfo(perm, flags); + if (protectionLevelChanged) { // if we return different protection level, don't use the cached info permissionInfo = new PermissionInfo(permissionInfo); permissionInfo.protectionLevel = adjustedProtectionLevel; @@ -541,14 +549,18 @@ public final class BasePermission { serializer.attribute(null, "protection", Integer.toString(protectionLevel)); } if (type == BasePermission.TYPE_DYNAMIC) { - final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo; - if (pi != null) { + if (perm != null || pendingPermissionInfo != null) { serializer.attribute(null, "type", "dynamic"); - if (pi.icon != 0) { - serializer.attribute(null, "icon", Integer.toString(pi.icon)); + int icon = perm != null ? perm.icon : pendingPermissionInfo.icon; + CharSequence nonLocalizedLabel = perm != null + ? perm.nonLocalizedLabel + : pendingPermissionInfo.nonLocalizedLabel; + + if (icon != 0) { + serializer.attribute(null, "icon", Integer.toString(icon)); } - if (pi.nonLocalizedLabel != null) { - serializer.attribute(null, "label", pi.nonLocalizedLabel.toString()); + if (nonLocalizedLabel != null) { + serializer.attribute(null, "label", nonLocalizedLabel.toString()); } } } @@ -568,14 +580,14 @@ public final class BasePermission { return s1.equals(s2); } - private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) { + private static boolean comparePermissionInfos(ParsedPermission pi1, PermissionInfo pi2) { if (pi1.icon != pi2.icon) return false; if (pi1.logo != pi2.logo) return false; if (pi1.protectionLevel != pi2.protectionLevel) return false; - if (!compareStrings(pi1.name, pi2.name)) return false; + if (!compareStrings(pi1.getName(), pi2.name)) return false; if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false; // We'll take care of setting this one. - if (!compareStrings(pi1.packageName, pi2.packageName)) return false; + if (!compareStrings(pi1.getPackageName(), pi2.packageName)) return false; // These are not currently stored in settings. //if (!compareStrings(pi1.group, pi2.group)) return false; //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false; @@ -611,9 +623,9 @@ public final class BasePermission { pw.println(PermissionInfo.protectionToString(protectionLevel)); if (perm != null) { pw.print(" perm="); pw.println(perm); - if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0 - || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) { - pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.info.flags)); + if ((perm.flags & PermissionInfo.FLAG_INSTALLED) == 0 + || (perm.flags & PermissionInfo.FLAG_REMOVED) != 0) { + pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.flags)); } } if (sourcePackageSetting != null) { @@ -625,4 +637,20 @@ public final class BasePermission { } return true; } + + @Override + public String toString() { + return "BasePermission{" + + "name='" + name + '\'' + + ", type=" + type + + ", sourcePackageName='" + sourcePackageName + '\'' + + ", sourcePackageSetting=" + sourcePackageSetting + + ", protectionLevel=" + protectionLevel + + ", perm=" + perm + + ", pendingPermissionInfo=" + pendingPermissionInfo + + ", uid=" + uid + + ", gids=" + Arrays.toString(gids) + + ", perUser=" + perUser + + '}'; + } } diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index b831374cec45..fc8d52005a1c 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -64,10 +64,13 @@ import android.content.pm.PackageManager.PermissionInfoFlags; import android.content.pm.PackageManager.PermissionWhitelistFlags; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Package; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.PackageInfoUtils; import android.content.pm.permission.SplitPermissionInfoParcelable; import android.metrics.LogMaker; import android.os.Binder; @@ -420,7 +423,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - @Nullable BasePermission getPermission(String permName) { + @Nullable + BasePermission getPermission(String permName) { synchronized (mLock) { return mSettings.getPermissionLocked(permName); } @@ -454,10 +458,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { } synchronized (mLock) { final int n = mSettings.mPermissionGroups.size(); - final ArrayList<PermissionGroupInfo> out = - new ArrayList<PermissionGroupInfo>(n); - for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) { - out.add(PackageParser.generatePermissionGroupInfo(pg, flags)); + final ArrayList<PermissionGroupInfo> out = new ArrayList<>(n); + for (ParsedPermissionGroup pg : mSettings.mPermissionGroups.values()) { + out.add(PackageInfoUtils.generatePermissionGroupInfo(pg, flags)); } return new ParceledListSlice<>(out); } @@ -473,7 +476,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return null; } synchronized (mLock) { - return PackageParser.generatePermissionGroupInfo( + return PackageInfoUtils.generatePermissionGroupInfo( mSettings.mPermissionGroups.get(groupName), flags); } } @@ -597,8 +600,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { false, // requirePermissionWhenSameUser "getPermissionFlags"); - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); - if (pkg == null || pkg.mExtras == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + if (pkg == null) { + return 0; + } + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); + if (ps == null) { return 0; } synchronized (mLock) { @@ -609,7 +617,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) { return 0; } - final PackageSetting ps = (PackageSetting) pkg.mExtras; PermissionsState permissionsState = ps.getPermissionsState(); return permissionsState.getPermissionFlags(permName, userId); } @@ -696,8 +703,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { flagValues &= ~PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; } - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); - if (pkg == null || pkg.mExtras == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + packageName); + if (pkg == null || ps == null) { Log.e(TAG, "Unknown package: " + packageName); return; } @@ -713,7 +722,6 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown permission: " + permName); } - final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); final boolean hadState = permissionsState.getRuntimePermissionState(permName, userId) != null; @@ -726,11 +734,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Install and runtime permissions are stored in different places, // so figure out what permission changed and persist the change. if (permissionsState.getInstallPermissionState(permName) != null) { - callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid); + callback.onInstallPermissionUpdatedNotifyListener(pkg.getUid()); } else if (permissionsState.getRuntimePermissionState(permName, userId) != null || hadState) { - callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false, - pkg.applicationInfo.uid); + callback.onPermissionUpdatedNotifyListener(new int[]{userId}, false, + pkg.getUid()); } } } @@ -762,18 +770,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { ? flagValues : flagValues & ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED; final boolean[] changed = new boolean[1]; - mPackageManagerInt.forEachPackage(new Consumer<PackageParser.Package>() { - @Override - public void accept(Package pkg) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; - if (ps == null) { - return; - } - final PermissionsState permissionsState = ps.getPermissionsState(); - changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions( - userId, effectiveFlagMask, effectiveFlagValues); - mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid); + mPackageManagerInt.forEachPackage(pkg -> { + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); + if (ps == null) { + return; } + final PermissionsState permissionsState = ps.getPermissionsState(); + changed[0] |= permissionsState.updatePermissionFlagsForAllPermissions( + userId, effectiveFlagMask, effectiveFlagValues); + mOnPermissionChangeListeners.onPermissionsChanged(pkg.getUid()); }); if (changed[0]) { @@ -804,7 +810,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { private int checkPermissionImpl(@NonNull String permissionName, @NonNull String packageName, @UserIdInt int userId) { - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null) { return PackageManager.PERMISSION_DENIED; } @@ -812,11 +818,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED; } - private boolean checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit, + private boolean checkPermissionInternal(@NonNull AndroidPackage pkg, boolean isPackageExplicit, @NonNull String permissionName, boolean useRequestedPermissionsForLegacyApps, @UserIdInt int userId) { final int callingUid = getCallingUid(); - if (isPackageExplicit || pkg.mSharedUserId == null) { + if (isPackageExplicit || pkg.getSharedUserId() == null) { if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) { return false; } @@ -826,8 +832,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid); - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final int uid = UserHandle.getUid(userId, pkg.getUid()); + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); if (ps == null) { return false; } @@ -858,9 +865,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); final int packageNamesSize = packageNames != null ? packageNames.length : 0; for (int i = 0; i < packageNamesSize; i++) { - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageNames[i]); - if (pkg != null && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M - && pkg.requestedPermissions.contains(permissionName)) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageNames[i]); + if (pkg != null && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M + && pkg.getRequestedPermissions().contains(permissionName)) { hasPermission = true; break; } @@ -901,7 +908,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private int checkUidPermissionImpl(@NonNull String permissionName, int uid) { - final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid); + final AndroidPackage pkg = mPackageManagerInt.getPackage(uid); return checkUidPermissionInternal(uid, pkg, permissionName, true) ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED; } @@ -913,7 +920,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * * @see SystemConfig#getSystemPermissions() */ - private boolean checkUidPermissionInternal(int uid, @Nullable Package pkg, + private boolean checkUidPermissionInternal(int uid, @Nullable AndroidPackage pkg, @NonNull String permissionName, boolean useRequestedPermissionsForLegacyApps) { if (pkg != null) { final int userId = UserHandle.getUserId(uid); @@ -948,7 +955,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } private boolean isUidPermissionGranted(int uid, @NonNull String permissionName) { - final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid); + final AndroidPackage pkg = mPackageManagerInt.getPackage(uid); return checkUidPermissionInternal(uid, pkg, permissionName, false); } @@ -989,7 +996,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { "getWhitelistedRestrictedPermissions for user " + userId); } - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null) { return null; } @@ -1022,7 +1029,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final long identity = Binder.clearCallingIdentity(); try { final PermissionsState permissionsState = - PackageManagerServiceUtils.getPermissionsState(pkg); + PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg); if (permissionsState == null) { return null; } @@ -1040,9 +1047,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArrayList<String> whitelistedPermissions = null; - final int permissionCount = pkg.requestedPermissions.size(); + final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions()); for (int i = 0; i < permissionCount; i++) { - final String permissionName = pkg.requestedPermissions.get(i); + final String permissionName = pkg.getRequestedPermissions().get(i); final int currentFlags = permissionsState.getPermissionFlags(permissionName, userId); if ((currentFlags & queryFlags) != 0) { @@ -1139,7 +1146,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { "setWhitelistedRestrictedPermissions for user " + userId); } - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null) { return false; } @@ -1168,7 +1175,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS); } final List<String> whitelistedPermissions = - getWhitelistedRestrictedPermissions(pkg.packageName, flags, userId); + getWhitelistedRestrictedPermissions(pkg.getPackageName(), flags, userId); if (permissions == null || permissions.isEmpty()) { if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) { return true; @@ -1242,8 +1249,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { false, // requirePermissionWhenSameUser "grantRuntimePermission"); - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); - if (pkg == null || pkg.mExtras == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + packageName); + if (pkg == null || ps == null) { Log.e(TAG, "Unknown package: " + packageName); return; } @@ -1258,21 +1267,19 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown package: " + packageName); } - bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg); + bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps); // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) { return; } - final int uid = UserHandle.getUid(userId, - UserHandle.getAppId(pkg.applicationInfo.uid)); + final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid())); - final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); final int flags = permissionsState.getPermissionFlags(permName, userId); @@ -1295,7 +1302,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext, - pkg.applicationInfo, UserHandle.of(userId), permName).canBeGranted()) { + pkg.toAppInfo(), UserHandle.of(userId), permName).mayGrantPermission()) { Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package " + packageName); return; @@ -1318,7 +1325,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { + permName + " for package " + packageName); } - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) { Slog.w(TAG, "Cannot grant runtime permission to a legacy app"); return; } @@ -1331,7 +1338,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: { if (callback != null) { - callback.onGidsChanged(UserHandle.getAppId(pkg.applicationInfo.uid), userId); + callback.onGidsChanged(UserHandle.getAppId(pkg.getUid()), userId); } } break; @@ -1404,8 +1411,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { false, // requirePermissionWhenSameUser "revokeRuntimePermission"); - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); - if (pkg == null || pkg.mExtras == null) { + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + packageName); + if (pkg == null || ps == null) { Log.e(TAG, "Unknown package: " + packageName); return; } @@ -1417,18 +1426,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { throw new IllegalArgumentException("Unknown permission: " + permName); } - bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg); + bp.enforceDeclaredUsedAndRuntimeOrDevelopment(pkg, ps); // If a permission review is required for legacy apps we represent // their permissions as always granted runtime ones since we need // to keep the review required permission flag per user while an // install permission's state is shared across all users. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && bp.isRuntime()) { return; } - final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); final int flags = permissionsState.getPermissionFlags(permName, userId); @@ -1471,7 +1479,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (callback != null) { callback.onPermissionRevoked(UserHandle.getUid(userId, - UserHandle.getAppId(pkg.applicationInfo.uid)), userId); + UserHandle.getAppId(pkg.getUid())), userId); } if (bp.isRuntime()) { @@ -1496,7 +1504,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { StorageManager.UUID_PRIVATE_INTERNAL, false, mDefaultPermissionCallback); for (final int userId : UserManagerService.getInstance().getUserIds()) { mPackageManagerInt.forEachPackage( - (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId)); + (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId)); } } @@ -1507,9 +1515,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param userId The device user for which to do a reset. */ @GuardedBy("mLock") - private void resetRuntimePermissionsInternal(final PackageParser.Package pkg, + private void resetRuntimePermissionsInternal(final AndroidPackage pkg, final int userId) { - final String packageName = pkg.packageName; + final String packageName = pkg.getPackageName(); // These are flags that can change base on user actions. final int userSettableMask = FLAG_PERMISSION_USER_SET @@ -1521,7 +1529,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { | FLAG_PERMISSION_POLICY_FIXED; // Delay and combine non-async permission callbacks - final int permissionCount = pkg.requestedPermissions.size(); + final int permissionCount = ArrayUtils.size(pkg.getRequestedPermissions()); final boolean[] permissionRemoved = new boolean[1]; final ArraySet<Long> revokedPermissions = new ArraySet<>(); final IntArray syncUpdatedUsers = new IntArray(permissionCount); @@ -1579,7 +1587,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); for (int i = 0; i < permissionCount; i++) { - final String permName = pkg.requestedPermissions.get(i); + final String permName = pkg.getRequestedPermissions().get(i); final BasePermission bp; synchronized (mLock) { bp = mSettings.getPermissionLocked(permName); @@ -1594,7 +1602,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // If shared user we just reset the state to which only this app contributed. final String sharedUserId = - mPackageManagerInt.getSharedUserIdForPackage(pkg.packageName); + mPackageManagerInt.getSharedUserIdForPackage(pkg.getPackageName()); final String[] pkgNames = mPackageManagerInt.getPackagesForSharedUserId(sharedUserId, userId); if (pkgNames != null && pkgNames.length > 0) { @@ -1602,10 +1610,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int packageCount = pkgNames.length; for (int j = 0; j < packageCount; j++) { final String sharedPkgName = pkgNames[j]; - final PackageParser.Package sharedPkg = + final AndroidPackage sharedPkg = mPackageManagerInt.getPackage(sharedPkgName); - if (sharedPkg != null && !sharedPkg.packageName.equals(packageName) - && sharedPkg.requestedPermissions.contains(permName)) { + if (sharedPkg != null && !sharedPkg.getPackageName().equals(packageName) + && sharedPkg.getRequestedPermissions().contains(permName)) { used = true; break; } @@ -1697,10 +1705,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { return null; } + DefaultBrowserProvider provider; synchronized (mLock) { - return mDefaultBrowserProvider == null - ? null : mDefaultBrowserProvider.getDefaultBrowser(userId); + provider = mDefaultBrowserProvider; } + return provider != null ? provider.getDefaultBrowser(userId) : null; } @Override @@ -1716,23 +1725,27 @@ public class PermissionManagerService extends IPermissionManager.Stub { private boolean setDefaultBrowserInternal(String packageName, boolean async, boolean doGrant, int userId) { + if (userId == UserHandle.USER_ALL) { + return false; + } + DefaultBrowserProvider provider; synchronized (mLock) { - if (userId == UserHandle.USER_ALL) { - return false; - } - if (mDefaultBrowserProvider == null) { + provider = mDefaultBrowserProvider; + } + if (provider == null) { + return false; + } + if (async) { + provider.setDefaultBrowserAsync(packageName, userId); + } else { + if (!provider.setDefaultBrowser(packageName, userId)) { return false; } - if (async) { - mDefaultBrowserProvider.setDefaultBrowserAsync(packageName, userId); - } else { - if (!mDefaultBrowserProvider.setDefaultBrowser(packageName, userId)) { - return false; - } - } - if (doGrant && packageName != null) { - mDefaultPermissionGrantPolicy - .grantDefaultPermissionsToDefaultBrowser(packageName, userId); + } + if (doGrant && packageName != null) { + synchronized (mLock) { + mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName, + userId); } } return true; @@ -2028,15 +2041,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { return protectionLevel; } // Normalize package name to handle renamed packages and static libs - final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); + final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName); if (pkg == null) { return protectionLevel; } - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.O) { + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.O) { return protectionLevelMasked; } // Apps that target O see flags for all protection levels. - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); if (ps == null) { return protectionLevel; } @@ -2057,35 +2071,35 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param permissionCallback Callback for permission changed */ private void revokeRuntimePermissionsIfGroupChanged( - @NonNull PackageParser.Package newPackage, - @NonNull PackageParser.Package oldPackage, + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage, @NonNull ArrayList<String> allPackageNames, @NonNull PermissionCallback permissionCallback) { - final int numOldPackagePermissions = oldPackage.permissions.size(); + final int numOldPackagePermissions = ArrayUtils.size(oldPackage.getPermissions()); final ArrayMap<String, String> oldPermissionNameToGroupName = new ArrayMap<>(numOldPackagePermissions); for (int i = 0; i < numOldPackagePermissions; i++) { - final PackageParser.Permission permission = oldPackage.permissions.get(i); + final ParsedPermission permission = oldPackage.getPermissions().get(i); - if (permission.group != null) { - oldPermissionNameToGroupName.put(permission.info.name, - permission.group.info.name); + if (permission.parsedPermissionGroup != null) { + oldPermissionNameToGroupName.put(permission.getName(), + permission.parsedPermissionGroup.getName()); } } final int callingUid = Binder.getCallingUid(); - final int numNewPackagePermissions = newPackage.permissions.size(); + final int numNewPackagePermissions = ArrayUtils.size(newPackage.getPermissions()); for (int newPermissionNum = 0; newPermissionNum < numNewPackagePermissions; newPermissionNum++) { - final PackageParser.Permission newPermission = - newPackage.permissions.get(newPermissionNum); - final int newProtection = newPermission.info.getProtection(); + final ParsedPermission newPermission = + newPackage.getPermissions().get(newPermissionNum); + final int newProtection = newPermission.getProtection(); if ((newProtection & PermissionInfo.PROTECTION_DANGEROUS) != 0) { - final String permissionName = newPermission.info.name; - final String newPermissionGroupName = - newPermission.group == null ? null : newPermission.group.info.name; + final String permissionName = newPermission.getName(); + final String newPermissionGroupName = newPermission.parsedPermissionGroup == null + ? null : newPermission.parsedPermissionGroup.getName(); final String oldPermissionGroupName = oldPermissionNameToGroupName.get( permissionName); @@ -2103,7 +2117,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { userId); if (permissionState == PackageManager.PERMISSION_GRANTED) { EventLog.writeEvent(0x534e4554, "72710897", - newPackage.applicationInfo.uid, + newPackage.getUid(), "Revoking permission " + permissionName + " from package " + packageName + " as the group changed from " + oldPermissionGroupName + @@ -2124,54 +2138,56 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void addAllPermissions(PackageParser.Package pkg, boolean chatty) { - final int N = pkg.permissions.size(); + private void addAllPermissions(AndroidPackage pkg, boolean chatty) { + final int N = ArrayUtils.size(pkg.getPermissions()); for (int i=0; i<N; i++) { - PackageParser.Permission p = pkg.permissions.get(i); + ParsedPermission p = pkg.getPermissions().get(i); // Assume by default that we did not install this permission into the system. - p.info.flags &= ~PermissionInfo.FLAG_INSTALLED; + p.flags &= ~PermissionInfo.FLAG_INSTALLED; synchronized (PermissionManagerService.this.mLock) { // Now that permission groups have a special meaning, we ignore permission // groups for legacy apps to prevent unexpected behavior. In particular, // permissions for one app being granted to someone just because they happen // to be in a group defined by another app (before this had no implications). - if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { - p.group = mSettings.mPermissionGroups.get(p.info.group); + if (pkg.getTargetSdkVersion() > Build.VERSION_CODES.LOLLIPOP_MR1) { + p.parsedPermissionGroup = mSettings.mPermissionGroups.get(p.getGroup()); // Warn for a permission in an unknown group. if (DEBUG_PERMISSIONS - && p.info.group != null && p.group == null) { - Slog.i(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " in an unknown group " + p.info.group); + && p.getGroup() != null && p.parsedPermissionGroup == null) { + Slog.i(TAG, "Permission " + p.getName() + " from package " + + p.getPackageName() + " in an unknown group " + p.getGroup()); } } if (p.tree) { final BasePermission bp = BasePermission.createOrUpdate( - mSettings.getPermissionTreeLocked(p.info.name), p, pkg, + mPackageManagerInt, + mSettings.getPermissionTreeLocked(p.getName()), p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); - mSettings.putPermissionTreeLocked(p.info.name, bp); + mSettings.putPermissionTreeLocked(p.getName(), bp); } else { final BasePermission bp = BasePermission.createOrUpdate( - mSettings.getPermissionLocked(p.info.name), + mPackageManagerInt, + mSettings.getPermissionLocked(p.getName()), p, pkg, mSettings.getAllPermissionTreesLocked(), chatty); - mSettings.putPermissionLocked(p.info.name, bp); + mSettings.putPermissionLocked(p.getName(), bp); } } } } - private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) { - final int N = pkg.permissionGroups.size(); + private void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { + final int N = ArrayUtils.size(pkg.getPermissionGroups()); StringBuilder r = null; for (int i=0; i<N; i++) { - final PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i); - final PackageParser.PermissionGroup cur = mSettings.mPermissionGroups.get(pg.info.name); - final String curPackageName = (cur == null) ? null : cur.info.packageName; - final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName); + final ParsedPermissionGroup pg = pkg.getPermissionGroups().get(i); + final ParsedPermissionGroup cur = mSettings.mPermissionGroups.get(pg.getName()); + final String curPackageName = (cur == null) ? null : cur.getPackageName(); + final boolean isPackageUpdate = pg.getPackageName().equals(curPackageName); if (cur == null || isPackageUpdate) { - mSettings.mPermissionGroups.put(pg.info.name, pg); + mSettings.mPermissionGroups.put(pg.getName(), pg); if (chatty && DEBUG_PACKAGE_SCANNING) { if (r == null) { r = new StringBuilder(256); @@ -2181,12 +2197,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (isPackageUpdate) { r.append("UPD:"); } - r.append(pg.info.name); + r.append(pg.getName()); } } else { - Slog.w(TAG, "Permission group " + pg.info.name + " from package " - + pg.info.packageName + " ignored: original from " - + cur.info.packageName); + Slog.w(TAG, "Permission group " + pg.getName() + " from package " + + pg.getPackageName() + " ignored: original from " + + cur.getPackageName()); if (chatty && DEBUG_PACKAGE_SCANNING) { if (r == null) { r = new StringBuilder(256); @@ -2194,7 +2210,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { r.append(' '); } r.append("DUP:"); - r.append(pg.info.name); + r.append(pg.getName()); } } } @@ -2204,15 +2220,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { } - private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) { + private void removeAllPermissions(AndroidPackage pkg, boolean chatty) { synchronized (mLock) { - int N = pkg.permissions.size(); + int N = ArrayUtils.size(pkg.getPermissions()); StringBuilder r = null; for (int i=0; i<N; i++) { - PackageParser.Permission p = pkg.permissions.get(i); - BasePermission bp = (BasePermission) mSettings.mPermissions.get(p.info.name); + ParsedPermission p = pkg.getPermissions().get(i); + BasePermission bp = mSettings.mPermissions.get(p.getName()); if (bp == null) { - bp = mSettings.mPermissionTrees.get(p.info.name); + bp = mSettings.mPermissionTrees.get(p.getName()); } if (bp != null && bp.isPermission(p)) { bp.setPermission(null); @@ -2222,14 +2238,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { } else { r.append(' '); } - r.append(p.info.name); + r.append(p.getName()); } } if (p.isAppOp()) { ArraySet<String> appOpPkgs = - mSettings.mAppOpPermissionPackages.get(p.info.name); + mSettings.mAppOpPermissionPackages.get(p.getName()); if (appOpPkgs != null) { - appOpPkgs.remove(pkg.packageName); + appOpPkgs.remove(pkg.getPackageName()); } } } @@ -2237,14 +2253,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); } - N = pkg.requestedPermissions.size(); + N = pkg.getRequestedPermissions().size(); r = null; for (int i=0; i<N; i++) { - String perm = pkg.requestedPermissions.get(i); + String perm = pkg.getRequestedPermissions().get(i); if (mSettings.isPermissionAppOp(perm)) { ArraySet<String> appOpPkgs = mSettings.mAppOpPermissionPackages.get(perm); if (appOpPkgs != null) { - appOpPkgs.remove(pkg.packageName); + appOpPkgs.remove(pkg.getPackageName()); if (appOpPkgs.isEmpty()) { mSettings.mAppOpPermissionPackages.remove(perm); } @@ -2273,7 +2289,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param packageOfInterest If this is the name of {@code pkg} add extra logging * @param callback Result call back */ - private void restorePermissionState(@NonNull PackageParser.Package pkg, boolean replace, + private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace, @Nullable String packageOfInterest, @Nullable PermissionCallback callback) { // IMPORTANT: There are two types of permissions: install and runtime. // Install time permissions are granted when the app is installed to @@ -2286,7 +2302,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { // being upgraded to target a newer SDK, in which case dangerous permissions // are transformed from install time to runtime ones. - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); if (ps == null) { return; } @@ -2327,23 +2344,25 @@ public class PermissionManagerService extends IPermissionManager.Stub { synchronized (mLock) { ArraySet<String> newImplicitPermissions = new ArraySet<>(); - final int N = pkg.requestedPermissions.size(); + final int N = pkg.getRequestedPermissions().size(); for (int i = 0; i < N; i++) { - final String permName = pkg.requestedPermissions.get(i); + final String permName = pkg.getRequestedPermissions().get(i); final BasePermission bp = mSettings.getPermissionLocked(permName); final boolean appSupportsRuntimePermissions = - pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; + pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; String upgradedActivityRecognitionPermission = null; if (DEBUG_INSTALL) { - Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp); + Log.i(TAG, "Package " + pkg.getPackageName() + + " checking " + permName + ": " + bp); } if (bp == null || bp.getSourcePackageSetting() == null) { - if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) { + if (packageOfInterest == null || packageOfInterest.equals( + pkg.getPackageName())) { if (DEBUG_PERMISSIONS) { Slog.i(TAG, "Unknown permission " + permName - + " in package " + pkg.packageName); + + " in package " + pkg.getPackageName()); } } continue; @@ -2352,14 +2371,14 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Cache newImplicitPermissions before modifing permissionsState as for the shared // uids the original and new state are the same object if (!origPermissions.hasRequestedPermission(permName) - && (pkg.implicitPermissions.contains(permName) + && (pkg.getImplicitPermissions().contains(permName) || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) { - if (pkg.implicitPermissions.contains(permName)) { + if (pkg.getImplicitPermissions().contains(permName)) { // If permName is an implicit permission, try to auto-grant newImplicitPermissions.add(permName); if (DEBUG_PERMISSIONS) { - Slog.i(TAG, permName + " is newly added for " + pkg.packageName); + Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName()); } } else { // Special case for Activity Recognition permission. Even if AR permission @@ -2382,7 +2401,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (DEBUG_PERMISSIONS) { Slog.i(TAG, permName + " is newly added for " - + pkg.packageName); + + pkg.getPackageName()); } break; } @@ -2391,10 +2410,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { } // Limit ephemeral apps to ephemeral allowed permissions. - if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) { + if (pkg.isInstantApp() && !bp.isInstant()) { if (DEBUG_PERMISSIONS) { Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() - + " for package " + pkg.packageName); + + " for package " + pkg.getPackageName()); } continue; } @@ -2402,7 +2421,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) { if (DEBUG_PERMISSIONS) { Log.i(TAG, "Denying runtime-only permission " + bp.getName() - + " for package " + pkg.packageName); + + " for package " + pkg.getPackageName()); } continue; } @@ -2413,7 +2432,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Keep track of app op permissions. if (bp.isAppOp()) { - mSettings.addAppOpPackage(perm, pkg.packageName); + mSettings.addAppOpPackage(perm, pkg.getPackageName()); } if (bp.isNormal()) { @@ -2439,7 +2458,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (DEBUG_PERMISSIONS) { Slog.i(TAG, "Considering granting permission " + perm + " to package " - + pkg.packageName); + + pkg.getPackageName()); } if (grant != GRANT_DENIED) { @@ -2725,10 +2744,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { default: { if (packageOfInterest == null - || packageOfInterest.equals(pkg.packageName)) { + || packageOfInterest.equals(pkg.getPackageName())) { if (DEBUG_PERMISSIONS) { Slog.i(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName + + " to package " + pkg.getPackageName() + " because it was previously installed without"); } } @@ -2743,9 +2762,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { changedInstallPermission = true; if (DEBUG_PERMISSIONS) { Slog.i(TAG, "Un-granting permission " + perm - + " from package " + pkg.packageName + + " from package " + pkg.getPackageName() + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + + " flags=0x" + Integer.toHexString(pkg.getFlags()) + ")"); } } else if (bp.isAppOp()) { @@ -2753,11 +2772,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { // not to be granted, there is a UI for the user to decide. if (DEBUG_PERMISSIONS && (packageOfInterest == null - || packageOfInterest.equals(pkg.packageName))) { + || packageOfInterest.equals(pkg.getPackageName()))) { Slog.i(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName + + " to package " + pkg.getPackageName() + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + + " flags=0x" + Integer.toHexString(pkg.getFlags()) + ")"); } } @@ -2787,7 +2806,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } for (int userId : updatedUserIds) { - notifyRuntimePermissionStateChanged(pkg.packageName, userId); + notifyRuntimePermissionStateChanged(pkg.getPackageName(), userId); } } @@ -2803,10 +2822,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @return The updated value of the {@code updatedUserIds} parameter */ private @NonNull int[] revokePermissionsNoLongerImplicitLocked( - @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, + @NonNull PermissionsState ps, @NonNull AndroidPackage pkg, @NonNull int[] updatedUserIds) { - String pkgName = pkg.packageName; - boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion + String pkgName = pkg.getPackageName(); + boolean supportsRuntimePermissions = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; int[] users = UserManagerService.getInstance().getUserIds(); @@ -2815,7 +2834,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { int userId = users[i]; for (String permission : ps.getPermissions(userId)) { - if (!pkg.implicitPermissions.contains(permission)) { + if (!pkg.getImplicitPermissions().contains(permission)) { if (!ps.hasInstallPermission(permission)) { int flags = ps.getRuntimePermissionState(permission, userId).getFlags(); @@ -2865,9 +2884,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private void inheritPermissionStateToNewImplicitPermissionLocked( @NonNull ArraySet<String> sourcePerms, @NonNull String newPerm, - @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, + @NonNull PermissionsState ps, @NonNull AndroidPackage pkg, @UserIdInt int userId) { - String pkgName = pkg.packageName; + String pkgName = pkg.getPackageName(); boolean isGranted = false; int flags = 0; @@ -2914,10 +2933,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @return The ids of the users that are changed */ private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated( - @NonNull PackageParser.Package pkg, boolean replace, @NonNull int[] updatedUserIds) { - if (replace && pkg.applicationInfo.hasRequestedLegacyExternalStorage() && ( - pkg.requestedPermissions.contains(READ_EXTERNAL_STORAGE) - || pkg.requestedPermissions.contains(WRITE_EXTERNAL_STORAGE))) { + @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) { + if (replace && pkg.hasRequestedLegacyExternalStorage() && ( + pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE) + || pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) { return UserManagerService.getInstance().getUserIds(); } @@ -2936,10 +2955,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { */ private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked( @NonNull PermissionsState origPs, - @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, + @NonNull PermissionsState ps, @NonNull AndroidPackage pkg, @NonNull ArraySet<String> newImplicitPermissions, @NonNull int[] updatedUserIds) { - String pkgName = pkg.packageName; + String pkgName = pkg.getPackageName(); ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>(); final List<SplitPermissionInfoParcelable> permissionList = getSplitPermissions(); @@ -3019,17 +3038,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { SystemConfig.getInstance().getSplitPermissions()); } - private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) { + private boolean isNewPlatformPermissionForPackage(String perm, AndroidPackage pkg) { boolean allowed = false; final int NP = PackageParser.NEW_PERMISSIONS.length; for (int ip=0; ip<NP; ip++) { final PackageParser.NewPermissionInfo npi = PackageParser.NEW_PERMISSIONS[ip]; if (npi.name.equals(perm) - && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) { + && pkg.getTargetSdkVersion() < npi.sdkVersion) { allowed = true; Log.i(TAG, "Auto-granting " + perm + " to old pkg " - + pkg.packageName); + + pkg.getPackageName()); break; } } @@ -3043,29 +3062,26 @@ public class PermissionManagerService extends IPermissionManager.Stub { * * <p>This handles parent/child apps. */ - private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) { - ArraySet<String> wlPermissions = null; + private boolean hasPrivappWhitelistEntry(String perm, AndroidPackage pkg) { + ArraySet<String> wlPermissions; if (pkg.isVendor()) { wlPermissions = - SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName); + SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.getPackageName()); } else if (pkg.isProduct()) { wlPermissions = - SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName); + SystemConfig.getInstance().getProductPrivAppPermissions(pkg.getPackageName()); } else if (pkg.isSystemExt()) { wlPermissions = SystemConfig.getInstance().getSystemExtPrivAppPermissions( - pkg.packageName); + pkg.getPackageName()); } else { - wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName); + wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.getPackageName()); } - // Let's check if this package is whitelisted... - boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm); - // If it's not, we'll also tail-recurse to the parent. - return whitelisted || - pkg.parentPackage != null && hasPrivappWhitelistEntry(perm, pkg.parentPackage); + + return wlPermissions != null && wlPermissions.contains(perm); } - private boolean grantSignaturePermission(String perm, PackageParser.Package pkg, + private boolean grantSignaturePermission(String perm, AndroidPackage pkg, BasePermission bp, PermissionsState origPermissions) { boolean oemPermission = bp.isOEM(); boolean vendorPrivilegedPermission = bp.isVendorPrivileged(); @@ -3073,7 +3089,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { boolean privappPermissionsDisable = RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE; boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName()); - boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName); + boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.getPackageName()); if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged() && !platformPackage && platformPermission) { if (!hasPrivappWhitelistEntry(perm, pkg)) { @@ -3083,22 +3099,22 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArraySet<String> deniedPermissions = null; if (pkg.isVendor()) { deniedPermissions = SystemConfig.getInstance() - .getVendorPrivAppDenyPermissions(pkg.packageName); + .getVendorPrivAppDenyPermissions(pkg.getPackageName()); } else if (pkg.isProduct()) { deniedPermissions = SystemConfig.getInstance() - .getProductPrivAppDenyPermissions(pkg.packageName); + .getProductPrivAppDenyPermissions(pkg.getPackageName()); } else if (pkg.isSystemExt()) { deniedPermissions = SystemConfig.getInstance() - .getSystemExtPrivAppDenyPermissions(pkg.packageName); + .getSystemExtPrivAppDenyPermissions(pkg.getPackageName()); } else { deniedPermissions = SystemConfig.getInstance() - .getPrivAppDenyPermissions(pkg.packageName); + .getPrivAppDenyPermissions(pkg.getPackageName()); } final boolean permissionViolation = deniedPermissions == null || !deniedPermissions.contains(perm); if (permissionViolation) { Slog.w(TAG, "Privileged permission " + perm + " for package " - + pkg.packageName + " (" + pkg.codePath + + pkg.getPackageName() + " (" + pkg.getCodePath() + ") not in privapp-permissions whitelist"); if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) { @@ -3106,7 +3122,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { mPrivappPermissionsViolations = new ArraySet<>(); } mPrivappPermissionsViolations.add( - pkg.packageName + " (" + pkg.codePath + "): " + perm); + pkg.getPackageName() + " (" + pkg.getCodePath() + "): " + perm); } } else { return false; @@ -3119,7 +3135,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } final String systemPackageName = mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM); - final PackageParser.Package systemPackage = + final AndroidPackage systemPackage = mPackageManagerInt.getPackage(systemPackageName); // check if the package is allow to use this signature permission. A package is allowed to @@ -3130,24 +3146,23 @@ public class PermissionManagerService extends IPermissionManager.Stub { // package, and the defining package still trusts the old certificate for permissions // - or it shares the above relationships with the system package boolean allowed = - pkg.mSigningDetails.hasAncestorOrSelf( + pkg.getSigningDetails().hasAncestorOrSelf( bp.getSourcePackageSetting().getSigningDetails()) || bp.getSourcePackageSetting().getSigningDetails().checkCapability( - pkg.mSigningDetails, + pkg.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION) - || pkg.mSigningDetails.hasAncestorOrSelf(systemPackage.mSigningDetails) - || systemPackage.mSigningDetails.checkCapability( - pkg.mSigningDetails, + || pkg.getSigningDetails().hasAncestorOrSelf(systemPackage.getSigningDetails()) + || systemPackage.getSigningDetails().checkCapability( + pkg.getSigningDetails(), PackageParser.SigningDetails.CertCapabilities.PERMISSION); if (!allowed && (privilegedPermission || oemPermission)) { if (pkg.isSystem()) { // For updated system applications, a privileged/oem permission // is granted only if it had been defined by the original application. if (pkg.isUpdatedSystemApp()) { - final PackageParser.Package disabledPkg = - mPackageManagerInt.getDisabledSystemPackage(pkg.packageName); - final PackageSetting disabledPs = - (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null; + final PackageSetting disabledPs = (PackageSetting) mPackageManagerInt + .getDisabledSystemPackage(pkg.getPackageName()); + final AndroidPackage disabledPkg = disabledPs == null ? null : disabledPs.pkg; if (disabledPs != null && disabledPs.getPermissionsState().hasInstallPermission(perm)) { // If the original was granted this permission, we take @@ -3172,40 +3187,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { && canGrantOemPermission(disabledPs, perm)))) { allowed = true; } - // Also if a privileged parent package on the system image or any of - // its children requested a privileged/oem permission, the updated child - // packages can also get the permission. - if (pkg.parentPackage != null) { - final PackageParser.Package disabledParentPkg = mPackageManagerInt - .getDisabledSystemPackage(pkg.parentPackage.packageName); - final PackageSetting disabledParentPs = (disabledParentPkg != null) - ? (PackageSetting) disabledParentPkg.mExtras : null; - if (disabledParentPkg != null - && ((privilegedPermission && disabledParentPs.isPrivileged()) - || (oemPermission && disabledParentPs.isOem()))) { - if (isPackageRequestingPermission(disabledParentPkg, perm) - && canGrantOemPermission(disabledParentPs, perm)) { - allowed = true; - } else if (disabledParentPkg.childPackages != null) { - for (PackageParser.Package disabledChildPkg - : disabledParentPkg.childPackages) { - final PackageSetting disabledChildPs = - (disabledChildPkg != null) - ? (PackageSetting) disabledChildPkg.mExtras - : null; - if (isPackageRequestingPermission(disabledChildPkg, perm) - && canGrantOemPermission( - disabledChildPs, perm)) { - allowed = true; - break; - } - } - } - } - } } } else { - final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); allowed = (privilegedPermission && pkg.isPrivileged()) || (oemPermission && pkg.isOem() && canGrantOemPermission(ps, perm)); @@ -3216,7 +3201,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (allowed && privilegedPermission && !vendorPrivilegedPermission && pkg.isVendor()) { Slog.w(TAG, "Permission " + perm + " cannot be granted to privileged vendor apk " - + pkg.packageName + " because it isn't a 'vendorPrivileged' permission."); + + pkg.getPackageName() + + " because it isn't a 'vendorPrivileged' permission."); allowed = false; } } @@ -3224,7 +3210,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!allowed) { if (!allowed && bp.isPre23() - && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + && pkg.getTargetSdkVersion() < Build.VERSION_CODES.M) { // If this was a previously normal/dangerous permission that got moved // to a system permission as part of the runtime permission redesign, then // we still want to blindly grant it to old apps. @@ -3234,9 +3220,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { // need a separate flag anymore. Hence we need to check which // permissions are needed by the permission controller if (!allowed && bp.isInstaller() - && (pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && (pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM)) - || pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + || pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER, UserHandle.USER_SYSTEM)))) { // If this permission is to be granted to the system installer and @@ -3244,7 +3230,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { allowed = true; } if (!allowed && bp.isVerifier() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM))) { // If this permission is to be granted to the system verifier and // this app is a verifier, then it gets the permission. @@ -3261,41 +3247,41 @@ public class PermissionManagerService extends IPermissionManager.Stub { allowed = origPermissions.hasInstallPermission(perm); } if (!allowed && bp.isSetup() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM))) { // If this permission is to be granted to the system setup wizard and // this app is a setup wizard, then it gets the permission. allowed = true; } if (!allowed && bp.isSystemTextClassifier() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER, UserHandle.USER_SYSTEM))) { // Special permissions for the system default text classifier. allowed = true; } if (!allowed && bp.isConfigurator() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_CONFIGURATOR, UserHandle.USER_SYSTEM))) { // Special permissions for the device configurator. allowed = true; } if (!allowed && bp.isWellbeing() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_WELLBEING, UserHandle.USER_SYSTEM))) { // Special permission granted only to the OEM specified wellbeing app allowed = true; } if (!allowed && bp.isDocumenter() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_DOCUMENTER, UserHandle.USER_SYSTEM))) { // If this permission is to be granted to the documenter and // this app is the documenter, then it gets the permission. allowed = true; } if (!allowed && bp.isIncidentReportApprover() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER, UserHandle.USER_SYSTEM))) { // If this permission is to be granted to the incident report approver and @@ -3303,7 +3289,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { allowed = true; } if (!allowed && bp.isAppPredictor() - && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + && pkg.getPackageName().equals(mPackageManagerInt.getKnownPackageName( PackageManagerInternal.PACKAGE_APP_PREDICTOR, UserHandle.USER_SYSTEM))) { // Special permissions for the system app predictor. allowed = true; @@ -3326,26 +3312,27 @@ public class PermissionManagerService extends IPermissionManager.Stub { return Boolean.TRUE == granted; } - private boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg, + private boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg, @UserIdInt int userId) { // Permission review applies only to apps not supporting the new permission model. - if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) { + if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M) { return false; } // Legacy apps have the permission and get user consent on launch. - if (pkg.mExtras == null) { + final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); + if (ps == null) { return false; } - final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); return permissionsState.isPermissionReviewRequired(userId); } - private boolean isPackageRequestingPermission(PackageParser.Package pkg, String permission) { - final int permCount = pkg.requestedPermissions.size(); + private boolean isPackageRequestingPermission(AndroidPackage pkg, String permission) { + final int permCount = pkg.getRequestedPermissions().size(); for (int j = 0; j < permCount; j++) { - String requestedPermission = pkg.requestedPermissions.get(j); + String requestedPermission = pkg.getRequestedPermissions().get(j); if (permission.equals(requestedPermission)) { return true; } @@ -3353,41 +3340,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { return false; } - @GuardedBy("mLock") - private void grantRuntimePermissionsGrantedToDisabledPackageLocked( - PackageParser.Package pkg, int callingUid, PermissionCallback callback) { - if (pkg.parentPackage == null) { - return; - } - if (pkg.requestedPermissions == null) { - return; - } - final PackageParser.Package disabledPkg = - mPackageManagerInt.getDisabledSystemPackage(pkg.parentPackage.packageName); - if (disabledPkg == null || disabledPkg.mExtras == null) { - return; - } - final PackageSetting disabledPs = (PackageSetting) disabledPkg.mExtras; - if (!disabledPs.isPrivileged() || disabledPs.hasChildPackages()) { - return; - } - final int permCount = pkg.requestedPermissions.size(); - for (int i = 0; i < permCount; i++) { - String permission = pkg.requestedPermissions.get(i); - BasePermission bp = mSettings.getPermissionLocked(permission); - if (bp == null || !(bp.isRuntime() || bp.isDevelopment())) { - continue; - } - for (int userId : mUserManagerInt.getUserIds()) { - if (disabledPs.getPermissionsState().hasRuntimePermission(permission, userId)) { - grantRuntimePermissionInternal( - permission, pkg.packageName, false, callingUid, userId, callback); - } - } - } - } - - private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds, + private void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds, String[] grantedPermissions, int callingUid, PermissionCallback callback) { for (int userId : userIds) { grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions, callingUid, @@ -3395,9 +3348,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId, + private void grantRequestedRuntimePermissionsForUser(AndroidPackage pkg, int userId, String[] grantedPermissions, int callingUid, PermissionCallback callback) { - PackageSetting ps = (PackageSetting) pkg.mExtras; + PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting( + pkg.getPackageName()); if (ps == null) { return; } @@ -3407,12 +3361,15 @@ public class PermissionManagerService extends IPermissionManager.Stub { final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED | PackageManager.FLAG_PERMISSION_POLICY_FIXED; - final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion + final int compatFlags = PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED + | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT; + + final boolean supportsRuntimePermissions = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M; - final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.packageName, userId); + final boolean instantApp = mPackageManagerInt.isInstantApp(pkg.getPackageName(), userId); - for (String permission : pkg.requestedPermissions) { + for (String permission : pkg.getRequestedPermissions()) { final BasePermission bp; synchronized (mLock) { bp = mSettings.getPermissionLocked(permission); @@ -3426,27 +3383,26 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (supportsRuntimePermissions) { // Installer cannot change immutable permissions. if ((flags & immutableFlags) == 0) { - grantRuntimePermissionInternal(permission, pkg.packageName, false, + grantRuntimePermissionInternal(permission, pkg.getPackageName(), false, callingUid, userId, callback); } } else { - // In permission review mode we clear the review flag when we - // are asked to install the app with all permissions granted. - if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { - updatePermissionFlagsInternal(permission, pkg.packageName, - PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, callingUid, - userId, false, callback); + // In permission review mode we clear the review flag and the revoked compat + // flag when we are asked to install the app with all permissions granted. + if ((flags & compatFlags) != 0) { + updatePermissionFlagsInternal(permission, pkg.getPackageName(), compatFlags, + 0, callingUid, userId, false, callback); } } } } } - private void setWhitelistedRestrictedPermissionsForUser(@NonNull PackageParser.Package pkg, + private void setWhitelistedRestrictedPermissionsForUser(@NonNull AndroidPackage pkg, @UserIdInt int userId, @Nullable List<String> permissions, int callingUid, @PermissionWhitelistFlags int whitelistFlags, PermissionCallback callback) { final PermissionsState permissionsState = - PackageManagerServiceUtils.getPermissionsState(pkg); + PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg); if (permissionsState == null) { return; } @@ -3454,9 +3410,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { ArraySet<String> oldGrantedRestrictedPermissions = null; boolean updatePermissions = false; - final int permissionCount = pkg.requestedPermissions.size(); + final int permissionCount = pkg.getRequestedPermissions().size(); for (int i = 0; i < permissionCount; i++) { - final String permissionName = pkg.requestedPermissions.get(i); + final String permissionName = pkg.getRequestedPermissions().get(i); final BasePermission bp = mSettings.getPermissionLocked(permissionName); @@ -3532,19 +3488,19 @@ public class PermissionManagerService extends IPermissionManager.Stub { // If we are whitelisting an app that does not support runtime permissions // we need to make sure it goes through the permission review UI at launch. - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M + if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M && !wasWhitelisted && isWhitelisted) { mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; } - updatePermissionFlagsInternal(permissionName, pkg.packageName, mask, newFlags, + updatePermissionFlagsInternal(permissionName, pkg.getPackageName(), mask, newFlags, callingUid, userId, false, null /*callback*/); } if (updatePermissions) { // Update permission of this app to take into account the new whitelist state. - restorePermissionState(pkg, false, pkg.packageName, callback); + restorePermissionState(pkg, false, pkg.getPackageName(), callback); // If this resulted in losing a permission we need to kill the app. if (oldGrantedRestrictedPermissions != null) { @@ -3553,9 +3509,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { final String permission = oldGrantedRestrictedPermissions.valueAt(i); // Sometimes we create a new permission state instance during update. final PermissionsState newPermissionsState = - PackageManagerServiceUtils.getPermissionsState(pkg); + PackageManagerServiceUtils.getPermissionsState(mPackageManagerInt, pkg); if (!newPermissionsState.hasPermission(permission, userId)) { - callback.onPermissionRevoked(pkg.applicationInfo.uid, userId); + callback.onPermissionRevoked(pkg.getUid(), userId); break; } } @@ -3568,17 +3524,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { SharedUserSetting suSetting, int[] allUserIds) { // Collect all used permissions in the UID final ArraySet<String> usedPermissions = new ArraySet<>(); - final List<PackageParser.Package> pkgList = suSetting.getPackages(); + final List<AndroidPackage> pkgList = suSetting.getPackages(); if (pkgList == null || pkgList.size() == 0) { return EmptyArray.INT; } - for (PackageParser.Package pkg : pkgList) { - if (pkg.requestedPermissions == null) { + for (AndroidPackage pkg : pkgList) { + if (pkg.getRequestedPermissions() == null) { continue; } - final int requestedPermCount = pkg.requestedPermissions.size(); + final int requestedPermCount = pkg.getRequestedPermissions().size(); for (int j = 0; j < requestedPermCount; j++) { - String permission = pkg.requestedPermissions.get(j); + String permission = pkg.getRequestedPermissions().get(j); BasePermission bp = mSettings.getPermissionLocked(permission); if (bp != null) { usedPermissions.add(permission); @@ -3640,18 +3596,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param allPackages All currently known packages * @param callback Callback to call after permission changes */ - private void updatePermissions(@NonNull String packageName, @Nullable PackageParser.Package pkg, + private void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg, @NonNull PermissionCallback callback) { final int flags = (pkg != null ? UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG : 0); updatePermissions( packageName, pkg, getVolumeUuidForPackage(pkg), flags, callback); - if (pkg != null && pkg.childPackages != null) { - for (PackageParser.Package childPkg : pkg.childPackages) { - updatePermissions(childPkg.packageName, childPkg, - getVolumeUuidForPackage(childPkg), flags, callback); - } - } } /** @@ -3687,10 +3637,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Only system declares background permissions, hence mapping does never change. mBackgroundPermissions = new ArrayMap<>(); for (BasePermission bp : mSettings.getAllPermissionsLocked()) { - if (bp.perm != null && bp.perm.info != null - && bp.perm.info.backgroundPermission != null) { + if (bp.perm != null && bp.perm.backgroundPermission != null) { String fgPerm = bp.name; - String bgPerm = bp.perm.info.backgroundPermission; + String bgPerm = bp.perm.backgroundPermission; List<String> fgPerms = mBackgroundPermissions.get(bgPerm); if (fgPerms == null) { @@ -3751,7 +3700,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @param callback Callback to call after permission changes */ private void updatePermissions(final @Nullable String changingPkgName, - final @Nullable PackageParser.Package changingPkg, + final @Nullable AndroidPackage changingPkg, final @Nullable String replaceVolumeUuid, @UpdatePermissionFlags int flags, final @Nullable PermissionCallback callback) { @@ -3784,7 +3733,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { // Now update the permissions for all packages. if ((flags & UPDATE_PERMISSIONS_ALL) != 0) { final boolean replaceAll = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0); - mPackageManagerInt.forEachPackage((Package pkg) -> { + mPackageManagerInt.forEachPackage((AndroidPackage pkg) -> { if (pkg == changingPkg) { return; } @@ -3823,7 +3772,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @return {@code true} if a permission source package might have changed */ private boolean updatePermissionSourcePackage(@Nullable String packageName, - @Nullable PackageParser.Package pkg, + @Nullable AndroidPackage pkg, final @Nullable PermissionCallback callback) { boolean changed = false; @@ -3846,8 +3795,8 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int userIdNum = 0; userIdNum < numUserIds; userIdNum++) { final int userId = userIds[userIdNum]; - mPackageManagerInt.forEachPackage((Package p) -> { - final String pName = p.packageName; + mPackageManagerInt.forEachPackage((AndroidPackage p) -> { + final String pName = p.getPackageName(); final ApplicationInfo appInfo = mPackageManagerInt.getApplicationInfo(pName, 0, Process.SYSTEM_UID, UserHandle.USER_SYSTEM); @@ -3892,11 +3841,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (needsUpdate != null) { for (final BasePermission bp : needsUpdate) { - final PackageParser.Package sourcePkg = + final AndroidPackage sourcePkg = mPackageManagerInt.getPackage(bp.getSourcePackageName()); + final PackageSetting sourcePs = + (PackageSetting) mPackageManagerInt.getPackageSetting( + bp.getSourcePackageName()); synchronized (mLock) { - if (sourcePkg != null && sourcePkg.mExtras != null) { - final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras; + if (sourcePkg != null && sourcePs != null) { if (bp.getSourcePackageSetting() == null) { bp.setSourcePackageSetting(sourcePs); } @@ -3929,7 +3880,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { * @return {@code true} if a permission tree ownership might have changed */ private boolean updatePermissionTreeSourcePackage(@Nullable String packageName, - @Nullable PackageParser.Package pkg) { + @Nullable AndroidPackage pkg) { boolean changed = false; Set<BasePermission> needsUpdate = null; @@ -3955,11 +3906,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { } if (needsUpdate != null) { for (final BasePermission bp : needsUpdate) { - final PackageParser.Package sourcePkg = + final AndroidPackage sourcePkg = mPackageManagerInt.getPackage(bp.getSourcePackageName()); + final PackageSetting sourcePs = + (PackageSetting) mPackageManagerInt.getPackageSetting( + bp.getSourcePackageName()); synchronized (mLock) { - if (sourcePkg != null && sourcePkg.mExtras != null) { - final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras; + if (sourcePkg != null && sourcePs != null) { if (bp.getSourcePackageSetting() == null) { bp.setSourcePackageSetting(sourcePs); } @@ -4082,24 +4035,28 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } - private static String getVolumeUuidForPackage(PackageParser.Package pkg) { + private static String getVolumeUuidForPackage(AndroidPackage pkg) { if (pkg == null) { return StorageManager.UUID_PRIVATE_INTERNAL; } if (pkg.isExternal()) { - if (TextUtils.isEmpty(pkg.volumeUuid)) { + if (TextUtils.isEmpty(pkg.getVolumeUuid())) { return StorageManager.UUID_PRIMARY_PHYSICAL; } else { - return pkg.volumeUuid; + return pkg.getVolumeUuid(); } } else { return StorageManager.UUID_PRIVATE_INTERNAL; } } - private static boolean hasPermission(PackageParser.Package pkgInfo, String permName) { - for (int i=pkgInfo.permissions.size()-1; i>=0; i--) { - if (pkgInfo.permissions.get(i).info.name.equals(permName)) { + private static boolean hasPermission(AndroidPackage pkg, String permName) { + if (pkg.getPermissions() == null) { + return false; + } + + for (int i = pkg.getPermissions().size() - 1; i >= 0; i--) { + if (pkg.getPermissions().get(i).getName().equals(permName)) { return true; } } @@ -4138,37 +4095,39 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService.this.systemReady(); } @Override - public boolean isPermissionsReviewRequired(@NonNull Package pkg, @UserIdInt int userId) { + public boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg, + @UserIdInt int userId) { return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId); } + @Override public void revokeRuntimePermissionsIfGroupChanged( - @NonNull PackageParser.Package newPackage, - @NonNull PackageParser.Package oldPackage, + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage, @NonNull ArrayList<String> allPackageNames) { PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage, oldPackage, allPackageNames, mDefaultPermissionCallback); } @Override - public void addAllPermissions(Package pkg, boolean chatty) { + public void addAllPermissions(AndroidPackage pkg, boolean chatty) { PermissionManagerService.this.addAllPermissions(pkg, chatty); } @Override - public void addAllPermissionGroups(Package pkg, boolean chatty) { + public void addAllPermissionGroups(AndroidPackage pkg, boolean chatty) { PermissionManagerService.this.addAllPermissionGroups(pkg, chatty); } @Override - public void removeAllPermissions(Package pkg, boolean chatty) { + public void removeAllPermissions(AndroidPackage pkg, boolean chatty) { PermissionManagerService.this.removeAllPermissions(pkg, chatty); } @Override - public void grantRequestedRuntimePermissions(PackageParser.Package pkg, int[] userIds, + public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds, String[] grantedPermissions, int callingUid) { PermissionManagerService.this.grantRequestedRuntimePermissions( pkg, userIds, grantedPermissions, callingUid, mDefaultPermissionCallback); } @Override - public void setWhitelistedRestrictedPermissions(@NonNull PackageParser.Package pkg, + public void setWhitelistedRestrictedPermissions(@NonNull AndroidPackage pkg, @NonNull int[] userIds, @Nullable List<String> permissions, int callingUid, @PackageManager.PermissionWhitelistFlags int flags) { for (int userId : userIds) { @@ -4183,13 +4142,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { packageName, permissions, flags, userId); } @Override - public void grantRuntimePermissionsGrantedToDisabledPackage(PackageParser.Package pkg, - int callingUid) { - PermissionManagerService.this.grantRuntimePermissionsGrantedToDisabledPackageLocked( - pkg, callingUid, mDefaultPermissionCallback); - } - @Override - public void updatePermissions(@NonNull String packageName, @Nullable Package pkg) { + public void updatePermissions(@NonNull String packageName, @Nullable AndroidPackage pkg) { PermissionManagerService.this .updatePermissions(packageName, pkg, mDefaultPermissionCallback); } @@ -4199,13 +4152,13 @@ public class PermissionManagerService extends IPermissionManager.Stub { .updateAllPermissions(volumeUuid, sdkUpdated, mDefaultPermissionCallback); } @Override - public void resetRuntimePermissions(Package pkg, int userId) { + public void resetRuntimePermissions(AndroidPackage pkg, int userId) { PermissionManagerService.this.resetRuntimePermissionsInternal(pkg, userId); } @Override public void resetAllRuntimePermissions(final int userId) { mPackageManagerInt.forEachPackage( - (PackageParser.Package pkg) -> resetRuntimePermissionsInternal(pkg, userId)); + (AndroidPackage pkg) -> resetRuntimePermissionsInternal(pkg, userId)); } @Override public String[] getAppOpPermissionPackages(String permName, int callingUid) { @@ -4251,9 +4204,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { for (int i = 0; i < numTotalPermissions; i++) { BasePermission bp = mSettings.mPermissions.valueAt(i); - if (bp.perm != null && bp.perm.info != null - && bp.protectionLevel == protectionLevel) { - matchingPermissions.add(bp.perm.info); + if (bp.perm != null && bp.protectionLevel == protectionLevel) { + matchingPermissions.add( + PackageInfoUtils.generatePermissionInfo(bp.perm, 0)); } } } @@ -4334,15 +4287,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { @Override public void setDefaultHome(String packageName, int userId, Consumer<Boolean> callback) { + if (userId == UserHandle.USER_ALL) { + return; + } + DefaultHomeProvider provider; synchronized (mLock) { - if (userId == UserHandle.USER_ALL) { - return; - } - if (mDefaultHomeProvider == null) { - return; - } - mDefaultHomeProvider.setDefaultHomeAsync(packageName, userId, callback); + provider = mDefaultHomeProvider; + } + if (provider == null) { + return; } + provider.setDefaultHomeAsync(packageName, userId, callback); } @Override @@ -4403,26 +4358,29 @@ public class PermissionManagerService extends IPermissionManager.Stub { @Override public String getDefaultBrowser(int userId) { + DefaultBrowserProvider provider; synchronized (mLock) { - return mDefaultBrowserProvider == null - ? null : mDefaultBrowserProvider.getDefaultBrowser(userId); + provider = mDefaultBrowserProvider; } + return provider != null ? provider.getDefaultBrowser(userId) : null; } @Override public String getDefaultDialer(int userId) { + DefaultDialerProvider provider; synchronized (mLock) { - return mDefaultDialerProvider == null - ? null : mDefaultDialerProvider.getDefaultDialer(userId); + provider = mDefaultDialerProvider; } + return provider != null ? provider.getDefaultDialer(userId) : null; } @Override public String getDefaultHome(int userId) { + DefaultHomeProvider provider; synchronized (mLock) { - return mDefaultHomeProvider == null - ? null : mDefaultHomeProvider.getDefaultHome(userId); + provider = mDefaultHomeProvider; } + return provider != null ? provider.getDefaultHome(userId) : null; } @Override diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 8f22f9245a53..752c2dc15d52 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -21,8 +21,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; +import android.content.pm.parsing.AndroidPackage; import android.permission.PermissionManagerInternal; import java.util.ArrayList; @@ -173,16 +173,14 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager public abstract void systemReady(); - public abstract boolean isPermissionsReviewRequired(@NonNull PackageParser.Package pkg, + public abstract boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg, @UserIdInt int userId); - public abstract void grantRuntimePermissionsGrantedToDisabledPackage( - @NonNull PackageParser.Package pkg, int callingUid); public abstract void grantRequestedRuntimePermissions( - @NonNull PackageParser.Package pkg, @NonNull int[] userIds, + @NonNull AndroidPackage pkg, @NonNull int[] userIds, @NonNull String[] grantedPermissions, int callingUid); public abstract void setWhitelistedRestrictedPermissions( - @NonNull PackageParser.Package pkg, @NonNull int[] userIds, + @NonNull AndroidPackage pkg, @NonNull int[] userIds, @NonNull List<String> permissions, int callingUid, @PackageManager.PermissionWhitelistFlags int whitelistFlags); /** Sets the whitelisted, restricted permissions for the given package. */ @@ -204,7 +202,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * @param callback Callback to call after permission changes */ public abstract void updatePermissions(@NonNull String packageName, - @Nullable PackageParser.Package pkg); + @Nullable AndroidPackage pkg); /** * Update all permissions for all apps. @@ -224,7 +222,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * Resets any user permission state changes (eg. permissions and flags) of all * packages installed for the given user. * - * @see #resetRuntimePermissions(android.content.pm.PackageParser.Package, int) + * @see #resetRuntimePermissions(AndroidPackage, int) */ public abstract void resetAllRuntimePermissions(@UserIdInt int userId); @@ -232,7 +230,7 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * Resets any user permission state changes (eg. permissions and flags) of the * specified package for the given user. */ - public abstract void resetRuntimePermissions(@NonNull PackageParser.Package pkg, + public abstract void resetRuntimePermissions(@NonNull AndroidPackage pkg, @UserIdInt int userId); /** @@ -245,8 +243,8 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * @param allPackageNames All packages */ public abstract void revokeRuntimePermissionsIfGroupChanged( - @NonNull PackageParser.Package newPackage, - @NonNull PackageParser.Package oldPackage, + @NonNull AndroidPackage newPackage, + @NonNull AndroidPackage oldPackage, @NonNull ArrayList<String> allPackageNames); /** @@ -255,9 +253,9 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager * NOTE: argument {@code groupTEMP} is temporary until mPermissionGroups is moved to * the permission settings. */ - public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); - public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty); - public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); + public abstract void addAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); + public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty); + public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); /** Retrieve the packages that have requested the given app op permission */ public abstract @Nullable String[] getAppOpPermissionPackages( diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java index 3d8cf2ddc2cc..254b720c57a0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java +++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java @@ -18,7 +18,7 @@ package com.android.server.pm.permission; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.PackageParser; +import android.content.pm.parsing.ComponentParseUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -65,8 +65,8 @@ public class PermissionSettings { * name to permission group object. */ @GuardedBy("mLock") - final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups = - new ArrayMap<String, PackageParser.PermissionGroup>(); + final ArrayMap<String, ComponentParseUtils.ParsedPermissionGroup> mPermissionGroups = + new ArrayMap<>(); /** * Set of packages that request a particular app op. The mapping is from permission diff --git a/services/core/java/com/android/server/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java index 505a0e22eac4..a78f5c4202f0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionsState.java +++ b/services/core/java/com/android/server/pm/permission/PermissionsState.java @@ -23,6 +23,7 @@ import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseBooleanArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; import java.util.ArrayList; @@ -30,7 +31,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; -import com.android.internal.annotations.GuardedBy; /** * This class encapsulates the permissions for a package or a shared user. diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 1bf319dfcb69..2f667133d64f 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -17,13 +17,12 @@ package com.android.server.policy; import static android.app.AppOpsManager.MODE_ALLOWED; -import static android.app.AppOpsManager.MODE_DEFAULT; -import static android.app.AppOpsManager.MODE_ERRORED; import static android.app.AppOpsManager.MODE_FOREGROUND; import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; +import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT; import static android.content.pm.PackageManager.GET_PERMISSIONS; import android.annotation.NonNull; @@ -38,8 +37,8 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; -import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; +import android.content.pm.parsing.AndroidPackage; import android.os.Build; import android.os.Process; import android.os.RemoteException; @@ -157,13 +156,12 @@ public final class PermissionPolicyService extends SystemService { appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener); } else if (perm.isSoftRestricted()) { appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener); - SoftRestrictedPermissionPolicy policy = SoftRestrictedPermissionPolicy.forPermission(null, null, null, perm.name); - if (policy.resolveAppOp() != OP_NONE) { - appOpsService.startWatchingMode(policy.resolveAppOp(), null, - appOpsListener); + int extraAppOp = policy.getExtraAppOpCode(); + if (extraAppOp != OP_NONE) { + appOpsService.startWatchingMode(extraAppOp, null, appOpsListener); } } } @@ -358,10 +356,10 @@ public final class PermissionPolicyService extends SystemService { pkg.sharedUserId, userId); if (sharedPkgNames != null) { for (String sharedPkgName : sharedPkgNames) { - final PackageParser.Package sharedPkg = packageManagerInternal + final AndroidPackage sharedPkg = packageManagerInternal .getPackage(sharedPkgName); if (sharedPkg != null) { - synchroniser.addPackage(sharedPkg.packageName); + synchroniser.addPackage(sharedPkg.getPackageName()); } } } @@ -378,7 +376,8 @@ public final class PermissionPolicyService extends SystemService { PackageManagerInternal.class); final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser( getUserContext(getContext(), UserHandle.of(userId))); - packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(pkg.packageName)); + packageManagerInternal.forEachPackage( + (pkg) -> synchronizer.addPackage(pkg.getPackageName())); synchronizer.syncPackages(); } @@ -395,24 +394,6 @@ public final class PermissionPolicyService extends SystemService { private final @NonNull SparseIntArray mAllUids = new SparseIntArray(); /** - * All ops that need to be set to default - * - * Currently, only used by the restricted permissions logic. - * - * @see #syncPackages - */ - private final @NonNull ArrayList<OpToChange> mOpsToDefault = new ArrayList<>(); - - /** - * All ops that need to be flipped to allow if default. - * - * Currently, only used by the restricted permissions logic. - * - * @see #syncPackages - */ - private final @NonNull ArrayList<OpToChange> mOpsToAllowIfDefault = new ArrayList<>(); - - /** * All ops that need to be flipped to allow. * * @see #syncPackages @@ -420,20 +401,20 @@ public final class PermissionPolicyService extends SystemService { private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>(); /** - * All ops that need to be flipped to ignore if default. - * - * Currently, only used by the restricted permissions logic. + * All ops that need to be flipped to ignore. * * @see #syncPackages */ - private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfDefault = new ArrayList<>(); + private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>(); /** - * All ops that need to be flipped to ignore. + * All ops that need to be flipped to ignore if not allowed. + * + * Currently, only used by soft restricted permissions logic. * * @see #syncPackages */ - private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>(); + private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>(); /** * All ops that need to be flipped to foreground. @@ -479,19 +460,6 @@ public final class PermissionPolicyService extends SystemService { alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); } - final int allowIfDefaultCount = mOpsToAllowIfDefault.size(); - for (int i = 0; i < allowIfDefaultCount; i++) { - final OpToChange op = mOpsToAllowIfDefault.get(i); - if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { - continue; - } - - boolean wasSet = setUidModeAllowedIfDefault(op.code, op.uid, op.packageName); - if (wasSet) { - alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); - } - } - final int foregroundIfAllowedCount = mOpsToForegroundIfAllow.size(); for (int i = 0; i < foregroundIfAllowedCount; i++) { final OpToChange op = mOpsToForegroundIfAllow.get(i); @@ -527,29 +495,18 @@ public final class PermissionPolicyService extends SystemService { alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); } - final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size(); - for (int i = 0; i < ignoreIfDefaultCount; i++) { - final OpToChange op = mOpsToIgnoreIfDefault.get(i); + final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size(); + for (int i = 0; i < ignoreIfNotAllowedCount; i++) { + final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i); if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { continue; } - boolean wasSet = setUidModeIgnoredIfDefault(op.code, op.uid, op.packageName); + boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName); if (wasSet) { alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); } } - - final int defaultCount = mOpsToDefault.size(); - for (int i = 0; i < defaultCount; i++) { - final OpToChange op = mOpsToDefault.get(i); - if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) { - continue; - } - - setUidModeDefault(op.code, op.uid, op.packageName); - alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1); - } } /** @@ -571,60 +528,49 @@ public final class PermissionPolicyService extends SystemService { return; } - final boolean applyRestriction = - (mPackageManager.getPermissionFlags(permission, pkg.packageName, - mContext.getUser()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; - - if (permissionInfo.isHardRestricted()) { - if (opCode != OP_NONE) { - if (applyRestriction) { - mOpsToDefault.add(new OpToChange(uid, pkg.packageName, opCode)); - } else { - mOpsToAllowIfDefault.add(new OpToChange(uid, pkg.packageName, opCode)); + if (opCode != OP_NONE) { + int permissionFlags = mPackageManager.getPermissionFlags(permission, + pkg.packageName, mContext.getUser()); + boolean isReviewRequired = (permissionFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0; + if (!isReviewRequired) { + boolean isRevokedCompat = + (permissionFlags & FLAG_PERMISSION_REVOKED_COMPAT) != 0; + if (permissionInfo.isHardRestricted()) { + boolean shouldApplyRestriction = + (permissionFlags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; + if (isRevokedCompat || shouldApplyRestriction) { + mOpsToIgnore.add(new OpToChange(uid, pkg.packageName, opCode)); + } else { + mOpsToAllow.add(new OpToChange(uid, pkg.packageName, opCode)); + } + } else if (permissionInfo.isSoftRestricted()) { + SoftRestrictedPermissionPolicy policy = + SoftRestrictedPermissionPolicy.forPermission(mContext, + pkg.applicationInfo, mContext.getUser(), permission); + if (!isRevokedCompat && policy.mayGrantPermission()) { + mOpsToAllow.add(new OpToChange(uid, pkg.packageName, opCode)); + } else { + mOpsToIgnore.add(new OpToChange(uid, pkg.packageName, opCode)); + } } } - } else if (permissionInfo.isSoftRestricted()) { - final SoftRestrictedPermissionPolicy policy = + } + + if (permissionInfo.isSoftRestricted()) { + SoftRestrictedPermissionPolicy policy = SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo, mContext.getUser(), permission); - - if (opCode != OP_NONE) { - if (policy.canBeGranted()) { - mOpsToAllowIfDefault.add(new OpToChange(uid, pkg.packageName, opCode)); + int extraOpCode = policy.getExtraAppOpCode(); + if (extraOpCode != OP_NONE) { + if (policy.mayAllowExtraAppOp()) { + mOpsToAllow.add(new OpToChange(uid, pkg.packageName, extraOpCode)); } else { - mOpsToDefault.add(new OpToChange(uid, pkg.packageName, opCode)); - } - } - - final int op = policy.resolveAppOp(); - if (op != OP_NONE) { - switch (policy.getDesiredOpMode()) { - case MODE_DEFAULT: - mOpsToDefault.add(new OpToChange(uid, pkg.packageName, op)); - break; - case MODE_ALLOWED: - if (policy.shouldSetAppOpIfNotDefault()) { - mOpsToAllow.add(new OpToChange(uid, pkg.packageName, op)); - } else { - mOpsToAllowIfDefault.add( - new OpToChange(uid, pkg.packageName, op)); - } - break; - case MODE_FOREGROUND: - Slog.wtf(LOG_TAG, - "Setting appop to foreground is not implemented"); - break; - case MODE_IGNORED: - if (policy.shouldSetAppOpIfNotDefault()) { - mOpsToIgnore.add(new OpToChange(uid, pkg.packageName, op)); - } else { - mOpsToIgnoreIfDefault.add( - new OpToChange(uid, pkg.packageName, - op)); - } - break; - case MODE_ERRORED: - Slog.wtf(LOG_TAG, "Setting appop to errored is not implemented"); + if (policy.mayDenyExtraAppOpIfGranted()) { + mOpsToIgnore.add(new OpToChange(uid, pkg.packageName, extraOpCode)); + } else { + mOpsToIgnoreIfNotAllowed.add(new OpToChange(uid, pkg.packageName, + extraOpCode)); + } } } } @@ -743,58 +689,49 @@ public final class PermissionPolicyService extends SystemService { } } - private boolean setUidModeAllowedIfDefault(int opCode, int uid, - @NonNull String packageName) { - return setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_ALLOWED, packageName); - } - private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) { setUidMode(opCode, uid, MODE_ALLOWED, packageName); } private boolean setUidModeForegroundIfAllow(int opCode, int uid, @NonNull String packageName) { - return setUidModeIfMode(opCode, uid, MODE_ALLOWED, MODE_FOREGROUND, packageName); + final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( + opCode), uid, packageName); + if (currentMode == MODE_ALLOWED) { + mAppOpsManager.setUidMode(opCode, uid, MODE_FOREGROUND); + return true; + } + return false; } private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) { setUidMode(opCode, uid, MODE_FOREGROUND, packageName); } - private boolean setUidModeIgnoredIfDefault(int opCode, int uid, - @NonNull String packageName) { - return setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_IGNORED, packageName); - } - private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) { setUidMode(opCode, uid, MODE_IGNORED, packageName); } - private void setUidMode(int opCode, int uid, int mode, + private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid, @NonNull String packageName) { - final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager - .opToPublicName(opCode), uid, packageName); - - if (currentMode != mode) { - mAppOpsManager.setUidMode(opCode, uid, mode); + final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( + opCode), uid, packageName); + if (currentMode != MODE_ALLOWED) { + if (currentMode != MODE_IGNORED) { + mAppOpsManager.setUidMode(opCode, uid, MODE_IGNORED); + } + return true; } + return false; } - private boolean setUidModeIfMode(int opCode, int uid, int requiredModeBefore, int newMode, + private void setUidMode(int opCode, int uid, int mode, @NonNull String packageName) { final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); - - if (currentMode == requiredModeBefore) { - mAppOpsManager.setUidMode(opCode, uid, newMode); - return true; + if (currentMode != mode) { + mAppOpsManager.setUidMode(opCode, uid, mode); } - - return false; - } - - private void setUidModeDefault(int opCode, int uid, String packageName) { - setUidMode(opCode, uid, MODE_DEFAULT, packageName); } private class OpToChange { diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java index c1a6dbd8ae14..b0f22e4248ba 100644 --- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java +++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java @@ -18,9 +18,6 @@ package com.android.server.policy; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; -import static android.app.AppOpsManager.MODE_ALLOWED; -import static android.app.AppOpsManager.MODE_DEFAULT; -import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; @@ -55,22 +52,7 @@ public abstract class SoftRestrictedPermissionPolicy { private static final SoftRestrictedPermissionPolicy DUMMY_POLICY = new SoftRestrictedPermissionPolicy() { @Override - public int resolveAppOp() { - return OP_NONE; - } - - @Override - public int getDesiredOpMode() { - return MODE_DEFAULT; - } - - @Override - public boolean shouldSetAppOpIfNotDefault() { - return false; - } - - @Override - public boolean canBeGranted() { + public boolean mayGrantPermission() { return true; } }; @@ -114,10 +96,8 @@ public abstract class SoftRestrictedPermissionPolicy { * Get the policy for a soft restricted permission. * * @param context A context to use - * @param appInfo The application the permission belongs to. Can be {@code null}, but then - * only {@link #resolveAppOp} will work. - * @param user The user the app belongs to. Can be {@code null}, but then only - * {@link #resolveAppOp} will work. + * @param appInfo The application the permission belongs to. + * @param user The user the app belongs to. * @param permission The name of the permission * * @return The policy for this permission @@ -130,82 +110,46 @@ public abstract class SoftRestrictedPermissionPolicy { // where the restricted state allows the permission but only for accessing the medial // collections. case READ_EXTERNAL_STORAGE: { - final int flags; - final boolean applyRestriction; final boolean isWhiteListed; - final boolean hasRequestedLegacyExternalStorage; + boolean shouldApplyRestriction; final int targetSDK; + final boolean hasRequestedLegacyExternalStorage; if (appInfo != null) { PackageManager pm = context.getPackageManager(); - flags = pm.getPermissionFlags(permission, appInfo.packageName, user); - applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; + int flags = pm.getPermissionFlags(permission, appInfo.packageName, user); isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; + shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; targetSDK = getMinimumTargetSDK(context, appInfo, user); - - boolean hasAnyRequestedLegacyExternalStorage = - appInfo.hasRequestedLegacyExternalStorage(); - - // hasRequestedLegacyExternalStorage is per package. To make sure two apps in - // the same shared UID do not fight over what to set, always compute the - // combined hasRequestedLegacyExternalStorage - String[] uidPkgs = pm.getPackagesForUid(appInfo.uid); - if (uidPkgs != null) { - for (String uidPkg : uidPkgs) { - if (!uidPkg.equals(appInfo.packageName)) { - ApplicationInfo uidPkgInfo; - try { - uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user); - } catch (PackageManager.NameNotFoundException e) { - continue; - } - - hasAnyRequestedLegacyExternalStorage |= - uidPkgInfo.hasRequestedLegacyExternalStorage(); - } - } - } - - hasRequestedLegacyExternalStorage = hasAnyRequestedLegacyExternalStorage; + hasRequestedLegacyExternalStorage = hasUidRequestedLegacyExternalStorage( + appInfo.uid, context); } else { - flags = 0; - applyRestriction = false; isWhiteListed = false; - hasRequestedLegacyExternalStorage = false; + shouldApplyRestriction = false; targetSDK = 0; + hasRequestedLegacyExternalStorage = false; } + // We have a check in PermissionPolicyService.PermissionToOpSynchroniser.setUidMode + // to prevent apps losing files in legacy storage, because we are holding the + // package manager lock here. If we ever remove this policy that check should be + // removed as well. return new SoftRestrictedPermissionPolicy() { @Override - public int resolveAppOp() { - return OP_LEGACY_STORAGE; + public boolean mayGrantPermission() { + return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q; } - @Override - public int getDesiredOpMode() { - if (applyRestriction) { - return MODE_DEFAULT; - } else if (hasRequestedLegacyExternalStorage) { - return MODE_ALLOWED; - } else { - return MODE_IGNORED; - } + public int getExtraAppOpCode() { + return OP_LEGACY_STORAGE; } - @Override - public boolean shouldSetAppOpIfNotDefault() { - // Do not switch from allowed -> ignored as this would mean to retroactively - // turn on isolated storage. This will make the app loose all its files. - return getDesiredOpMode() != MODE_IGNORED; + public boolean mayAllowExtraAppOp() { + return !shouldApplyRestriction && hasRequestedLegacyExternalStorage; } - @Override - public boolean canBeGranted() { - if (isWhiteListed || targetSDK >= Build.VERSION_CODES.Q) { - return true; - } else { - return false; - } + public boolean mayDenyExtraAppOpIfGranted() { + return shouldApplyRestriction; } }; } @@ -225,22 +169,7 @@ public abstract class SoftRestrictedPermissionPolicy { return new SoftRestrictedPermissionPolicy() { @Override - public int resolveAppOp() { - return OP_NONE; - } - - @Override - public int getDesiredOpMode() { - return MODE_DEFAULT; - } - - @Override - public boolean shouldSetAppOpIfNotDefault() { - return false; - } - - @Override - public boolean canBeGranted() { + public boolean mayGrantPermission() { return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q; } }; @@ -250,25 +179,51 @@ public abstract class SoftRestrictedPermissionPolicy { } } + private static boolean hasUidRequestedLegacyExternalStorage(int uid, @NonNull Context context) { + PackageManager packageManager = context.getPackageManager(); + String[] packageNames = packageManager.getPackagesForUid(uid); + if (packageNames == null) { + return false; + } + UserHandle user = UserHandle.getUserHandleForUid(uid); + for (String packageName : packageNames) { + ApplicationInfo applicationInfo; + try { + applicationInfo = packageManager.getApplicationInfoAsUser(packageName, 0, user); + } catch (PackageManager.NameNotFoundException e) { + continue; + } + if (applicationInfo.hasRequestedLegacyExternalStorage()) { + return true; + } + } + return false; + } + /** - * @return An app op to be changed based on the state of the permission or - * {@link AppOpsManager#OP_NONE} if not app-op should be set. + * @return If the permission can be granted */ - public abstract int resolveAppOp(); + public abstract boolean mayGrantPermission(); /** - * @return The mode the {@link #resolveAppOp() app op} should be in. + * @return An app op to be changed based on the state of the permission or + * {@link AppOpsManager#OP_NONE} if not app-op should be set. */ - public abstract @AppOpsManager.Mode int getDesiredOpMode(); + public int getExtraAppOpCode() { + return OP_NONE; + } /** - * @return If the {@link #resolveAppOp() app op} should be set even if the app-op is currently - * not {@link AppOpsManager#MODE_DEFAULT}. + * @return Whether the {@link #getExtraAppOpCode() app op} may be granted. */ - public abstract boolean shouldSetAppOpIfNotDefault(); + public boolean mayAllowExtraAppOp() { + return false; + } /** - * @return If the permission can be granted + * @return Whether the {@link #getExtraAppOpCode() app op} may be denied if was granted. */ - public abstract boolean canBeGranted(); + public boolean mayDenyExtraAppOpIfGranted() { + return false; + } } diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index bf8c042835dd..06876352da0b 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -308,12 +308,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C ByteArrayOutputStream out = new ByteArrayOutputStream(); pm.forEachInstalledPackage(FunctionalUtils.uncheckExceptions(pkg -> { - out.write(pkg.packageName.getBytes()); + out.write(pkg.getPackageName().getBytes()); out.write(BitUtils.toBytes(pkg.getLongVersionCode())); - out.write(pm.getApplicationEnabledState(pkg.packageName, userId)); + out.write(pm.getApplicationEnabledState(pkg.getPackageName(), userId)); ArraySet<String> enabledComponents = - pm.getEnabledComponents(pkg.packageName, userId); + pm.getEnabledComponents(pkg.getPackageName(), userId); int numComponents = CollectionUtils.size(enabledComponents); out.write(numComponents); for (int i = 0; i < numComponents; i++) { @@ -321,12 +321,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } ArraySet<String> disabledComponents = - pm.getDisabledComponents(pkg.packageName, userId); + pm.getDisabledComponents(pkg.getPackageName(), userId); numComponents = CollectionUtils.size(disabledComponents); for (int i = 0; i < numComponents; i++) { out.write(disabledComponents.valueAt(i).getBytes()); } - for (Signature signature : pkg.mSigningDetails.signatures) { + for (Signature signature : pkg.getSigningDetails().signatures) { out.write(signature.toByteArray()); } }), userId); diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java index 3f9cc83b53d8..a9f44b9bbeb1 100644 --- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java +++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java @@ -78,7 +78,6 @@ public class AppDataRollbackHelper { + packageRollbackInfo.getPackageName() + ", userId: " + user, ie); } } - packageRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds)); } /** diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java index 2dc495197254..78b8b2e78772 100644 --- a/services/core/java/com/android/server/rollback/Rollback.java +++ b/services/core/java/com/android/server/rollback/Rollback.java @@ -16,14 +16,33 @@ package com.android.server.rollback; +import static com.android.server.rollback.RollbackManagerServiceImpl.sendFailure; + +import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; +import android.content.Context; +import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.content.rollback.RollbackInfo; +import android.content.rollback.RollbackManager; +import android.os.Binder; +import android.os.ParcelFileDescriptor; +import android.os.UserManager; +import android.util.IntArray; +import android.util.Slog; +import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ArrayUtils; import java.io.File; +import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.text.ParseException; @@ -41,10 +60,14 @@ import java.util.List; * {@link PackageRollbackInfo} objects held within. */ class Rollback { + + private static final String TAG = "RollbackManager"; + @IntDef(flag = true, prefix = { "ROLLBACK_STATE_" }, value = { ROLLBACK_STATE_ENABLING, ROLLBACK_STATE_AVAILABLE, ROLLBACK_STATE_COMMITTED, + ROLLBACK_STATE_DELETED }) @Retention(RetentionPolicy.SOURCE) @interface RollbackState {} @@ -66,6 +89,11 @@ class Rollback { static final int ROLLBACK_STATE_COMMITTED = 3; /** + * The rollback has been deleted. + */ + static final int ROLLBACK_STATE_DELETED = 4; + + /** * The session ID for the staged session if this rollback data represents a staged session, * {@code -1} otherwise. */ @@ -234,19 +262,285 @@ class Rollback { } /** - * Sets the state of the rollback to AVAILABLE. + * Returns true if the rollback is in the DELETED state. + */ + @GuardedBy("getLock") + boolean isDeleted() { + return mState == ROLLBACK_STATE_DELETED; + } + + /** + * Enables this rollback for the provided package. + * + * @return boolean True if the rollback was enabled successfully for the specified package. */ @GuardedBy("getLock") - void setAvailable() { + boolean enableForPackage(String packageName, long newVersion, long installedVersion, + boolean isApex, String sourceDir, String[] splitSourceDirs) { + try { + RollbackStore.backupPackageCodePath(this, packageName, sourceDir); + if (!ArrayUtils.isEmpty(splitSourceDirs)) { + for (String dir : splitSourceDirs) { + RollbackStore.backupPackageCodePath(this, packageName, dir); + } + } + } catch (IOException e) { + Slog.e(TAG, "Unable to copy package for rollback for " + packageName, e); + return false; + } + + PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo( + new VersionedPackage(packageName, newVersion), + new VersionedPackage(packageName, installedVersion), + new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */, + isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */); + + info.getPackages().add(packageRollbackInfo); + + return true; + } + + /** + * Snapshots user data for the provided package and user ids. Does nothing if this rollback is + * not in the ENABLING state. + */ + @GuardedBy("getLock") + void snapshotUserData(String packageName, int[] userIds, AppDataRollbackHelper dataHelper) { + if (!isEnabling()) { + return; + } + + for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) { + if (pkgRollbackInfo.getPackageName().equals(packageName)) { + dataHelper.snapshotAppData(info.getRollbackId(), pkgRollbackInfo, userIds); + + RollbackStore.saveRollback(this); + pkgRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds)); + break; + } + } + } + + /** + * Changes the state of the rollback to AVAILABLE. This also changes the timestamp to the + * current time and saves the rollback. Does nothing if this rollback is already in the + * DELETED state. + */ + @GuardedBy("getLock") + void makeAvailable() { + if (isDeleted()) { + Slog.w(TAG, "Cannot make deleted rollback available."); + return; + } mState = ROLLBACK_STATE_AVAILABLE; + mTimestamp = Instant.now(); + RollbackStore.saveRollback(this); + } + + /** + * Commits the rollback. + */ + @GuardedBy("getLock") + void commit(final Context context, List<VersionedPackage> causePackages, + String callerPackageName, IntentSender statusReceiver) { + + if (!isAvailable()) { + sendFailure(context, statusReceiver, + RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE, + "Rollback unavailable"); + return; + } + + // Get a context to use to install the downgraded version of the package. + Context pkgContext; + try { + pkgContext = context.createPackageContext(callerPackageName, 0); + } catch (PackageManager.NameNotFoundException e) { + sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE, + "Invalid callerPackageName"); + return; + } + + PackageManager pm = pkgContext.getPackageManager(); + try { + PackageInstaller packageInstaller = pm.getPackageInstaller(); + PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams( + PackageInstaller.SessionParams.MODE_FULL_INSTALL); + parentParams.setRequestDowngrade(true); + parentParams.setMultiPackage(); + if (isStaged()) { + parentParams.setStaged(); + } + + int parentSessionId = packageInstaller.createSession(parentParams); + PackageInstaller.Session parentSession = packageInstaller.openSession( + parentSessionId); + + for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) { + PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( + PackageInstaller.SessionParams.MODE_FULL_INSTALL); + // TODO: We can't get the installerPackageName for apex + // (b/123920130). Is it okay to ignore the installer package + // for apex? + if (!pkgRollbackInfo.isApex()) { + String installerPackageName = + pm.getInstallerPackageName(pkgRollbackInfo.getPackageName()); + if (installerPackageName != null) { + params.setInstallerPackageName(installerPackageName); + } + } + params.setRequestDowngrade(true); + params.setRequiredInstalledVersionCode( + pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode()); + if (isStaged()) { + params.setStaged(); + } + if (pkgRollbackInfo.isApex()) { + params.setInstallAsApex(); + } + int sessionId = packageInstaller.createSession(params); + PackageInstaller.Session session = packageInstaller.openSession(sessionId); + File[] packageCodePaths = RollbackStore.getPackageCodePaths( + this, pkgRollbackInfo.getPackageName()); + if (packageCodePaths == null) { + sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE, + "Backup copy of package inaccessible"); + return; + } + + for (File packageCodePath : packageCodePaths) { + try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(packageCodePath, + ParcelFileDescriptor.MODE_READ_ONLY)) { + final long token = Binder.clearCallingIdentity(); + try { + session.write(packageCodePath.getName(), 0, + packageCodePath.length(), + fd); + } finally { + Binder.restoreCallingIdentity(token); + } + } + } + parentSession.addChildSessionId(sessionId); + } + + final LocalIntentReceiver receiver = new LocalIntentReceiver( + (Intent result) -> { + int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + if (status != PackageInstaller.STATUS_SUCCESS) { + // Committing the rollback failed, but we still have all the info we + // need to try rolling back again, so restore the rollback state to how + // it was before we tried committing. + // TODO: Should we just kill this rollback if commit failed? + // Why would we expect commit not to fail again? + // TODO: Could this cause a rollback to be resurrected + // if it should otherwise have expired by now? + synchronized (mLock) { + mState = ROLLBACK_STATE_AVAILABLE; + mRestoreUserDataInProgress = false; + } + sendFailure(context, statusReceiver, + RollbackManager.STATUS_FAILURE_INSTALL, + "Rollback downgrade install failed: " + + result.getStringExtra( + PackageInstaller.EXTRA_STATUS_MESSAGE)); + return; + } + + synchronized (mLock) { + if (!isStaged()) { + // All calls to restoreUserData should have + // completed by now for a non-staged install. + mRestoreUserDataInProgress = false; + } + + info.setCommittedSessionId(parentSessionId); + info.getCausePackages().addAll(causePackages); + RollbackStore.deletePackageCodePaths(this); + RollbackStore.saveRollback(this); + } + + // Send success. + try { + final Intent fillIn = new Intent(); + fillIn.putExtra( + RollbackManager.EXTRA_STATUS, RollbackManager.STATUS_SUCCESS); + statusReceiver.sendIntent(context, 0, fillIn, null, null); + } catch (IntentSender.SendIntentException e) { + // Nowhere to send the result back to, so don't bother. + } + + Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED); + + for (UserInfo userInfo : UserManager.get(context).getUsers(true)) { + context.sendBroadcastAsUser(broadcast, + userInfo.getUserHandle(), + Manifest.permission.MANAGE_ROLLBACKS); + } + } + ); + + mState = ROLLBACK_STATE_COMMITTED; + mRestoreUserDataInProgress = true; + parentSession.commit(receiver.getIntentSender()); + } catch (IOException e) { + Slog.e(TAG, "Rollback failed", e); + sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE, + "IOException: " + e.toString()); + } } /** - * Sets the state of the rollback to COMMITTED. + * Restores user data for the specified package if this rollback is currently marked as + * having a restore in progress. + * + * @return boolean True if this rollback has a restore in progress and contains the specified + * package. */ @GuardedBy("getLock") - void setCommitted() { - mState = ROLLBACK_STATE_COMMITTED; + boolean restoreUserDataForPackageIfInProgress(String packageName, int[] userIds, int appId, + String seInfo, AppDataRollbackHelper dataHelper) { + if (!isRestoreUserDataInProgress()) { + return false; + } + + boolean foundPackage = false; + for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) { + if (pkgRollbackInfo.getPackageName().equals(packageName)) { + foundPackage = true; + boolean changedRollback = false; + for (int userId : userIds) { + changedRollback |= dataHelper.restoreAppData( + info.getRollbackId(), pkgRollbackInfo, userId, appId, seInfo); + } + // We've updated metadata about this rollback, so save it to flash. + if (changedRollback) { + RollbackStore.saveRollback(this); + } + break; + } + } + return foundPackage; + } + + /** + * Deletes app data snapshots associated with this rollback, and moves to the DELETED state. + */ + @GuardedBy("getLock") + void delete(AppDataRollbackHelper dataHelper) { + for (PackageRollbackInfo pkgInfo : info.getPackages()) { + IntArray snapshottedUsers = pkgInfo.getSnapshottedUsers(); + for (int i = 0; i < snapshottedUsers.size(); i++) { + // Destroy app data snapshot. + int userId = snapshottedUsers.get(i); + + dataHelper.destroyAppDataSnapshot(info.getRollbackId(), pkgInfo, userId); + } + } + + RollbackStore.deleteRollback(this); + mState = ROLLBACK_STATE_DELETED; } /** @@ -288,8 +582,8 @@ class Rollback { */ @GuardedBy("getLock") boolean includesPackage(String packageName) { - for (PackageRollbackInfo info : info.getPackages()) { - if (info.getPackageName().equals(packageName)) { + for (PackageRollbackInfo packageRollbackInfo : info.getPackages()) { + if (packageRollbackInfo.getPackageName().equals(packageName)) { return true; } } @@ -302,9 +596,10 @@ class Rollback { */ @GuardedBy("getLock") boolean includesPackageWithDifferentVersion(String packageName, long versionCode) { - for (PackageRollbackInfo info : info.getPackages()) { - if (info.getPackageName().equals(packageName) - && info.getVersionRolledBackFrom().getLongVersionCode() != versionCode) { + for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) { + if (pkgRollbackInfo.getPackageName().equals(packageName) + && pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode() + != versionCode) { return true; } } @@ -317,8 +612,8 @@ class Rollback { @GuardedBy("getLock") List<String> getPackageNames() { List<String> result = new ArrayList<>(); - for (PackageRollbackInfo info : info.getPackages()) { - result.add(info.getPackageName()); + for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) { + result.add(pkgRollbackInfo.getPackageName()); } return result; } @@ -329,9 +624,9 @@ class Rollback { @GuardedBy("getLock") List<String> getApexPackageNames() { List<String> result = new ArrayList<>(); - for (PackageRollbackInfo info : info.getPackages()) { - if (info.isApex()) { - result.add(info.getPackageName()); + for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) { + if (pkgRollbackInfo.isApex()) { + result.add(pkgRollbackInfo.getPackageName()); } } return result; diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index e8e448aa118e..2221dff79336 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -43,7 +43,6 @@ import android.os.Binder; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; -import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; @@ -53,10 +52,8 @@ import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; import android.util.SparseBooleanArray; -import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.LocalServices; import com.android.server.Watchdog; @@ -64,7 +61,6 @@ import com.android.server.pm.Installer; import java.io.File; import java.io.FileDescriptor; -import java.io.IOException; import java.io.PrintWriter; import java.security.SecureRandom; import java.time.Instant; @@ -339,7 +335,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (rollback.getLock()) { rollback.setTimestamp( rollback.getTimestamp().plusMillis(timeDifference)); - saveRollback(rollback); + RollbackStore.saveRollback(rollback); } } } @@ -366,154 +362,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Rollback rollback = getRollbackForId(rollbackId); if (rollback == null) { - sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE, + sendFailure( + mContext, statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE, "Rollback unavailable"); return; } synchronized (rollback.getLock()) { - if (!rollback.isAvailable()) { - sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE, - "Rollback unavailable"); - return; - } - - // Get a context for the caller to use to install the downgraded - // version of the package. - final Context context; - try { - context = mContext.createPackageContext(callerPackageName, 0); - } catch (PackageManager.NameNotFoundException e) { - sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE, - "Invalid callerPackageName"); - return; - } - - PackageManager pm = context.getPackageManager(); - try { - PackageInstaller packageInstaller = pm.getPackageInstaller(); - PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams( - PackageInstaller.SessionParams.MODE_FULL_INSTALL); - parentParams.setRequestDowngrade(true); - parentParams.setMultiPackage(); - if (rollback.isStaged()) { - parentParams.setStaged(); - } - - int parentSessionId = packageInstaller.createSession(parentParams); - PackageInstaller.Session parentSession = packageInstaller.openSession( - parentSessionId); - - for (PackageRollbackInfo info : rollback.info.getPackages()) { - PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( - PackageInstaller.SessionParams.MODE_FULL_INSTALL); - // TODO: We can't get the installerPackageName for apex - // (b/123920130). Is it okay to ignore the installer package - // for apex? - if (!info.isApex()) { - String installerPackageName = - pm.getInstallerPackageName(info.getPackageName()); - if (installerPackageName != null) { - params.setInstallerPackageName(installerPackageName); - } - } - params.setRequestDowngrade(true); - params.setRequiredInstalledVersionCode( - info.getVersionRolledBackFrom().getLongVersionCode()); - if (rollback.isStaged()) { - params.setStaged(); - } - if (info.isApex()) { - params.setInstallAsApex(); - } - int sessionId = packageInstaller.createSession(params); - PackageInstaller.Session session = packageInstaller.openSession(sessionId); - File[] packageCodePaths = RollbackStore.getPackageCodePaths( - rollback, info.getPackageName()); - if (packageCodePaths == null) { - sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE, - "Backup copy of package inaccessible"); - return; - } - - for (File packageCodePath : packageCodePaths) { - try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(packageCodePath, - ParcelFileDescriptor.MODE_READ_ONLY)) { - final long token = Binder.clearCallingIdentity(); - try { - session.write(packageCodePath.getName(), 0, - packageCodePath.length(), - fd); - } finally { - Binder.restoreCallingIdentity(token); - } - } - } - parentSession.addChildSessionId(sessionId); - } - - final LocalIntentReceiver receiver = new LocalIntentReceiver( - (Intent result) -> getHandler().post(() -> { - - int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); - if (status != PackageInstaller.STATUS_SUCCESS) { - // Committing the rollback failed, but we - // still have all the info we need to try - // rolling back again, so restore the rollback - // state to how it was before we tried - // committing. - // TODO: Should we just kill this rollback if - // commit failed? Why would we expect commit - // not to fail again? - // TODO: Could this cause a rollback to be - // resurrected if it should otherwise have - // expired by now? - synchronized (rollback.getLock()) { - rollback.setAvailable(); - rollback.setRestoreUserDataInProgress(false); - } - sendFailure(statusReceiver, - RollbackManager.STATUS_FAILURE_INSTALL, - "Rollback downgrade install failed: " - + result.getStringExtra( - PackageInstaller.EXTRA_STATUS_MESSAGE)); - return; - } - - synchronized (rollback.getLock()) { - if (!rollback.isStaged()) { - // All calls to restoreUserData should have - // completed by now for a non-staged install. - rollback.setRestoreUserDataInProgress(false); - } - - rollback.info.setCommittedSessionId(parentSessionId); - rollback.info.getCausePackages().addAll(causePackages); - RollbackStore.deletePackageCodePaths(rollback); - saveRollback(rollback); - } - - sendSuccess(statusReceiver); - - Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED); - - for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) { - mContext.sendBroadcastAsUser(broadcast, - userInfo.getUserHandle(), - Manifest.permission.MANAGE_ROLLBACKS); - } - }) - ); - - rollback.setCommitted(); - rollback.setRestoreUserDataInProgress(true); - parentSession.commit(receiver.getIntentSender()); - } catch (IOException e) { - Slog.e(TAG, "Rollback failed", e); - sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE, - "IOException: " + e.toString()); - return; - } + rollback.commit(mContext, causePackages, callerPackageName, statusReceiver); } } @@ -552,7 +407,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (rollback.getLock()) { if (rollback.includesPackage(packageName)) { iter.remove(); - deleteRollback(rollback); + rollback.delete(mAppDataRollbackHelper); } } } @@ -596,7 +451,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (rollback.getLock()) { if (mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser( userId, rollback)) { - saveRollback(rollback); + RollbackStore.saveRollback(rollback); } } } @@ -658,7 +513,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // mRollbacks, or is it okay to leave as // unavailable until the next reboot when it will go // away on its own? - deleteRollback(rollback); + rollback.delete(mAppDataRollbackHelper); } else if (session.isStagedSessionApplied()) { makeRollbackAvailable(rollback); } @@ -674,7 +529,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { if (session != null) { if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) { rollback.setRestoreUserDataInProgress(false); - saveRollback(rollback); + RollbackStore.saveRollback(rollback); } } } @@ -716,7 +571,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { && rollback.includesPackageWithDifferentVersion(packageName, installedVersion)) { iter.remove(); - deleteRollback(rollback); + rollback.delete(mAppDataRollbackHelper); } } } @@ -738,27 +593,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * @param status the RollbackManager.STATUS_* code with the failure. * @param message the failure message. */ - private void sendFailure(IntentSender statusReceiver, @RollbackManager.Status int status, - String message) { + static void sendFailure(Context context, IntentSender statusReceiver, + @RollbackManager.Status int status, String message) { Slog.e(TAG, message); try { final Intent fillIn = new Intent(); fillIn.putExtra(RollbackManager.EXTRA_STATUS, status); fillIn.putExtra(RollbackManager.EXTRA_STATUS_MESSAGE, message); - statusReceiver.sendIntent(mContext, 0, fillIn, null, null); - } catch (IntentSender.SendIntentException e) { - // Nowhere to send the result back to, so don't bother. - } - } - - /** - * Notifies an IntentSender of success. - */ - private void sendSuccess(IntentSender statusReceiver) { - try { - final Intent fillIn = new Intent(); - fillIn.putExtra(RollbackManager.EXTRA_STATUS, RollbackManager.STATUS_SUCCESS); - statusReceiver.sendIntent(mContext, 0, fillIn, null, null); + statusReceiver.sendIntent(context, 0, fillIn, null, null); } catch (IntentSender.SendIntentException e) { // Nowhere to send the result back to, so don't bother. } @@ -781,7 +623,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { rollback.getTimestamp() .plusMillis(mRollbackLifetimeDurationInMillis))) { iter.remove(); - deleteRollback(rollback); + rollback.delete(mAppDataRollbackHelper); } else if (oldest == null || oldest.isAfter(rollback.getTimestamp())) { oldest = rollback.getTimestamp(); } @@ -954,7 +796,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } // Get information about the package to be installed. - PackageParser.PackageLite newPackage = null; + PackageParser.PackageLite newPackage; try { newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0); } catch (PackageParser.PackageParserException e) { @@ -973,11 +815,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return false; } - VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode); final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0); // Get information about the currently installed package. - PackageManager pm = mContext.getPackageManager(); final PackageInfo pkgInfo; try { pkgInfo = getPackageInfo(packageName); @@ -988,32 +828,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return false; } - VersionedPackage installedVersion = new VersionedPackage(packageName, - pkgInfo.getLongVersionCode()); - - PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo( - newVersion, installedVersion, - new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */, - isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */); - - - try { - ApplicationInfo appInfo = pkgInfo.applicationInfo; - RollbackStore.backupPackageCodePath(rollback, packageName, appInfo.sourceDir); - if (!ArrayUtils.isEmpty(appInfo.splitSourceDirs)) { - for (String sourceDir : appInfo.splitSourceDirs) { - RollbackStore.backupPackageCodePath(rollback, packageName, sourceDir); - } - } - } catch (IOException e) { - Slog.e(TAG, "Unable to copy package for rollback for " + packageName, e); - return false; - } - + ApplicationInfo appInfo = pkgInfo.applicationInfo; synchronized (rollback.getLock()) { - rollback.info.getPackages().add(packageRollbackInfo); + return rollback.enableForPackage(packageName, newPackage.versionCode, + pkgInfo.getLongVersionCode(), isApex, appInfo.sourceDir, + appInfo.splitSourceDirs); } - return true; } @Override @@ -1026,7 +846,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { getHandler().post(() -> { snapshotUserDataInternal(packageName, userIds); - restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token); + restoreUserDataInternal(packageName, userIds, appId, seInfo); final PackageManagerInternal pmi = LocalServices.getService( PackageManagerInternal.class); pmi.finishPackageInstall(token, false); @@ -1039,69 +859,32 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { for (int i = 0; i < mRollbacks.size(); i++) { Rollback rollback = mRollbacks.get(i); synchronized (rollback.getLock()) { - if (!rollback.isEnabling()) { - continue; - } - - for (PackageRollbackInfo info : rollback.info.getPackages()) { - if (info.getPackageName().equals(packageName)) { - mAppDataRollbackHelper.snapshotAppData( - rollback.info.getRollbackId(), info, userIds); - saveRollback(rollback); - break; - } - } + rollback.snapshotUserData(packageName, userIds, mAppDataRollbackHelper); } } // non-staged installs - PackageRollbackInfo info; for (NewRollback rollback : mNewRollbacks) { synchronized (rollback.rollback.getLock()) { - info = getPackageRollbackInfo(rollback.rollback, packageName); - if (info != null) { - mAppDataRollbackHelper.snapshotAppData( - rollback.rollback.info.getRollbackId(), info, userIds); - saveRollback(rollback.rollback); - } + rollback.rollback.snapshotUserData( + packageName, userIds, mAppDataRollbackHelper); } } } } - private void restoreUserDataInternal(String packageName, int[] userIds, int appId, - long ceDataInode, String seInfo, int token) { - PackageRollbackInfo info = null; - Rollback rollback = null; + private void restoreUserDataInternal( + String packageName, int[] userIds, int appId, String seInfo) { synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { - Rollback candidate = mRollbacks.get(i); - synchronized (candidate.getLock()) { - if (candidate.isRestoreUserDataInProgress()) { - info = getPackageRollbackInfo(candidate, packageName); - if (info != null) { - rollback = candidate; - break; - } + Rollback rollback = mRollbacks.get(i); + synchronized (rollback.getLock()) { + if (rollback.restoreUserDataForPackageIfInProgress( + packageName, userIds, appId, seInfo, mAppDataRollbackHelper)) { + return; } } } } - - if (rollback == null) { - return; - } - - for (int userId : userIds) { - synchronized (rollback.getLock()) { - final boolean changedRollback = mAppDataRollbackHelper.restoreAppData( - rollback.info.getRollbackId(), info, userId, appId, seInfo); - - // We've updated metadata about this rollback, so save it to flash. - if (changedRollback) { - saveRollback(rollback); - } - } - } } @Override @@ -1189,7 +972,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { if (rollback != null) { synchronized (rollback.getLock()) { rollback.setApkSessionId(apkSessionId); - saveRollback(rollback); + RollbackStore.saveRollback(rollback); } } }); @@ -1238,8 +1021,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { * Returns -1 if the package is not currently installed. */ private long getInstalledPackageVersion(String packageName) { - PackageManager pm = mContext.getPackageManager(); - PackageInfo pkgInfo = null; + PackageInfo pkgInfo; try { pkgInfo = getPackageInfo(packageName); } catch (PackageManager.NameNotFoundException e) { @@ -1250,9 +1032,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } /** - * Gets PackageInfo for the given package. - * Matches any user and apex. Returns null if no such package is - * installed. + * Gets PackageInfo for the given package. Matches any user and apex. + * + * @throws PackageManager.NameNotFoundException if no such package is installed. */ private PackageInfo getPackageInfo(String packageName) throws PackageManager.NameNotFoundException { @@ -1268,13 +1050,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } } - - private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) { - return a != null && b != null - && a.getPackageName().equals(b.getPackageName()) - && a.getLongVersionCode() == b.getLongVersionCode(); - } - private class SessionCallback extends PackageInstaller.SessionCallback { @Override @@ -1326,23 +1101,23 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (rollback.getLock()) { if (!success) { // The install session was aborted, clean up the pending install. - deleteRollback(rollback); + rollback.delete(mAppDataRollbackHelper); return null; } if (newRollback.isCancelled) { Slog.e(TAG, "Rollback has been cancelled by PackageManager"); - deleteRollback(rollback); + rollback.delete(mAppDataRollbackHelper); return null; } if (rollback.info.getPackages().size() != newRollback.packageSessionIds.length) { Slog.e(TAG, "Failed to enable rollback for all packages in session."); - deleteRollback(rollback); + rollback.delete(mAppDataRollbackHelper); return null; } - saveRollback(rollback); + RollbackStore.saveRollback(rollback); } synchronized (mLock) { // Note: There is a small window of time between when @@ -1363,17 +1138,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @GuardedBy("rollback.getLock") private void makeRollbackAvailable(Rollback rollback) { - // TODO: What if the rollback has since been expired, for example due - // to a new package being installed. Won't this revive an expired - // rollback? Consider adding a ROLLBACK_STATE_EXPIRED to address this. - rollback.setAvailable(); - rollback.setTimestamp(Instant.now()); - saveRollback(rollback); + rollback.makeAvailable(); // TODO(zezeozue): Provide API to explicitly start observing instead // of doing this for all rollbacks. If we do this for all rollbacks, // should document in PackageInstaller.SessionParams#setEnableRollback - // After enabling and commiting any rollback, observe packages and + // After enabling and committing any rollback, observe packages and // prepare to rollback if packages crashes too frequently. mPackageHealthObserver.startObservingHealth(rollback.getPackageNames(), mRollbackLifetimeDurationInMillis); @@ -1396,22 +1166,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return null; } - /** - * Returns the {@code PackageRollbackInfo} associated with {@code packageName} from - * a specified {@code Rollback}. - */ - @GuardedBy("rollback.getLock") - private static PackageRollbackInfo getPackageRollbackInfo(Rollback rollback, - String packageName) { - for (PackageRollbackInfo info : rollback.info.getPackages()) { - if (info.getPackageName().equals(packageName)) { - return info; - } - } - - return null; - } - @GuardedBy("mLock") private int allocateRollbackIdLocked() { int n = 0; @@ -1427,35 +1181,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { throw new IllegalStateException("Failed to allocate rollback ID"); } - @GuardedBy("rollback.getLock") - private void deleteRollback(Rollback rollback) { - for (PackageRollbackInfo info : rollback.info.getPackages()) { - IntArray snapshottedUsers = info.getSnapshottedUsers(); - for (int i = 0; i < snapshottedUsers.size(); i++) { - int userId = snapshottedUsers.get(i); - mAppDataRollbackHelper.destroyAppDataSnapshot(rollback.info.getRollbackId(), - info, userId); - } - } - mRollbackStore.deleteRollback(rollback); - } - - /** - * Saves a rollback, swallowing any IOExceptions. - * For those times when it's not obvious what to do about the IOException. - * TODO: Double check we can't do a better job handling the IOException in - * a cases where this method is called. - */ - @GuardedBy("rollback.getLock") - private void saveRollback(Rollback rollback) { - try { - mRollbackStore.saveRollback(rollback); - } catch (IOException ioe) { - Slog.e(TAG, "Unable to save rollback for: " - + rollback.info.getRollbackId(), ioe); - } - } - @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index b6d1f1875907..a9331aa5648f 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -253,7 +253,7 @@ class RollbackStore { * Saves the given rollback to persistent storage. */ @GuardedBy("rollback.getLock") - void saveRollback(Rollback rollback) throws IOException { + static void saveRollback(Rollback rollback) { try { JSONObject dataJson = new JSONObject(); dataJson.put("info", rollbackInfoToJson(rollback.info)); @@ -266,15 +266,15 @@ class RollbackStore { PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json")); pw.println(dataJson.toString()); pw.close(); - } catch (JSONException e) { - throw new IOException(e); + } catch (JSONException | IOException e) { + Slog.e(TAG, "Unable to save rollback for: " + rollback.info.getRollbackId(), e); } } /** * Removes all persistent storage associated with the given rollback. */ - void deleteRollback(Rollback rollback) { + static void deleteRollback(Rollback rollback) { removeFile(rollback.getBackupDir()); } diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java index 2b25b8921540..8431ae4aeb98 100644 --- a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java +++ b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java @@ -72,6 +72,30 @@ final class ProcfsMemoryUtil { return null; } + /** + * Reads cmdline of a process from procfs. + * + * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string + * if the file is not available. + */ + public static String readCmdlineFromProcfs(int pid) { + return parseCmdline(readFile("/proc/" + pid + "/cmdline")); + } + + /** + * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs. + * + * Parsing is required to strip anything after the first null byte. + */ + @VisibleForTesting + static String parseCmdline(String contents) { + int firstNullByte = contents.indexOf("\0"); + if (firstNullByte == -1) { + return contents; + } + return contents.substring(0, firstNullByte); + } + private static String readFile(String path) { try { final File file = new File(path); diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 67830a930caf..1d3ac6a9f14f 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -24,11 +24,10 @@ import static android.os.storage.VolumeInfo.TYPE_PRIVATE; import static android.os.storage.VolumeInfo.TYPE_PUBLIC; import static com.android.internal.util.Preconditions.checkNotNull; -import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem; -import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs; import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs; import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs; +import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs; import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs; import android.annotation.NonNull; @@ -1193,48 +1192,13 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { e.writeLong(memoryStat.rssInBytes); e.writeLong(memoryStat.cacheInBytes); e.writeLong(memoryStat.swapInBytes); - e.writeLong(0); // unused - e.writeLong(memoryStat.startTimeNanos); - e.writeInt(anonAndSwapInKilobytes(memoryStat)); + e.writeLong(-1); // unused + e.writeLong(-1); // unused + e.writeInt(-1); // unsed pulledData.add(e); } } - private void pullNativeProcessMemoryState( - int tagId, long elapsedNanos, long wallClockNanos, - List<StatsLogEventWrapper> pulledData) { - int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES); - for (int pid : pids) { - String processName = readCmdlineFromProcfs(pid); - MemoryStat memoryStat = readMemoryStatFromProcfs(pid); - if (memoryStat == null) { - continue; - } - int uid = getUidForPid(pid); - // Sometimes we get here a process that is not included in the whitelist. It comes - // from forking the zygote for an app. We can ignore that sample because this process - // is collected by ProcessMemoryState. - if (isAppUid(uid)) { - continue; - } - StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); - e.writeInt(uid); - e.writeString(processName); - e.writeLong(memoryStat.pgfault); - e.writeLong(memoryStat.pgmajfault); - e.writeLong(memoryStat.rssInBytes); - e.writeLong(0); // unused - e.writeLong(memoryStat.startTimeNanos); - e.writeLong(memoryStat.swapInBytes); - e.writeInt(anonAndSwapInKilobytes(memoryStat)); - pulledData.add(e); - } - } - - private static int anonAndSwapInKilobytes(MemoryStat memoryStat) { - return (int) ((memoryStat.anonRssInBytes + memoryStat.swapInBytes) / 1024); - } - private void pullProcessMemoryHighWaterMark( int tagId, long elapsedNanos, long wallClockNanos, List<StatsLogEventWrapper> pulledData) { @@ -2405,10 +2369,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret); break; } - case StatsLog.NATIVE_PROCESS_MEMORY_STATE: { - pullNativeProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret); - break; - } case StatsLog.PROCESS_MEMORY_HIGH_WATER_MARK: { pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret); break; diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java b/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java index f8ffb7c1c0e2..b7bc77dc97ee 100644 --- a/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java +++ b/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java @@ -21,8 +21,6 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.media.tv.ITvRemoteProvider; -import android.media.tv.ITvRemoteServiceInput; -import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; @@ -30,44 +28,33 @@ import android.util.Log; import android.util.Slog; import java.io.PrintWriter; -import java.lang.ref.WeakReference; /** * Maintains a connection to a tv remote provider service. */ final class TvRemoteProviderProxy implements ServiceConnection { - private static final String TAG = "TvRemoteProvProxy"; // max. 23 chars + private static final String TAG = "TvRemoteProviderProxy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE); - private static final boolean DEBUG_KEY = false; // This should match TvRemoteProvider.ACTION_TV_REMOTE_PROVIDER protected static final String SERVICE_INTERFACE = "com.android.media.tv.remoteprovider.TvRemoteProvider"; private final Context mContext; + private final Object mLock; private final ComponentName mComponentName; private final int mUserId; private final int mUid; - /** - * State guarded by mLock. - * This is the first lock in sequence for an incoming call. - * The second lock is always {@link TvRemoteService#mLock} - * - * There are currently no methods that break this sequence. - */ - private final Object mLock = new Object(); - - private ProviderMethods mProviderMethods; - // Connection state + // State changes happen only in the main thread, hence no lock is needed private boolean mRunning; private boolean mBound; - private Connection mActiveConnection; + private boolean mConnected; - TvRemoteProviderProxy(Context context, ProviderMethods provider, + TvRemoteProviderProxy(Context context, Object lock, ComponentName componentName, int userId, int uid) { mContext = context; - mProviderMethods = provider; + mLock = lock; mComponentName = componentName; mUserId = userId; mUid = uid; @@ -78,7 +65,7 @@ final class TvRemoteProviderProxy implements ServiceConnection { pw.println(prefix + " mUserId=" + mUserId); pw.println(prefix + " mRunning=" + mRunning); pw.println(prefix + " mBound=" + mBound); - pw.println(prefix + " mActiveConnection=" + mActiveConnection); + pw.println(prefix + " mConnected=" + mConnected); } public boolean hasComponentName(String packageName, String className) { @@ -109,11 +96,9 @@ final class TvRemoteProviderProxy implements ServiceConnection { } public void rebindIfDisconnected() { - synchronized (mLock) { - if (mActiveConnection == null && mRunning) { - unbind(); - bind(); - } + if (mRunning && !mConnected) { + unbind(); + bind(); } } @@ -129,7 +114,7 @@ final class TvRemoteProviderProxy implements ServiceConnection { mBound = mContext.bindServiceAsUser(service, this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUserId)); - if (!mBound && DEBUG) { + if (DEBUG && !mBound) { Slog.d(TAG, this + ": Bind failed"); } } catch (SecurityException ex) { @@ -147,7 +132,6 @@ final class TvRemoteProviderProxy implements ServiceConnection { } mBound = false; - disconnect(); mContext.unbindService(this); } } @@ -158,392 +142,27 @@ final class TvRemoteProviderProxy implements ServiceConnection { Slog.d(TAG, this + ": onServiceConnected()"); } - if (mBound) { - disconnect(); + mConnected = true; - ITvRemoteProvider provider = ITvRemoteProvider.Stub.asInterface(service); - if (provider != null) { - Connection connection = new Connection(provider); - if (connection.register()) { - synchronized (mLock) { - mActiveConnection = connection; - } - if (DEBUG) { - Slog.d(TAG, this + ": Connected successfully."); - } - } else { - if (DEBUG) { - Slog.d(TAG, this + ": Registration failed"); - } - } - } else { - Slog.e(TAG, this + ": Service returned invalid remote-control provider binder"); - } + final ITvRemoteProvider provider = ITvRemoteProvider.Stub.asInterface(service); + if (provider == null) { + Slog.e(TAG, this + ": Invalid binder"); + return; } - } - @Override - public void onServiceDisconnected(ComponentName name) { - if (DEBUG) Slog.d(TAG, this + ": Service disconnected"); - disconnect(); - } - - private void disconnect() { - synchronized (mLock) { - if (mActiveConnection != null) { - mActiveConnection.dispose(); - mActiveConnection = null; - } + try { + provider.setRemoteServiceInputSink(new TvRemoteServiceInput(mLock, provider)); + } catch (RemoteException e) { + Slog.e(TAG, this + ": Failed remote call to setRemoteServiceInputSink"); } } - interface ProviderMethods { - // InputBridge - boolean openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name, - int width, int height, int maxPointers); - - void closeInputBridge(TvRemoteProviderProxy provider, IBinder token); - - void clearInputBridge(TvRemoteProviderProxy provider, IBinder token); - - void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode); - - void sendKeyUp(TvRemoteProviderProxy provider, IBinder token, int keyCode); - - void sendPointerDown(TvRemoteProviderProxy provider, IBinder token, int pointerId, int x, - int y); - - void sendPointerUp(TvRemoteProviderProxy provider, IBinder token, int pointerId); - - void sendPointerSync(TvRemoteProviderProxy provider, IBinder token); - } - - private final class Connection { - private final ITvRemoteProvider mTvRemoteProvider; - private final RemoteServiceInputProvider mServiceInputProvider; - - public Connection(ITvRemoteProvider provider) { - mTvRemoteProvider = provider; - mServiceInputProvider = new RemoteServiceInputProvider(this); - } - - public boolean register() { - if (DEBUG) Slog.d(TAG, "Connection::register()"); - try { - mTvRemoteProvider.setRemoteServiceInputSink(mServiceInputProvider); - return true; - } catch (RemoteException ex) { - dispose(); - return false; - } - } - - public void dispose() { - if (DEBUG) Slog.d(TAG, "Connection::dispose()"); - mServiceInputProvider.dispose(); - } - - - public void onInputBridgeConnected(IBinder token) { - if (DEBUG) Slog.d(TAG, this + ": onInputBridgeConnected"); - try { - mTvRemoteProvider.onInputBridgeConnected(token); - } catch (RemoteException ex) { - Slog.e(TAG, "Failed to deliver onInputBridgeConnected. ", ex); - } - } - - void openInputBridge(final IBinder token, final String name, final int width, - final int height, final int maxPointers) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - if (DEBUG) { - Slog.d(TAG, this + ": openInputBridge," + - " token=" + token + ", name=" + name); - } - final long idToken = Binder.clearCallingIdentity(); - try { - if (mProviderMethods.openInputBridge(TvRemoteProviderProxy.this, token, - name, width, height, maxPointers)) { - onInputBridgeConnected(token); - } - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "openInputBridge, Invalid connection or incorrect uid: " + Binder - .getCallingUid()); - } - } - } - } - - void closeInputBridge(final IBinder token) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - if (DEBUG) { - Slog.d(TAG, this + ": closeInputBridge," + - " token=" + token); - } - final long idToken = Binder.clearCallingIdentity(); - try { - mProviderMethods.closeInputBridge(TvRemoteProviderProxy.this, token); - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "closeInputBridge, Invalid connection or incorrect uid: " + - Binder.getCallingUid()); - } - } - } - } - - void clearInputBridge(final IBinder token) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - if (DEBUG) { - Slog.d(TAG, this + ": clearInputBridge," + - " token=" + token); - } - final long idToken = Binder.clearCallingIdentity(); - try { - mProviderMethods.clearInputBridge(TvRemoteProviderProxy.this, token); - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "clearInputBridge, Invalid connection or incorrect uid: " + - Binder.getCallingUid()); - } - } - } - } - - void sendTimestamp(final IBinder token, final long timestamp) { - if (DEBUG) { - Slog.e(TAG, "sendTimestamp is deprecated, please remove all usages of this API."); - } - } - - void sendKeyDown(final IBinder token, final int keyCode) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - if (DEBUG_KEY) { - Slog.d(TAG, this + ": sendKeyDown," + - " token=" + token + ", keyCode=" + keyCode); - } - final long idToken = Binder.clearCallingIdentity(); - try { - mProviderMethods.sendKeyDown(TvRemoteProviderProxy.this, token, keyCode); - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "sendKeyDown, Invalid connection or incorrect uid: " + Binder - .getCallingUid()); - } - } - } - } - - void sendKeyUp(final IBinder token, final int keyCode) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - if (DEBUG_KEY) { - Slog.d(TAG, this + ": sendKeyUp," + - " token=" + token + ", keyCode=" + keyCode); - } - final long idToken = Binder.clearCallingIdentity(); - try { - mProviderMethods.sendKeyUp(TvRemoteProviderProxy.this, token, keyCode); - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "sendKeyUp, Invalid connection or incorrect uid: " + Binder - .getCallingUid()); - } - } - } - } - - void sendPointerDown(final IBinder token, final int pointerId, final int x, final int y) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - if (DEBUG_KEY) { - Slog.d(TAG, this + ": sendPointerDown," + - " token=" + token + ", pointerId=" + pointerId); - } - final long idToken = Binder.clearCallingIdentity(); - try { - mProviderMethods.sendPointerDown(TvRemoteProviderProxy.this, token, - pointerId, x, y); - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "sendPointerDown, Invalid connection or incorrect uid: " + Binder - .getCallingUid()); - } - } - } - } - - void sendPointerUp(final IBinder token, final int pointerId) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - if (DEBUG_KEY) { - Slog.d(TAG, this + ": sendPointerUp," + - " token=" + token + ", pointerId=" + pointerId); - } - final long idToken = Binder.clearCallingIdentity(); - try { - mProviderMethods.sendPointerUp(TvRemoteProviderProxy.this, token, - pointerId); - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "sendPointerUp, Invalid connection or incorrect uid: " + Binder - .getCallingUid()); - } - } - } - } - - void sendPointerSync(final IBinder token) { - synchronized (mLock) { - if (mActiveConnection == this && Binder.getCallingUid() == mUid) { - if (DEBUG_KEY) { - Slog.d(TAG, this + ": sendPointerSync," + - " token=" + token); - } - final long idToken = Binder.clearCallingIdentity(); - try { - if (mProviderMethods != null) { - mProviderMethods.sendPointerSync(TvRemoteProviderProxy.this, token); - } - } finally { - Binder.restoreCallingIdentity(idToken); - } - } else { - if (DEBUG) { - Slog.w(TAG, - "sendPointerSync, Invalid connection or incorrect uid: " + Binder - .getCallingUid()); - } - } - } - } - } - - /** - * Receives events from the connected provider. - * <p> - * This inner class is static and only retains a weak reference to the connection - * to prevent the client from being leaked in case the service is holding an - * active reference to the client's callback. - * </p> - */ - private static final class RemoteServiceInputProvider extends ITvRemoteServiceInput.Stub { - private final WeakReference<Connection> mConnectionRef; - - public RemoteServiceInputProvider(Connection connection) { - mConnectionRef = new WeakReference<Connection>(connection); - } - - public void dispose() { - // Terminate the connection. - mConnectionRef.clear(); - } - - @Override - public void openInputBridge(IBinder token, String name, int width, - int height, int maxPointers) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.openInputBridge(token, name, width, height, maxPointers); - } - } - - @Override - public void closeInputBridge(IBinder token) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.closeInputBridge(token); - } - } - - @Override - public void clearInputBridge(IBinder token) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.clearInputBridge(token); - } - } - - @Override - public void sendTimestamp(IBinder token, long timestamp) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.sendTimestamp(token, timestamp); - } - } - - @Override - public void sendKeyDown(IBinder token, int keyCode) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.sendKeyDown(token, keyCode); - } - } - - @Override - public void sendKeyUp(IBinder token, int keyCode) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.sendKeyUp(token, keyCode); - } - } - - @Override - public void sendPointerDown(IBinder token, int pointerId, int x, int y) - throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.sendPointerDown(token, pointerId, x, y); - } - } - - @Override - public void sendPointerUp(IBinder token, int pointerId) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.sendPointerUp(token, pointerId); - } - } + @Override + public void onServiceDisconnected(ComponentName name) { + mConnected = false; - @Override - public void sendPointerSync(IBinder token) throws RemoteException { - Connection connection = mConnectionRef.get(); - if (connection != null) { - connection.sendPointerSync(token); - } + if (DEBUG) { + Slog.d(TAG, this + ": onServiceDisconnected()"); } } } diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java index 0d29edd02663..cddcabe80f33 100644 --- a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java +++ b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java @@ -41,27 +41,27 @@ import java.util.Collections; */ final class TvRemoteProviderWatcher { - private static final String TAG = "TvRemoteProvWatcher"; // max. 23 chars + private static final String TAG = "TvRemoteProviderWatcher"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE); private final Context mContext; - private final TvRemoteProviderProxy.ProviderMethods mProvider; private final Handler mHandler; private final PackageManager mPackageManager; private final ArrayList<TvRemoteProviderProxy> mProviderProxies = new ArrayList<>(); private final int mUserId; private final String mUnbundledServicePackage; + private final Object mLock; private boolean mRunning; - TvRemoteProviderWatcher(Context context, TvRemoteProviderProxy.ProviderMethods provider) { + TvRemoteProviderWatcher(Context context, Object lock) { mContext = context; - mProvider = provider; mHandler = new Handler(true); mUserId = UserHandle.myUserId(); mPackageManager = context.getPackageManager(); mUnbundledServicePackage = context.getString( com.android.internal.R.string.config_tvRemoteServicePackage); + mLock = lock; } public void start() { @@ -116,7 +116,7 @@ final class TvRemoteProviderWatcher { int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name); if (sourceIndex < 0) { TvRemoteProviderProxy providerProxy = - new TvRemoteProviderProxy(mContext, mProvider, + new TvRemoteProviderProxy(mContext, mLock, new ComponentName(serviceInfo.packageName, serviceInfo.name), mUserId, serviceInfo.applicationInfo.uid); providerProxy.start(); diff --git a/services/core/java/com/android/server/tv/TvRemoteService.java b/services/core/java/com/android/server/tv/TvRemoteService.java index bee6fb34a899..58946456b940 100644 --- a/services/core/java/com/android/server/tv/TvRemoteService.java +++ b/services/core/java/com/android/server/tv/TvRemoteService.java @@ -17,17 +17,11 @@ package com.android.server.tv; import android.content.Context; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.ArrayMap; import android.util.Slog; import com.android.server.SystemService; import com.android.server.Watchdog; -import java.io.IOException; -import java.util.Map; - /** * TvRemoteService represents a system service that allows a connected * remote control (emote) service to inject white-listed input events @@ -38,27 +32,17 @@ import java.util.Map; public class TvRemoteService extends SystemService implements Watchdog.Monitor { private static final String TAG = "TvRemoteService"; private static final boolean DEBUG = false; - private static final boolean DEBUG_KEYS = false; - - private final TvRemoteProviderWatcher mWatcher; - private Map<IBinder, UinputBridge> mBridgeMap = new ArrayMap(); /** - * State guarded by mLock. - * This is the second lock in sequence for an incoming call. - * The first lock is always {@link TvRemoteProviderProxy#mLock} - * - * There are currently no methods that break this sequence. - * Special note: - * Outgoing call informInputBridgeConnected(), which is called from - * openInputBridgeInternalLocked() uses a handler thereby relinquishing held locks. + * All actions on input bridges are serialized using mLock. + * This is necessary because {@link UInputBridge} is not thread-safe. */ private final Object mLock = new Object(); + private final TvRemoteProviderWatcher mWatcher; public TvRemoteService(Context context) { super(context); - mWatcher = new TvRemoteProviderWatcher(context, - new UserProvider(TvRemoteService.this)); + mWatcher = new TvRemoteProviderWatcher(context, mLock); Watchdog.getInstance().addMonitor(this); } @@ -81,214 +65,4 @@ public class TvRemoteService extends SystemService implements Watchdog.Monitor { mWatcher.start(); // Also schedules the start of all providers. } } - - private boolean openInputBridgeInternalLocked(final IBinder token, - String name, int width, int height, - int maxPointers) { - if (DEBUG) { - Slog.d(TAG, "openInputBridgeInternalLocked(), token: " + token + ", name: " + name + - ", width: " + width + ", height: " + height + ", maxPointers: " + maxPointers); - } - - try { - //Create a new bridge, if one does not exist already - if (mBridgeMap.containsKey(token)) { - if (DEBUG) Slog.d(TAG, "RemoteBridge already exists"); - return true; - } - - UinputBridge inputBridge = new UinputBridge(token, name, width, height, maxPointers); - mBridgeMap.put(token, inputBridge); - - try { - token.linkToDeath(new IBinder.DeathRecipient() { - @Override - public void binderDied() { - synchronized (mLock) { - closeInputBridgeInternalLocked(token); - } - } - }, 0); - } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Token is already dead"); - closeInputBridgeInternalLocked(token); - return false; - } - } catch (IOException ioe) { - Slog.e(TAG, "Cannot create device for " + name); - return false; - } - return true; - } - - private void closeInputBridgeInternalLocked(IBinder token) { - if (DEBUG) { - Slog.d(TAG, "closeInputBridgeInternalLocked(), token: " + token); - } - - // Close an existing RemoteBridge - UinputBridge inputBridge = mBridgeMap.get(token); - if (inputBridge != null) { - inputBridge.close(token); - } - - mBridgeMap.remove(token); - } - - private void clearInputBridgeInternalLocked(IBinder token) { - if (DEBUG) { - Slog.d(TAG, "clearInputBridgeInternalLocked(), token: " + token); - } - - UinputBridge inputBridge = mBridgeMap.get(token); - if (inputBridge != null) { - inputBridge.clear(token); - } - } - - private void sendKeyDownInternalLocked(IBinder token, int keyCode) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendKeyDownInternalLocked(), token: " + token + ", keyCode: " + keyCode); - } - - UinputBridge inputBridge = mBridgeMap.get(token); - if (inputBridge != null) { - inputBridge.sendKeyDown(token, keyCode); - } - } - - private void sendKeyUpInternalLocked(IBinder token, int keyCode) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendKeyUpInternalLocked(), token: " + token + ", keyCode: " + keyCode); - } - - UinputBridge inputBridge = mBridgeMap.get(token); - if (inputBridge != null) { - inputBridge.sendKeyUp(token, keyCode); - } - } - - private void sendPointerDownInternalLocked(IBinder token, int pointerId, int x, int y) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendPointerDownInternalLocked(), token: " + token + ", pointerId: " + - pointerId + ", x: " + x + ", y: " + y); - } - - UinputBridge inputBridge = mBridgeMap.get(token); - if (inputBridge != null) { - inputBridge.sendPointerDown(token, pointerId, x, y); - } - } - - private void sendPointerUpInternalLocked(IBinder token, int pointerId) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendPointerUpInternalLocked(), token: " + token + ", pointerId: " + - pointerId); - } - - UinputBridge inputBridge = mBridgeMap.get(token); - if (inputBridge != null) { - inputBridge.sendPointerUp(token, pointerId); - } - } - - private void sendPointerSyncInternalLocked(IBinder token) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendPointerSyncInternalLocked(), token: " + token); - } - - UinputBridge inputBridge = mBridgeMap.get(token); - if (inputBridge != null) { - inputBridge.sendPointerSync(token); - } - } - - private final class UserProvider implements TvRemoteProviderProxy.ProviderMethods { - - private final TvRemoteService mService; - - public UserProvider(TvRemoteService service) { - mService = service; - } - - @Override - public boolean openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name, - int width, int height, int maxPointers) { - if (DEBUG) { - Slog.d(TAG, "openInputBridge(), token: " + token + - ", name: " + name + ", width: " + width + - ", height: " + height + ", maxPointers: " + maxPointers); - } - - synchronized (mLock) { - return mService.openInputBridgeInternalLocked(token, name, width, - height, maxPointers); - } - } - - @Override - public void closeInputBridge(TvRemoteProviderProxy provider, IBinder token) { - if (DEBUG) Slog.d(TAG, "closeInputBridge(), token: " + token); - synchronized (mLock) { - mService.closeInputBridgeInternalLocked(token); - } - } - - @Override - public void clearInputBridge(TvRemoteProviderProxy provider, IBinder token) { - if (DEBUG) Slog.d(TAG, "clearInputBridge(), token: " + token); - synchronized (mLock) { - mService.clearInputBridgeInternalLocked(token); - } - } - - @Override - public void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendKeyDown(), token: " + token + ", keyCode: " + keyCode); - } - synchronized (mLock) { - mService.sendKeyDownInternalLocked(token, keyCode); - } - } - - @Override - public void sendKeyUp(TvRemoteProviderProxy provider, IBinder token, int keyCode) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendKeyUp(), token: " + token + ", keyCode: " + keyCode); - } - synchronized (mLock) { - mService.sendKeyUpInternalLocked(token, keyCode); - } - } - - @Override - public void sendPointerDown(TvRemoteProviderProxy provider, IBinder token, int pointerId, - int x, int y) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendPointerDown(), token: " + token + ", pointerId: " + pointerId); - } - synchronized (mLock) { - mService.sendPointerDownInternalLocked(token, pointerId, x, y); - } - } - - @Override - public void sendPointerUp(TvRemoteProviderProxy provider, IBinder token, int pointerId) { - if (DEBUG_KEYS) { - Slog.d(TAG, "sendPointerUp(), token: " + token + ", pointerId: " + pointerId); - } - synchronized (mLock) { - mService.sendPointerUpInternalLocked(token, pointerId); - } - } - - @Override - public void sendPointerSync(TvRemoteProviderProxy provider, IBinder token) { - if (DEBUG_KEYS) Slog.d(TAG, "sendPointerSync(), token: " + token); - synchronized (mLock) { - mService.sendPointerSyncInternalLocked(token); - } - } - } } diff --git a/services/core/java/com/android/server/tv/TvRemoteServiceInput.java b/services/core/java/com/android/server/tv/TvRemoteServiceInput.java new file mode 100644 index 000000000000..8fe6da5e8dbe --- /dev/null +++ b/services/core/java/com/android/server/tv/TvRemoteServiceInput.java @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2019 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 com.android.server.tv; + +import android.media.tv.ITvRemoteProvider; +import android.media.tv.ITvRemoteServiceInput; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.ArrayMap; +import android.util.Slog; + +import java.io.IOException; +import java.util.Map; + +final class TvRemoteServiceInput extends ITvRemoteServiceInput.Stub { + private static final String TAG = "TvRemoteServiceInput"; + private static final boolean DEBUG = false; + private static final boolean DEBUG_KEYS = false; + + private final Map<IBinder, UinputBridge> mBridgeMap; + private final Object mLock; + private final ITvRemoteProvider mProvider; + + TvRemoteServiceInput(Object lock, ITvRemoteProvider provider) { + mBridgeMap = new ArrayMap(); + mLock = lock; + mProvider = provider; + } + + @Override + public void openInputBridge(IBinder token, String name, int width, + int height, int maxPointers) { + if (DEBUG) { + Slog.d(TAG, "openInputBridge(), token: " + token + + ", name: " + name + ", width: " + width + + ", height: " + height + ", maxPointers: " + maxPointers); + } + + synchronized (mLock) { + if (mBridgeMap.containsKey(token)) { + if (DEBUG) { + Slog.d(TAG, "InputBridge already exists"); + } + } else { + final long idToken = Binder.clearCallingIdentity(); + try { + mBridgeMap.put(token, + new UinputBridge(token, name, width, height, maxPointers)); + token.linkToDeath(new IBinder.DeathRecipient() { + @Override + public void binderDied() { + closeInputBridge(token); + } + }, 0); + } catch (IOException e) { + Slog.e(TAG, "Cannot create device for " + name); + return; + } catch (RemoteException e) { + Slog.e(TAG, "Token is already dead"); + closeInputBridge(token); + return; + } finally { + Binder.restoreCallingIdentity(idToken); + } + } + } + + try { + mProvider.onInputBridgeConnected(token); + } catch (RemoteException e) { + Slog.e(TAG, "Failed remote call to onInputBridgeConnected"); + } + } + + @Override + public void closeInputBridge(IBinder token) { + if (DEBUG) { + Slog.d(TAG, "closeInputBridge(), token: " + token); + } + + synchronized (mLock) { + UinputBridge inputBridge = mBridgeMap.remove(token); + if (inputBridge == null) { + return; + } + + final long idToken = Binder.clearCallingIdentity(); + try { + inputBridge.close(token); + } finally { + Binder.restoreCallingIdentity(idToken); + } + } + } + + @Override + public void clearInputBridge(IBinder token) { + if (DEBUG) { + Slog.d(TAG, "clearInputBridge, token: " + token); + } + + synchronized (mLock) { + UinputBridge inputBridge = mBridgeMap.get(token); + if (inputBridge == null) { + return; + } + + final long idToken = Binder.clearCallingIdentity(); + try { + inputBridge.clear(token); + } finally { + Binder.restoreCallingIdentity(idToken); + } + } + } + + @Override + public void sendTimestamp(IBinder token, long timestamp) { + if (DEBUG) { + Slog.e(TAG, "sendTimestamp is deprecated, please remove all usages of this API."); + } + } + + @Override + public void sendKeyDown(IBinder token, int keyCode) { + if (DEBUG_KEYS) { + Slog.d(TAG, "sendKeyDown(), token: " + token + ", keyCode: " + keyCode); + } + + synchronized (mLock) { + UinputBridge inputBridge = mBridgeMap.get(token); + if (inputBridge == null) { + return; + } + + final long idToken = Binder.clearCallingIdentity(); + try { + inputBridge.sendKeyDown(token, keyCode); + } finally { + Binder.restoreCallingIdentity(idToken); + } + } + } + + @Override + public void sendKeyUp(IBinder token, int keyCode) { + if (DEBUG_KEYS) { + Slog.d(TAG, "sendKeyUp(), token: " + token + ", keyCode: " + keyCode); + } + + synchronized (mLock) { + UinputBridge inputBridge = mBridgeMap.get(token); + if (inputBridge == null) { + return; + } + + final long idToken = Binder.clearCallingIdentity(); + try { + inputBridge.sendKeyUp(token, keyCode); + } finally { + Binder.restoreCallingIdentity(idToken); + } + } + } + + @Override + public void sendPointerDown(IBinder token, int pointerId, int x, int y) { + if (DEBUG_KEYS) { + Slog.d(TAG, "sendPointerDown(), token: " + token + ", pointerId: " + + pointerId + ", x: " + x + ", y: " + y); + } + + synchronized (mLock) { + UinputBridge inputBridge = mBridgeMap.get(token); + if (inputBridge == null) { + return; + } + + final long idToken = Binder.clearCallingIdentity(); + try { + inputBridge.sendPointerDown(token, pointerId, x, y); + } finally { + Binder.restoreCallingIdentity(idToken); + } + } + } + + @Override + public void sendPointerUp(IBinder token, int pointerId) { + if (DEBUG_KEYS) { + Slog.d(TAG, "sendPointerUp(), token: " + token + ", pointerId: " + pointerId); + } + + synchronized (mLock) { + UinputBridge inputBridge = mBridgeMap.get(token); + if (inputBridge == null) { + return; + } + + final long idToken = Binder.clearCallingIdentity(); + try { + inputBridge.sendPointerUp(token, pointerId); + } finally { + Binder.restoreCallingIdentity(idToken); + } + } + } + + @Override + public void sendPointerSync(IBinder token) { + if (DEBUG_KEYS) { + Slog.d(TAG, "sendPointerSync(), token: " + token); + } + + synchronized (mLock) { + UinputBridge inputBridge = mBridgeMap.get(token); + if (inputBridge == null) { + return; + } + + final long idToken = Binder.clearCallingIdentity(); + try { + inputBridge.sendPointerSync(token); + } finally { + Binder.restoreCallingIdentity(idToken); + } + } + } +} diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index dbf06a580282..54bb5f7bcd5f 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1743,7 +1743,12 @@ class ActivityStarter { return START_SUCCESS; } - if (!mMovedToFront && mDoResume) { + if (mMovedToFront) { + // We moved the task to front, use starting window to hide initial drawn delay. + targetTaskTop.showStartingWindow(null /* prev */, false /* newTask */, + true /* taskSwitch */); + } else if (mDoResume) { + // Make sure the stack and its belonging display are moved to topmost. mTargetStack.moveToFront("intentActivityFound"); } // We didn't do anything... but it was needed (a.k.a., client don't use that intent!) @@ -2349,11 +2354,6 @@ class ActivityStarter { } mOptions = null; - - // We are moving a task to the front, use starting window to hide initial drawn - // delay. - intentActivity.showStartingWindow(null /* prev */, false /* newTask */, - true /* taskSwitch */); } } // Need to update mTargetStack because if task was moved out of it, the original stack may diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index f8f6334b04dc..d5f403f85621 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -113,7 +113,7 @@ class DragDropController { final WindowState callingWin = mService.windowForClientLocked( null, window, false); - if (callingWin == null) { + if (callingWin == null || callingWin.cantReceiveTouchInput()) { Slog.w(TAG_WM, "Bad requesting window " + window); return null; // !!! TODO: throw here? } @@ -167,8 +167,7 @@ class DragDropController { final SurfaceControl surfaceControl = mDragState.mSurfaceControl; if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag"); - final SurfaceControl.Transaction transaction = - callingWin.getPendingTransaction(); + final SurfaceControl.Transaction transaction = mDragState.mTransaction; transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha); transaction.setPosition( surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY); diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 17daabfe3e79..3c616945f762 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -120,7 +120,7 @@ class DragState { // A surface used to catch input events for the drag-and-drop operation. SurfaceControl mInputSurface; - private final SurfaceControl.Transaction mTransaction; + final SurfaceControl.Transaction mTransaction; private final Rect mTmpClipRect = new Rect(); @@ -129,7 +129,6 @@ class DragState { * {@code true} when {@link #closeLocked()} is called. */ private boolean mIsClosing; - IBinder mTransferTouchFromToken; DragState(WindowManagerService service, DragDropController controller, IBinder token, SurfaceControl surface, int flags, IBinder localWin) { @@ -167,12 +166,11 @@ class DragState { mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y); mTransaction.setWindowCrop(mInputSurface, mTmpClipRect); - mTransaction.transferTouchFocus(mTransferTouchFromToken, h.token); - mTransferTouchFromToken = null; - // syncInputWindows here to ensure the input channel isn't removed before the transfer. + // syncInputWindows here to ensure the input window info is sent before the + // transferTouchFocus is called. mTransaction.syncInputWindows(); - mTransaction.apply(); + mTransaction.apply(true); } /** diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 42866f97b4b8..fc8a27d64fce 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -50,6 +50,7 @@ import android.view.InputDevice; import android.view.InputEvent; import android.view.InputWindowHandle; import android.view.MotionEvent; +import android.view.SurfaceControl; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; @@ -302,7 +303,8 @@ class TaskPositioner implements IBinder.DeathRecipient { mDisplayContent.getDisplayRotation().pause(); // Notify InputMonitor to take mDragWindowHandle. - mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/); + mDisplayContent.getInputMonitor().updateInputWindowsImmediately(); + new SurfaceControl.Transaction().syncInputWindows().apply(true); mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics); mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics); diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index 2441954012e5..56b3bba2a431 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -24,7 +24,6 @@ import android.app.IActivityTaskManager; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; -import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Slog; @@ -51,7 +50,6 @@ class TaskPositioningController { private @Nullable TaskPositioner mTaskPositioner; private final Rect mTmpClipRect = new Rect(); - private IBinder mTransferTouchFromToken; boolean isPositioningLocked() { return mTaskPositioner != null; @@ -104,8 +102,6 @@ class TaskPositioningController { mTmpClipRect.set(0, 0, p.x, p.y); t.setWindowCrop(mInputSurface, mTmpClipRect); - t.transferTouchFocus(mTransferTouchFromToken, h.token); - mTransferTouchFromToken = null; } boolean startMovingTask(IWindow window, float startX, float startY) { @@ -168,6 +164,7 @@ class TaskPositioningController { mPositioningDisplay = displayContent; mTaskPositioner = TaskPositioner.create(mService); + mTaskPositioner.register(displayContent); // We need to grab the touch focus so that the touch events during the // resizing/scrolling are not sent to the app. 'win' is the main window @@ -178,8 +175,12 @@ class TaskPositioningController { && displayContent.mCurrentFocus.mAppToken == win.mAppToken) { transferFocusFromWin = displayContent.mCurrentFocus; } - mTransferTouchFromToken = transferFocusFromWin.mInputChannel.getToken(); - mTaskPositioner.register(displayContent); + if (!mInputManager.transferTouchFocus( + transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) { + Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus"); + cleanUpTaskPositioner(); + return false; + } mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY); return true; diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java index d36ebf01bcc1..f291573f854a 100644 --- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java +++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java @@ -38,8 +38,8 @@ class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable { private int mWidth; private int mHeight; - TaskScreenshotAnimatable(Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory, Task task, - SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer) { + TaskScreenshotAnimatable(Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory, + Task task, SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer) { GraphicBuffer buffer = screenshotBuffer == null ? null : screenshotBuffer.getGraphicBuffer(); mTask = task; @@ -58,6 +58,8 @@ class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable { surface.copyFrom(mSurfaceControl); surface.attachAndQueueBufferWithColorSpace(buffer, screenshotBuffer.getColorSpace()); surface.release(); + final float scale = 1.0f * mTask.getBounds().width() / mWidth; + mSurfaceControl.setMatrix(scale, 0, 0, scale); } getPendingTransaction().show(mSurfaceControl); } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index aa2a96497b99..abbd1abff614 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -161,9 +161,8 @@ public abstract class WindowManagerInternal { default boolean registerInputChannel( DragState state, Display display, InputManagerService service, InputChannel source) { - state.mTransferTouchFromToken = source.getToken(); state.register(display); - return true; + return service.transferTouchFocus(source, state.getInputChannel()); } /** diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index d5fbd2b316e7..7aa9c7cce876 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -56,37 +56,57 @@ inline Return<R> NullptrStatus() { return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)}; } -// Helper used to transparently deal with the vibrator HAL becoming unavailable. -template<class R, class I, class... Args0, class... Args1> -Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) { - // Assume that if getService returns a nullptr, HAL is not available on the - // device. - static sp<I> sHal = I::getService(); - static bool sAvailable = sHal != nullptr; +template <typename I> +class HalWrapper { + public: + static std::unique_ptr<HalWrapper> Create() { + // Assume that if getService returns a nullptr, HAL is not available on the + // device. + auto hal = I::getService(); + return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; + } - if (!sAvailable) { - return NullptrStatus<R>(); + // Helper used to transparently deal with the vibrator HAL becoming unavailable. + template<class R, class... Args0, class... Args1> + Return<R> call(Return<R> (I::* fn)(Args0...), Args1&&... args1) { + // Return<R> doesn't have a default constructor, so make a Return<R> with + // STATUS::EX_NONE. + using ::android::hardware::Status; + Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)}; + + // Note that ret is guaranteed to be changed after this loop. + for (int i = 0; i < NUM_TRIES; ++i) { + ret = (mHal == nullptr) ? NullptrStatus<R>() + : (*mHal.*fn)(std::forward<Args1>(args1)...); + + if (ret.isOk()) { + break; + } + + ALOGE("Failed to issue command to vibrator HAL. Retrying."); + // Restoring connection to the HAL. + mHal = I::tryGetService(); + } + return ret; } - // Return<R> doesn't have a default constructor, so make a Return<R> with - // STATUS::EX_NONE. - using ::android::hardware::Status; - Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)}; + private: + HalWrapper(sp<I> &&hal) : mHal(std::move(hal)) {} - // Note that ret is guaranteed to be changed after this loop. - for (int i = 0; i < NUM_TRIES; ++i) { - ret = (sHal == nullptr) ? NullptrStatus<R>() - : (*sHal.*fn)(std::forward<Args1>(args1)...); + private: + sp<I> mHal; +}; - if (ret.isOk()) { - break; - } +template <typename I> +static auto getHal() { + static auto sHalWrapper = HalWrapper<I>::Create(); + return sHalWrapper.get(); +} - ALOGE("Failed to issue command to vibrator HAL. Retrying."); - // Restoring connection to the HAL. - sHal = I::tryGetService(); - } - return ret; +template<class R, class I, class... Args0, class... Args1> +Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) { + auto hal = getHal<I>(); + return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); } template<class R> diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 03f475582a5a..fb2fdab19a54 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -159,12 +159,7 @@ static void loadSystemIconAsSpriteWithPointerIcon(JNIEnv* env, jobject contextOb status_t status = android_view_PointerIcon_loadSystemIcon(env, contextObj, style, outPointerIcon); if (!status) { - SkBitmap* bitmapCopy = &outSpriteIcon->bitmap; - SkImageInfo bitmapCopyInfo = outPointerIcon->bitmap.info().makeColorType(kN32_SkColorType); - if (bitmapCopy->tryAllocPixels(bitmapCopyInfo)) { - outPointerIcon->bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(), - bitmapCopy->rowBytes(), 0, 0); - } + outSpriteIcon->bitmap = outPointerIcon->bitmap.copy(ANDROID_BITMAP_FORMAT_RGBA_8888); outSpriteIcon->style = outPointerIcon->style; outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX; outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY; @@ -1575,6 +1570,27 @@ static void nativeSetSystemUiVisibility(JNIEnv* /* env */, im->setSystemUiVisibility(visibility); } +static jboolean nativeTransferTouchFocus(JNIEnv* env, + jclass /* clazz */, jlong ptr, jobject fromChannelObj, jobject toChannelObj) { + NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); + + sp<InputChannel> fromChannel = + android_view_InputChannel_getInputChannel(env, fromChannelObj); + sp<InputChannel> toChannel = + android_view_InputChannel_getInputChannel(env, toChannelObj); + + if (fromChannel == nullptr || toChannel == nullptr) { + return JNI_FALSE; + } + + if (im->getInputManager()->getDispatcher()-> + transferTouchFocus(fromChannel->getToken(), toChannel->getToken())) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } +} + static void nativeSetPointerSpeed(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jint speed) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); @@ -1709,15 +1725,8 @@ static void nativeSetCustomPointerIcon(JNIEnv* env, jclass /* clazz */, return; } - SpriteIcon spriteIcon; - SkImageInfo spriteInfo = pointerIcon.bitmap.info().makeColorType(kN32_SkColorType); - if (spriteIcon.bitmap.tryAllocPixels(spriteInfo)) { - pointerIcon.bitmap.readPixels(spriteInfo, spriteIcon.bitmap.getPixels(), - spriteIcon.bitmap.rowBytes(), 0, 0); - } - spriteIcon.style = pointerIcon.style; - spriteIcon.hotSpotX = pointerIcon.hotSpotX; - spriteIcon.hotSpotY = pointerIcon.hotSpotY; + SpriteIcon spriteIcon(pointerIcon.bitmap.copy(ANDROID_BITMAP_FORMAT_RGBA_8888), + pointerIcon.style, pointerIcon.hotSpotX, pointerIcon.hotSpotY); im->setCustomPointerIcon(spriteIcon); } @@ -1775,6 +1784,8 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*) nativeSetInputDispatchMode }, { "nativeSetSystemUiVisibility", "(JI)V", (void*) nativeSetSystemUiVisibility }, + { "nativeTransferTouchFocus", "(JLandroid/view/InputChannel;Landroid/view/InputChannel;)Z", + (void*) nativeTransferTouchFocus }, { "nativeSetPointerSpeed", "(JI)V", (void*) nativeSetPointerSpeed }, { "nativeSetShowTouches", "(JZ)V", diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 479dd1e5d84e..c3ff28530b7f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -126,6 +126,7 @@ import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager.PasswordComplexity; import android.app.admin.DevicePolicyManagerInternal; +import android.app.admin.DeviceStateCache; import android.app.admin.NetworkEvent; import android.app.admin.PasswordMetrics; import android.app.admin.SecurityLog; @@ -507,6 +508,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private final OverlayPackagesProvider mOverlayPackagesProvider; private final DevicePolicyCacheImpl mPolicyCache = new DevicePolicyCacheImpl(); + private final DeviceStateCacheImpl mStateCache = new DeviceStateCacheImpl(); /** * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p @@ -2295,6 +2297,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { policy = new DevicePolicyData(userHandle); mUserData.append(userHandle, policy); loadSettingsLocked(policy, userHandle); + if (userHandle == UserHandle.USER_SYSTEM) { + mStateCache.setDeviceProvisioned(policy.mUserSetupComplete); + } } return policy; } @@ -8958,6 +8963,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus())); pw.println(); mPolicyCache.dump(pw); + pw.println(); + mStateCache.dump(pw); } } @@ -11169,6 +11176,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DevicePolicyData policy = getUserData(userHandle); if (!policy.mUserSetupComplete) { policy.mUserSetupComplete = true; + if (userHandle == UserHandle.USER_SYSTEM) { + mStateCache.setDeviceProvisioned(true); + } synchronized (getLockObject()) { saveSettingsLocked(userHandle); } @@ -11481,6 +11491,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { protected DevicePolicyCache getDevicePolicyCache() { return mPolicyCache; } + + @Override + protected DeviceStateCache getDeviceStateCache() { + return mStateCache; + } + } private Intent createShowAdminSupportIntent(ComponentName admin, int userId) { @@ -13021,6 +13037,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0; DevicePolicyData policy = getUserData(userId); policy.mUserSetupComplete = isUserCompleted; + mStateCache.setDeviceProvisioned(isUserCompleted); synchronized (getLockObject()) { saveSettingsLocked(userId); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java new file mode 100644 index 000000000000..c3cb9b035ed2 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 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 com.android.server.devicepolicy; + +import android.app.admin.DeviceStateCache; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; + +/** + * Implementation of {@link DeviceStateCache}, to which {@link DevicePolicyManagerService} pushes + * device state. + * + */ +public class DeviceStateCacheImpl extends DeviceStateCache { + /** + * Lock object. For simplicity we just always use this as the lock. We could use each object + * as a lock object to make it more fine-grained, but that'd make copy-paste error-prone. + */ + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private boolean mIsDeviceProvisioned = false; + + @Override + public boolean isDeviceProvisioned() { + return mIsDeviceProvisioned; + } + + /** Update the device provisioned flag for USER_SYSTEM */ + public void setDeviceProvisioned(boolean provisioned) { + synchronized (mLock) { + mIsDeviceProvisioned = provisioned; + } + } + + /** Dump content */ + public void dump(IndentingPrintWriter pw) { + pw.println("Device state cache:"); + pw.increaseIndent(); + pw.println("Device provisioned: " + mIsDeviceProvisioned); + pw.decreaseIndent(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java index 9e3b54d1ca96..c3a1243f75af 100644 --- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java +++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java @@ -16,10 +16,8 @@ package com.android.server.am; -import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE; -import static com.android.server.am.MemoryStatUtil.JIFFY_NANOS; import static com.android.server.am.MemoryStatUtil.MemoryStat; -import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs; +import static com.android.server.am.MemoryStatUtil.PAGE_SIZE; import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg; import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs; @@ -30,7 +28,6 @@ import androidx.test.filters.SmallTest; import org.junit.Test; -import java.io.ByteArrayOutputStream; import java.util.Collections; /** @@ -99,7 +96,7 @@ public class MemoryStatUtilTest { "0", "2222", // this in start time (in ticks per second) "1257177088", - "3", + "3", // this is RSS in pages "4294967295", "2936971264", "2936991289", @@ -129,53 +126,6 @@ public class MemoryStatUtilTest { "3198889956", "0"); - private static final String PROC_STATUS_CONTENTS = "Name:\tandroid.youtube\n" - + "State:\tS (sleeping)\n" - + "Tgid:\t12088\n" - + "Pid:\t12088\n" - + "PPid:\t723\n" - + "TracerPid:\t0\n" - + "Uid:\t10083\t10083\t10083\t10083\n" - + "Gid:\t10083\t10083\t10083\t10083\n" - + "Ngid:\t0\n" - + "FDSize:\t128\n" - + "Groups:\t3003 9997 20083 50083 \n" - + "VmPeak:\t 4546844 kB\n" - + "VmSize:\t 4542636 kB\n" - + "VmLck:\t 0 kB\n" - + "VmPin:\t 0 kB\n" - + "VmHWM:\t 137668 kB\n" // RSS high-water mark - + "VmRSS:\t 126776 kB\n" // RSS - + "RssAnon:\t 37860 kB\n" - + "RssFile:\t 88764 kB\n" - + "RssShmem:\t 152 kB\n" - + "VmData:\t 4125112 kB\n" - + "VmStk:\t 8192 kB\n" - + "VmExe:\t 24 kB\n" - + "VmLib:\t 102432 kB\n" - + "VmPTE:\t 1300 kB\n" - + "VmPMD:\t 36 kB\n" - + "VmSwap:\t 22 kB\n" // Swap - + "Threads:\t95\n" - + "SigQ:\t0/13641\n" - + "SigPnd:\t0000000000000000\n" - + "ShdPnd:\t0000000000000000\n" - + "SigBlk:\t0000000000001204\n" - + "SigIgn:\t0000000000000001\n" - + "SigCgt:\t00000006400084f8\n" - + "CapInh:\t0000000000000000\n" - + "CapPrm:\t0000000000000000\n" - + "CapEff:\t0000000000000000\n" - + "CapBnd:\t0000000000000000\n" - + "CapAmb:\t0000000000000000\n" - + "Seccomp:\t2\n" - + "Cpus_allowed:\tff\n" - + "Cpus_allowed_list:\t0-7\n" - + "Mems_allowed:\t1\n" - + "Mems_allowed_list:\t0\n" - + "voluntary_ctxt_switches:\t903\n" - + "nonvoluntary_ctxt_switches:\t104\n"; - @Test public void testParseMemoryStatFromMemcg_parsesCorrectValues() { MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS); @@ -197,71 +147,26 @@ public class MemoryStatUtilTest { @Test public void testParseMemoryStatFromProcfs_parsesCorrectValues() { - MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, PROC_STATUS_CONTENTS); + MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS); assertEquals(1, stat.pgfault); assertEquals(2, stat.pgmajfault); - assertEquals(126776 * BYTES_IN_KILOBYTE, stat.rssInBytes); + assertEquals(3 * PAGE_SIZE, stat.rssInBytes); assertEquals(0, stat.cacheInBytes); - assertEquals(22 * BYTES_IN_KILOBYTE, stat.swapInBytes); - assertEquals(2222 * JIFFY_NANOS, stat.startTimeNanos); - assertEquals(37860 * BYTES_IN_KILOBYTE, stat.anonRssInBytes); + assertEquals(0, stat.swapInBytes); } @Test public void testParseMemoryStatFromProcfs_emptyContents() { - MemoryStat stat = parseMemoryStatFromProcfs("", PROC_STATUS_CONTENTS); - assertNull(stat); - - stat = parseMemoryStatFromProcfs(null, PROC_STATUS_CONTENTS); + MemoryStat stat = parseMemoryStatFromProcfs(""); assertNull(stat); - stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, ""); - assertNull(stat); - - stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, null); + stat = parseMemoryStatFromProcfs(null); assertNull(stat); } @Test public void testParseMemoryStatFromProcfs_invalidValue() { String contents = String.join(" ", Collections.nCopies(24, "memory")); - assertNull(parseMemoryStatFromProcfs(contents, PROC_STATUS_CONTENTS)); - } - - @Test - public void testParseCmdlineFromProcfs_invalidValue() { - byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test - - assertEquals("", parseCmdlineFromProcfs(bytesToString(nothing))); - } - - @Test - public void testParseCmdlineFromProcfs_correctValue_noNullBytes() { - assertEquals("com.google.app", parseCmdlineFromProcfs("com.google.app")); - } - - @Test - public void testParseCmdlineFromProcfs_correctValue_withNullBytes() { - byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0 - - assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing))); - - // test\0\0test - byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74}; - - assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing))); - } - - @Test - public void testParseCmdlineFromProcfs_emptyContents() { - assertEquals("", parseCmdlineFromProcfs("")); - - assertEquals("", parseCmdlineFromProcfs(null)); - } - - private static String bytesToString(byte[] bytes) { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - output.write(bytes, 0, bytes.length); - return output.toString(); + assertNull(parseMemoryStatFromProcfs(contents)); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index 1f5ebe4536d8..7cece1f5cecc 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -29,6 +29,7 @@ import android.app.KeyguardManager; import android.app.NotificationManager; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; +import android.app.admin.DeviceStateCache; import android.app.trust.TrustManager; import android.content.ComponentName; import android.content.pm.UserInfo; @@ -37,6 +38,7 @@ import android.os.FileUtils; import android.os.IProgressListener; import android.os.RemoteException; import android.os.UserManager; +import android.os.UserManagerInternal; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.security.KeyStore; @@ -91,6 +93,8 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { FakeGsiService mGsiService; PasswordSlotManagerTestable mPasswordSlotManager; RecoverableKeyStoreManager mRecoverableKeyStoreManager; + UserManagerInternal mUserManagerInternal; + DeviceStateCache mDeviceStateCache; protected boolean mHasSecureLockScreen; @Override @@ -108,6 +112,8 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { mGsiService = new FakeGsiService(); mPasswordSlotManager = new PasswordSlotManagerTestable(); mRecoverableKeyStoreManager = mock(RecoverableKeyStoreManager.class); + mUserManagerInternal = mock(UserManagerInternal.class); + mDeviceStateCache = mock(DeviceStateCache.class); LocalServices.removeServiceForTest(LockSettingsInternal.class); LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); @@ -144,7 +150,8 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { mAuthSecretService = mock(IAuthSecret.class); mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage, mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager, - mSpManager, mAuthSecretService, mGsiService, mRecoverableKeyStoreManager); + mSpManager, mAuthSecretService, mGsiService, mRecoverableKeyStoreManager, + mUserManagerInternal, mDeviceStateCache); when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO); mPrimaryUserProfiles.add(PRIMARY_USER_INFO); installChildProfile(MANAGED_PROFILE_USER_ID); @@ -172,6 +179,9 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { // Adding a fake Device Owner app which will enable escrow token support in LSS. when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn( new ComponentName("com.dummy.package", ".FakeDeviceOwner")); + when(mUserManagerInternal.isDeviceManaged()).thenReturn(true); + when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true); + mLocalService = LocalServices.getService(LockSettingsInternal.class); } @@ -184,6 +194,7 @@ public abstract class BaseLockSettingsServiceTests extends AndroidTestCase { when(mUserManager.getProfileParent(eq(profileId))).thenReturn(PRIMARY_USER_INFO); when(mUserManager.isUserRunning(eq(profileId))).thenReturn(true); when(mUserManager.isUserUnlocked(eq(profileId))).thenReturn(true); + when(mUserManagerInternal.isUserManaged(eq(profileId))).thenReturn(true); return userInfo; } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 5c67d0422aca..65d6f45b5c6c 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -19,12 +19,14 @@ package com.android.server.locksettings; import static org.mockito.Mockito.mock; import android.app.IActivityManager; +import android.app.admin.DeviceStateCache; import android.content.Context; import android.hardware.authsecret.V1_0.IAuthSecret; import android.os.Handler; import android.os.Looper; import android.os.Process; import android.os.RemoteException; +import android.os.UserManagerInternal; import android.os.storage.IStorageManager; import android.security.KeyStore; import android.security.keystore.KeyPermanentlyInvalidatedException; @@ -44,15 +46,16 @@ public class LockSettingsServiceTestable extends LockSettingsService { private LockPatternUtils mLockPatternUtils; private IStorageManager mStorageManager; private SyntheticPasswordManager mSpManager; - private IAuthSecret mAuthSecretService; private FakeGsiService mGsiService; private RecoverableKeyStoreManager mRecoverableKeyStoreManager; + private UserManagerInternal mUserManagerInternal; + private DeviceStateCache mDeviceStateCache; public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore, IActivityManager activityManager, LockPatternUtils lockPatternUtils, IStorageManager storageManager, SyntheticPasswordManager spManager, - IAuthSecret authSecretService, FakeGsiService gsiService, - RecoverableKeyStoreManager recoverableKeyStoreManager) { + FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager, + UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) { super(context); mLockSettingsStorage = storage; mKeyStore = keyStore; @@ -62,6 +65,8 @@ public class LockSettingsServiceTestable extends LockSettingsService { mSpManager = spManager; mGsiService = gsiService; mRecoverableKeyStoreManager = recoverableKeyStoreManager; + mUserManagerInternal = userManagerInternal; + mDeviceStateCache = deviceStateCache; } @Override @@ -93,6 +98,10 @@ public class LockSettingsServiceTestable extends LockSettingsService { public LockPatternUtils getLockPatternUtils() { return mLockPatternUtils; } + @Override + public DeviceStateCache getDeviceStateCache() { + return mDeviceStateCache; + } @Override public KeyStore getKeyStore() { @@ -110,6 +119,11 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override + public UserManagerInternal getUserManagerInternal() { + return mUserManagerInternal; + } + + @Override public boolean hasEnrolledBiometrics(int userId) { return false; } @@ -134,10 +148,11 @@ public class LockSettingsServiceTestable extends LockSettingsService { LockSettingsStorage storage, FakeGateKeeperService gatekeeper, KeyStore keystore, IStorageManager storageManager, IActivityManager mActivityManager, SyntheticPasswordManager spManager, IAuthSecret authSecretService, - FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager) { + FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager, + UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) { super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils, - storageManager, spManager, authSecretService, gsiService, - recoverableKeyStoreManager)); + storageManager, spManager, gsiService, + recoverableKeyStoreManager, userManagerInternal, deviceStateCache)); mGateKeeperService = gatekeeper; mAuthSecretService = authSecretService; } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 127cf4970725..0776589ea47f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.admin.PasswordMetrics; import android.os.RemoteException; @@ -468,6 +469,18 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); } + public void testEscrowTokenCannotBeActivatedOnUnmanagedUser() { + final byte[] token = "some-high-entropy-secure-token".getBytes(); + when(mUserManagerInternal.isDeviceManaged()).thenReturn(false); + when(mUserManagerInternal.isUserManaged(PRIMARY_USER_ID)).thenReturn(false); + when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true); + + try { + mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); + fail("Escrow token should not be possible on unmanaged device"); + } catch (SecurityException expected) { } + } + public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception { final byte[] password = "password".getBytes(); final byte[] pattern = "123654".getBytes(); diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 819091c378b8..e020945ebefc 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -27,10 +27,13 @@ import static org.mockito.Mockito.when; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsingPackage; import android.os.Build; import android.os.Process; import android.permission.IPermissionManager; @@ -56,45 +59,55 @@ public class AppsFilterTest { @Mock AppsFilter.FeatureConfig mFeatureConfigMock; - private Map<String, PackageParser.Package> mExisting = new ArrayMap<>(); + private Map<String, AndroidPackage> mExisting = new ArrayMap<>(); - private static PackageBuilder pkg(String packageName) { - return new PackageBuilder(packageName) - .setApplicationInfoTargetSdkVersion(Build.VERSION_CODES.R); + private static ParsingPackage pkg(String packageName) { + return PackageImpl.forParsing(packageName) + .setTargetSdkVersion(Build.VERSION_CODES.R); } - private static PackageBuilder pkg(String packageName, Intent... queries) { - return pkg(packageName).setQueriesIntents(queries); + private static ParsingPackage pkg(String packageName, Intent... queries) { + ParsingPackage pkg = pkg(packageName); + if (queries != null) { + for (Intent intent : queries) { + pkg.addQueriesIntent(intent); + } + } + return pkg; } - private static PackageBuilder pkg(String packageName, String... queriesPackages) { - return pkg(packageName).setQueriesPackages(queriesPackages); + private static ParsingPackage pkg(String packageName, String... queriesPackages) { + ParsingPackage pkg = pkg(packageName); + if (queriesPackages != null) { + for (String queryPackageName : queriesPackages) { + pkg.addQueriesPackage(queryPackageName); + } + } + return pkg; } - private static PackageBuilder pkg(String packageName, IntentFilter... filters) { - final PackageBuilder packageBuilder = pkg(packageName).addActivity( - pkg -> new PackageParser.ParseComponentArgs(pkg, new String[1], 0, 0, 0, 0, 0, 0, - new String[]{packageName}, 0, 0, 0), new ActivityInfo()); + private static ParsingPackage pkg(String packageName, IntentFilter... filters) { + ParsedActivity activity = new ParsedActivity(); + activity.setPackageName(packageName); for (IntentFilter filter : filters) { - packageBuilder.addActivityIntentInfo(0 /* index */, activity -> { - final PackageParser.ActivityIntentInfo info = - new PackageParser.ActivityIntentInfo(activity); - if (filter.countActions() > 0) { - filter.actionsIterator().forEachRemaining(info::addAction); - } - if (filter.countCategories() > 0) { - filter.actionsIterator().forEachRemaining(info::addAction); - } - if (filter.countDataAuthorities() > 0) { - filter.authoritiesIterator().forEachRemaining(info::addDataAuthority); - } - if (filter.countDataSchemes() > 0) { - filter.schemesIterator().forEachRemaining(info::addDataScheme); - } - return info; - }); + final ParsedActivityIntentInfo info = new ParsedActivityIntentInfo(packageName, null); + if (filter.countActions() > 0) { + filter.actionsIterator().forEachRemaining(info::addAction); + } + if (filter.countCategories() > 0) { + filter.actionsIterator().forEachRemaining(info::addAction); + } + if (filter.countDataAuthorities() > 0) { + filter.authoritiesIterator().forEachRemaining(info::addDataAuthority); + } + if (filter.countDataSchemes() > 0) { + filter.schemesIterator().forEachRemaining(info::addDataScheme); + } + activity.addIntent(info); } - return packageBuilder; + + return pkg(packageName) + .addActivity(activity); } @Before @@ -106,7 +119,7 @@ public class AppsFilterTest { .checkPermission(anyString(), anyString(), anyInt())) .thenReturn(PackageManager.PERMISSION_DENIED); when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true); - when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class))) + when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(true); } @@ -152,7 +165,7 @@ public class AppsFilterTest { PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package")).build(); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package", - new Intent("TEST_ACTION")).setApplicationInfoTargetSdkVersion( + new Intent("TEST_ACTION")).setTargetSdkVersion( Build.VERSION_CODES.P)).build(); assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); @@ -245,7 +258,7 @@ public class AppsFilterTest { @Test public void testNoQueries_FeatureOff_DoesntFilter() { - when(mFeatureConfigMock.packageIsEnabled(any(PackageParser.Package.class))) + when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(false); final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, mPermissionManagerMock, @@ -301,13 +314,15 @@ public class AppsFilterTest { } private PackageSettingBuilder simulateAddPackage(AppsFilter filter, - PackageBuilder newPkgBuilder) { - PackageParser.Package newPkg = newPkgBuilder.build(); + ParsingPackage newPkgBuilder) { + AndroidPackage newPkg = newPkgBuilder + .hideAsParsed() + .hideAsFinal(); filter.addPackage(newPkg, mExisting); - mExisting.put(newPkg.packageName, newPkg); + mExisting.put(newPkg.getPackageName(), newPkg); return new PackageSettingBuilder() .setPackage(newPkg) - .setName(newPkg.packageName) + .setName(newPkg.getPackageName()) .setCodePath("/") .setResourcePath("/") .setPVersionCode(1L); diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java index fec3267c2649..0273a1c5d86e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java @@ -19,17 +19,17 @@ package com.android.server.pm; import android.content.pm.PackageParser; import android.content.pm.Signature; +import android.test.AndroidTestCase; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LongSparseArray; + import com.android.internal.util.ArrayUtils; import java.io.File; import java.io.IOException; -import java.security.cert.CertificateException; import java.security.PublicKey; - -import android.test.AndroidTestCase; +import java.security.cert.CertificateException; public class KeySetManagerServiceTest extends AndroidTestCase { @@ -39,7 +39,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { public PackageSetting generateFakePackageSetting(String name) { return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"), new File(mContext.getCacheDir(), "fakeResPath"), "", "", "", - "", 1, 0, 0, null, null, 0 /*sharedUserId*/, null /*usesStaticLibraries*/, + "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); } diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java deleted file mode 100644 index c38672cfc93c..000000000000 --- a/services/tests/servicestests/src/com/android/server/pm/PackageBuilder.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.server.pm; - -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageParser; - -import com.android.internal.util.ArrayUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; - -class PackageBuilder { - final PackageParser.Package mPkg; - - PackageBuilder(String packageName) { - mPkg = new PackageParser.Package(packageName); - } - - PackageBuilder setApplicationInfoCodePath(String codePath) { - mPkg.applicationInfo.setCodePath(codePath); - return this; - } - - PackageBuilder setApplicationInfoResourcePath(String resourcePath) { - mPkg.applicationInfo.setResourcePath(resourcePath); - return this; - } - - PackageBuilder setCodePath(String codePath) { - mPkg.codePath = codePath; - return this; - } - - PackageBuilder setBaseCodePath(String baseCodePath) { - mPkg.baseCodePath = baseCodePath; - return this; - } - - PackageBuilder addUsesStaticLibrary(String name, long version) { - mPkg.usesStaticLibraries = ArrayUtils.add(mPkg.usesStaticLibraries, name); - mPkg.usesStaticLibrariesVersions = - ArrayUtils.appendLong(mPkg.usesStaticLibrariesVersions, version); - return this; - } - - PackageBuilder setApplicationInfoNativeLibraryRootDir(String dir) { - mPkg.applicationInfo.nativeLibraryRootDir = dir; - return this; - } - - PackageBuilder setStaticSharedLib(String staticSharedLibName, long staticSharedLibVersion) { - mPkg.staticSharedLibVersion = staticSharedLibVersion; - mPkg.staticSharedLibName = staticSharedLibName; - return this; - } - - PackageBuilder setManifestPackageName(String manifestPackageName) { - mPkg.manifestPackageName = manifestPackageName; - return this; - } - - PackageBuilder setVersionCodeMajor(int versionCodeMajor) { - mPkg.mVersionCodeMajor = versionCodeMajor; - return this; - } - - PackageBuilder setVersionCode(int versionCode) { - mPkg.mVersionCode = versionCode; - return this; - } - - PackageBuilder addSplitCodePath(String splitCodePath) { - mPkg.splitCodePaths = - ArrayUtils.appendElement(String.class, mPkg.splitCodePaths, splitCodePath); - return this; - } - - PackageBuilder setApplicationInfoVolumeUuid(String volumeUuid) { - mPkg.applicationInfo.volumeUuid = volumeUuid; - return this; - } - - PackageBuilder addLibraryName(String libraryName) { - mPkg.libraryNames = ArrayUtils.add(mPkg.libraryNames, libraryName); - return this; - } - - PackageBuilder setRealPackageName(String realPackageName) { - mPkg.mRealPackage = realPackageName; - return this; - } - - PackageBuilder setCpuAbiOVerride(String cpuAbiOverride) { - mPkg.cpuAbiOverride = cpuAbiOverride; - return this; - } - - PackageBuilder addPermissionRequest(String permissionName) { - mPkg.requestedPermissions.add(permissionName); - return this; - } - - PackageParser.Package build() { - return mPkg; - } - - public PackageBuilder addApplicationInfoFlag(int flag) { - mPkg.applicationInfo.flags |= flag; - return this; - } - - public PackageBuilder setApplicationInfoTargetSdkVersion(int versionCode) { - mPkg.applicationInfo.targetSdkVersion = versionCode; - return this; - } - - public PackageBuilder setQueriesIntents(Collection<Intent> queriesIntents) { - mPkg.mQueriesIntents = new ArrayList<>(queriesIntents); - return this; - } - - public PackageBuilder setQueriesIntents(Intent... intents) { - return setQueriesIntents(Arrays.asList(intents)); - } - - public PackageBuilder setQueriesPackages(Collection<String> queriesPackages) { - mPkg.mQueriesPackages = new ArrayList<>(queriesPackages); - return this; - } - - public PackageBuilder setQueriesPackages(String... queriesPackages) { - return setQueriesPackages(Arrays.asList(queriesPackages)); - } - - public PackageBuilder setForceQueryable(boolean forceQueryable) { - mPkg.mForceQueryable = forceQueryable; - return this; - } - - public interface ParseComponentArgsCreator { - PackageParser.ParseComponentArgs create(PackageParser.Package pkg); - } - - public PackageBuilder addActivity(ParseComponentArgsCreator argsCreator, ActivityInfo info) { - mPkg.activities.add(new PackageParser.Activity(argsCreator.create(mPkg), info)); - return this; - } - - public interface ActivityIntentInfoCreator { - PackageParser.ActivityIntentInfo create(PackageParser.Activity activity); - } - - public PackageBuilder addActivityIntentInfo( - int activityIndex, ActivityIntentInfoCreator creator) { - final PackageParser.Activity activity = mPkg.activities.get(activityIndex); - activity.intents.add(creator.create(activity)); - return this; - } -} diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java index 0a310d193675..85840e135909 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java @@ -87,7 +87,7 @@ public class PackageManagerServiceTest { setting = new PackageSetting("name", "realName", new File("codePath"), new File("resourcePath"), "legacyNativeLibraryPathString", "primaryCpuAbiString", "secondaryCpuAbiString", - "cpuAbiOverrideString", 0, 0, 0, "parentPackageName", null, 0, + "cpuAbiOverrideString", 0, 0, 0, 0, null, null); pri.populateUsers(new int[] { 1, 2, 3, 4, 5 diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 3fe9b52b8415..6836d3b6e21d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -346,10 +346,6 @@ public class PackageManagerSettingsTests { private static final String PACKAGE_NAME = "com.android.bar"; private static final String REAL_PACKAGE_NAME = "com.android.foo"; - private static final String PARENT_PACKAGE_NAME = "com.android.bar.parent"; - private static final String CHILD_PACKAGE_NAME_01 = "com.android.bar.child01"; - private static final String CHILD_PACKAGE_NAME_02 = "com.android.bar.child02"; - private static final String CHILD_PACKAGE_NAME_03 = "com.android.bar.child03"; private static final File INITIAL_CODE_PATH = new File(InstrumentationRegistry.getContext().getFilesDir(), "com.android.bar-1"); private static final File UPDATED_CODE_PATH = @@ -359,10 +355,6 @@ public class PackageManagerSettingsTests { @Test public void testPackageStateCopy01() { - final List<String> childPackageNames = new ArrayList<>(); - childPackageNames.add(CHILD_PACKAGE_NAME_01); - childPackageNames.add(CHILD_PACKAGE_NAME_02); - childPackageNames.add(CHILD_PACKAGE_NAME_03); final PackageSetting origPkgSetting01 = new PackageSetting( PACKAGE_NAME, REAL_PACKAGE_NAME, @@ -375,8 +367,6 @@ public class PackageManagerSettingsTests { INITIAL_VERSION_CODE, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN, - PARENT_PACKAGE_NAME, - childPackageNames, 0, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -386,10 +376,6 @@ public class PackageManagerSettingsTests { @Test public void testPackageStateCopy02() { - final List<String> childPackageNames = new ArrayList<>(); - childPackageNames.add(CHILD_PACKAGE_NAME_01); - childPackageNames.add(CHILD_PACKAGE_NAME_02); - childPackageNames.add(CHILD_PACKAGE_NAME_03); final PackageSetting origPkgSetting01 = new PackageSetting( PACKAGE_NAME /*pkgName*/, REAL_PACKAGE_NAME /*realPkgName*/, @@ -402,8 +388,6 @@ public class PackageManagerSettingsTests { INITIAL_VERSION_CODE, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_HAS_CODE, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED|ApplicationInfo.PRIVATE_FLAG_HIDDEN, - PARENT_PACKAGE_NAME, - childPackageNames, 0, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -419,8 +403,6 @@ public class PackageManagerSettingsTests { UPDATED_VERSION_CODE, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, - null /*parentPkgName*/, - null /*childPkgNames*/, 0, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -448,7 +430,6 @@ public class PackageManagerSettingsTests { "armeabi" /*secondaryCpuAbi*/, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -482,7 +463,6 @@ public class PackageManagerSettingsTests { "armeabi" /*secondaryCpuAbi*/, ApplicationInfo.FLAG_SYSTEM /*pkgFlags*/, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED /*pkgPrivateFlags*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -522,7 +502,6 @@ public class PackageManagerSettingsTests { "armeabi" /*secondaryCpuAbi*/, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -555,8 +534,6 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, - null /*parentPkgName*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -596,8 +573,6 @@ public class PackageManagerSettingsTests { true /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, - null /*parentPkgName*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -643,8 +618,6 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, - null /*parentPkgName*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -687,8 +660,6 @@ public class PackageManagerSettingsTests { false /*allowInstall*/, false /*instantApp*/, false /*virtualPreload*/, - null /*parentPkgName*/, - null /*childPkgNames*/, UserManagerService.getInstance(), null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -745,9 +716,6 @@ public class PackageManagerSettingsTests { private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) { assertThat(origPkgSetting, is(not(testPkgSetting))); assertThat(origPkgSetting.appId, is(testPkgSetting.appId)); - // different but equal objects - assertNotSame(origPkgSetting.childPackageNames, testPkgSetting.childPackageNames); - assertThat(origPkgSetting.childPackageNames, is(testPkgSetting.childPackageNames)); assertSame(origPkgSetting.codePath, testPkgSetting.codePath); assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath)); assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString); @@ -773,8 +741,6 @@ public class PackageManagerSettingsTests { // mOldCodePaths is _not_ copied // assertNotSame(origPkgSetting.mOldCodePaths, testPkgSetting.mOldCodePaths); // assertThat(origPkgSetting.mOldCodePaths, is(not(testPkgSetting.mOldCodePaths))); - assertSame(origPkgSetting.parentPackageName, testPkgSetting.parentPackageName); - assertThat(origPkgSetting.parentPackageName, is(testPkgSetting.parentPackageName)); assertSame(origPkgSetting.pkg, testPkgSetting.pkg); // No equals() method for this object // assertThat(origPkgSetting.pkg, is(testPkgSetting.pkg)); @@ -826,8 +792,6 @@ public class PackageManagerSettingsTests { INITIAL_VERSION_CODE, pkgFlags, 0 /*privateFlags*/, - null /*parentPackageName*/, - null /*childPackageNames*/, sharedUserId, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); @@ -846,8 +810,6 @@ public class PackageManagerSettingsTests { INITIAL_VERSION_CODE, 0, 0 /*privateFlags*/, - null /*parentPackageName*/, - null /*childPackageNames*/, 0, null /*usesStaticLibraries*/, null /*usesStaticLibrariesVersions*/); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java index e33d8ca66ed0..162092b5040a 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java @@ -15,35 +15,49 @@ */ package com.android.server.pm; -import static android.content.res.Resources.ID_NULL; - +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; import android.content.pm.FeatureGroupInfo; import android.content.pm.FeatureInfo; -import android.content.pm.InstrumentationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ComponentParseUtils; +import android.content.pm.parsing.ComponentParseUtils.ParsedActivity; +import android.content.pm.parsing.ComponentParseUtils.ParsedComponent; +import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation; +import android.content.pm.parsing.ComponentParseUtils.ParsedIntentInfo; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermission; +import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup; +import android.content.pm.parsing.ComponentParseUtils.ParsedProvider; +import android.content.pm.parsing.ComponentParseUtils.ParsedService; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.PackageInfoUtils; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackage; import android.os.Bundle; import android.os.Parcel; import android.platform.test.annotations.Presubmit; -import android.util.ArrayMap; import android.util.ArraySet; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.ArrayUtils; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -57,6 +71,7 @@ import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -64,6 +79,9 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) @MediumTest public class PackageParserTest { + // TODO(b/135203078): Update this test with all fields and validate equality. Initial change + // was just migrating to new interfaces. Consider adding actual equals() methods. + @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); @@ -79,12 +97,12 @@ public class PackageParserTest { @Test public void testParse_noCache() throws Exception { PackageParser pp = new CachePackageNameParser(); - PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, + ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); assertNotNull(pkg); pp.setCacheDir(mTmpDir); - pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, + pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); assertNotNull(pkg); @@ -99,27 +117,27 @@ public class PackageParserTest { pp.setCacheDir(mTmpDir); // The first parse will write this package to the cache. - pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); + pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); // Now attempt to parse the package again, should return the // cached result. - PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, + ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); - assertEquals("cache_android", pkg.packageName); + assertEquals("cache_android", pkg.getPackageName()); // Try again, with useCaches == false, shouldn't return the parsed // result. - pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); - assertEquals("android", pkg.packageName); + pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); + assertEquals("android", pkg.getPackageName()); // We haven't set a cache directory here : the parse should still succeed, // just not using the cached results. pp = new CachePackageNameParser(); - pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); - assertEquals("android", pkg.packageName); + pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, true /* useCaches */); + assertEquals("android", pkg.getPackageName()); - pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); - assertEquals("android", pkg.packageName); + pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, false /* useCaches */); + assertEquals("android", pkg.getPackageName()); } @Test @@ -127,14 +145,14 @@ public class PackageParserTest { PackageParser pp = new PackageParser(); pp.setCacheDir(mTmpDir); - PackageParser.Package pkg = pp.parsePackage(FRAMEWORK, 0 /* parseFlags */, - true /* useCaches */); + ParsedPackage pkg = pp.parseParsedPackage(FRAMEWORK, 0 /* parseFlags */, + true /* useCaches */); Parcel p = Parcel.obtain(); pkg.writeToParcel(p, 0 /* flags */); p.setDataPosition(0); - PackageParser.Package deserialized = new PackageParser.Package(p); + ParsedPackage deserialized = new PackageImpl(p); assertPackagesEqual(pkg, deserialized); } @@ -143,46 +161,52 @@ public class PackageParserTest { @SmallTest @Presubmit public void test_roundTripKnownFields() throws Exception { - PackageParser.Package pkg = new PackageParser.Package("foo"); + ParsingPackage pkg = PackageImpl.forParsing("foo"); setKnownFields(pkg); Parcel p = Parcel.obtain(); pkg.writeToParcel(p, 0 /* flags */); p.setDataPosition(0); - PackageParser.Package deserialized = new PackageParser.Package(p); + ParsedPackage deserialized = new PackageImpl(p); assertAllFieldsExist(deserialized); } @Test public void test_stringInterning() throws Exception { - PackageParser.Package pkg = new PackageParser.Package("foo"); + ParsingPackage pkg = PackageImpl.forParsing("foo"); setKnownFields(pkg); Parcel p = Parcel.obtain(); pkg.writeToParcel(p, 0 /* flags */); p.setDataPosition(0); - PackageParser.Package deserialized = new PackageParser.Package(p); + ParsingPackage deserialized = new PackageImpl(p); p.setDataPosition(0); - PackageParser.Package deserialized2 = new PackageParser.Package(p); - - assertSame(deserialized.packageName, deserialized2.packageName); - assertSame(deserialized.applicationInfo.permission, - deserialized2.applicationInfo.permission); - assertSame(deserialized.requestedPermissions.get(0), - deserialized2.requestedPermissions.get(0)); - assertSame(deserialized.protectedBroadcasts.get(0), - deserialized2.protectedBroadcasts.get(0)); - assertSame(deserialized.usesLibraries.get(0), - deserialized2.usesLibraries.get(0)); - assertSame(deserialized.usesOptionalLibraries.get(0), - deserialized2.usesOptionalLibraries.get(0)); - assertSame(deserialized.mVersionName, deserialized2.mVersionName); - assertSame(deserialized.mSharedUserId, deserialized2.mSharedUserId); - } + ParsingPackage deserialized2 = new PackageImpl(p); + assertSame(deserialized.getPackageName(), deserialized2.getPackageName()); + assertSame(deserialized.getPermission(), + deserialized2.getPermission()); + assertSame(deserialized.getRequestedPermissions().get(0), + deserialized2.getRequestedPermissions().get(0)); + + List<String> protectedBroadcastsOne = new ArrayList<>(1); + protectedBroadcastsOne.addAll(deserialized.getProtectedBroadcasts()); + + List<String> protectedBroadcastsTwo = new ArrayList<>(1); + protectedBroadcastsTwo.addAll(deserialized2.getProtectedBroadcasts()); + + assertSame(protectedBroadcastsOne.get(0), protectedBroadcastsTwo.get(0)); + + assertSame(deserialized.getUsesLibraries().get(0), + deserialized2.getUsesLibraries().get(0)); + assertSame(deserialized.getUsesOptionalLibraries().get(0), + deserialized2.getUsesOptionalLibraries().get(0)); + assertSame(deserialized.getVersionName(), deserialized2.getVersionName()); + assertSame(deserialized.getSharedUserId(), deserialized2.getSharedUserId()); + } /** * A trivial subclass of package parser that only caches the package name, and throws away @@ -190,107 +214,111 @@ public class PackageParserTest { */ public static class CachePackageNameParser extends PackageParser { @Override - public byte[] toCacheEntry(Package pkg) { - return ("cache_" + pkg.packageName).getBytes(StandardCharsets.UTF_8); + public byte[] toCacheEntry(ParsedPackage pkg) { + return ("cache_" + pkg.getPackageName()).getBytes(StandardCharsets.UTF_8); } @Override - public Package fromCacheEntry(byte[] cacheEntry) { - return new Package(new String(cacheEntry, StandardCharsets.UTF_8)); + public ParsedPackage fromCacheEntry(byte[] cacheEntry) { + return PackageImpl.forParsing(new String(cacheEntry, StandardCharsets.UTF_8)) + .hideAsParsed(); } } // NOTE: The equality assertions below are based on code autogenerated by IntelliJ. - public static void assertPackagesEqual(PackageParser.Package a, PackageParser.Package b) { - assertEquals(a.baseRevisionCode, b.baseRevisionCode); - assertEquals(a.baseHardwareAccelerated, b.baseHardwareAccelerated); - assertEquals(a.mVersionCode, b.mVersionCode); - assertEquals(a.mSharedUserLabel, b.mSharedUserLabel); - assertEquals(a.mPreferredOrder, b.mPreferredOrder); - assertEquals(a.installLocation, b.installLocation); - assertEquals(a.coreApp, b.coreApp); - assertEquals(a.mRequiredForAllUsers, b.mRequiredForAllUsers); - assertEquals(a.mCompileSdkVersion, b.mCompileSdkVersion); - assertEquals(a.mCompileSdkVersionCodename, b.mCompileSdkVersionCodename); - assertEquals(a.use32bitAbi, b.use32bitAbi); - assertEquals(a.packageName, b.packageName); - assertTrue(Arrays.equals(a.splitNames, b.splitNames)); - assertEquals(a.volumeUuid, b.volumeUuid); - assertEquals(a.codePath, b.codePath); - assertEquals(a.baseCodePath, b.baseCodePath); - assertTrue(Arrays.equals(a.splitCodePaths, b.splitCodePaths)); - assertTrue(Arrays.equals(a.splitRevisionCodes, b.splitRevisionCodes)); - assertTrue(Arrays.equals(a.splitFlags, b.splitFlags)); - assertTrue(Arrays.equals(a.splitPrivateFlags, b.splitPrivateFlags)); - assertApplicationInfoEqual(a.applicationInfo, b.applicationInfo); - - assertEquals(a.permissions.size(), b.permissions.size()); - for (int i = 0; i < a.permissions.size(); ++i) { - assertPermissionsEqual(a.permissions.get(i), b.permissions.get(i)); - assertSame(a.permissions.get(i).owner, a); - assertSame(b.permissions.get(i).owner, b); + public static void assertPackagesEqual(AndroidPackage a, AndroidPackage b) { + assertEquals(a.getBaseRevisionCode(), b.getBaseRevisionCode()); + assertEquals(a.isBaseHardwareAccelerated(), b.isBaseHardwareAccelerated()); + assertEquals(a.getVersionCode(), b.getVersionCode()); + assertEquals(a.getSharedUserLabel(), b.getSharedUserLabel()); + assertEquals(a.getPreferredOrder(), b.getPreferredOrder()); + assertEquals(a.getInstallLocation(), b.getInstallLocation()); + assertEquals(a.isCoreApp(), b.isCoreApp()); + assertEquals(a.isRequiredForAllUsers(), b.isRequiredForAllUsers()); + assertEquals(a.getCompileSdkVersion(), b.getCompileSdkVersion()); + assertEquals(a.getCompileSdkVersionCodeName(), b.getCompileSdkVersionCodeName()); + assertEquals(a.isUse32BitAbi(), b.isUse32BitAbi()); + assertEquals(a.getPackageName(), b.getPackageName()); + assertArrayEquals(a.getSplitNames(), b.getSplitNames()); + assertEquals(a.getVolumeUuid(), b.getVolumeUuid()); + assertEquals(a.getCodePath(), b.getCodePath()); + assertEquals(a.getBaseCodePath(), b.getBaseCodePath()); + assertArrayEquals(a.getSplitCodePaths(), b.getSplitCodePaths()); + assertArrayEquals(a.getSplitRevisionCodes(), b.getSplitRevisionCodes()); + assertArrayEquals(a.getSplitFlags(), b.getSplitFlags()); + + PackageInfo aInfo = PackageInfoUtils.generate(a, new int[]{}, 0, 0, 0, + Collections.emptySet(), new PackageUserState(), 0); + PackageInfo bInfo = PackageInfoUtils.generate(b, new int[]{}, 0, 0, 0, + Collections.emptySet(), new PackageUserState(), 0); + assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); + + assertEquals(ArrayUtils.size(a.getPermissions()), ArrayUtils.size(b.getPermissions())); + for (int i = 0; i < ArrayUtils.size(a.getPermissions()); ++i) { + assertPermissionsEqual(a.getPermissions().get(i), b.getPermissions().get(i)); } - assertEquals(a.permissionGroups.size(), b.permissionGroups.size()); - for (int i = 0; i < a.permissionGroups.size(); ++i) { - assertPermissionGroupsEqual(a.permissionGroups.get(i), b.permissionGroups.get(i)); + assertEquals(ArrayUtils.size(a.getPermissionGroups()), + ArrayUtils.size(b.getPermissionGroups())); + for (int i = 0; i < a.getPermissionGroups().size(); ++i) { + assertPermissionGroupsEqual(a.getPermissionGroups().get(i), + b.getPermissionGroups().get(i)); } - assertEquals(a.activities.size(), b.activities.size()); - for (int i = 0; i < a.activities.size(); ++i) { - assertActivitiesEqual(a.activities.get(i), b.activities.get(i)); + assertEquals(ArrayUtils.size(a.getActivities()), ArrayUtils.size(b.getActivities())); + for (int i = 0; i < ArrayUtils.size(a.getActivities()); ++i) { + assertActivitiesEqual(a, a.getActivities().get(i), b, b.getActivities().get(i)); } - assertEquals(a.receivers.size(), b.receivers.size()); - for (int i = 0; i < a.receivers.size(); ++i) { - assertActivitiesEqual(a.receivers.get(i), b.receivers.get(i)); + assertEquals(ArrayUtils.size(a.getReceivers()), ArrayUtils.size(b.getReceivers())); + for (int i = 0; i < ArrayUtils.size(a.getReceivers()); ++i) { + assertActivitiesEqual(a, a.getReceivers().get(i), b, b.getReceivers().get(i)); } - assertEquals(a.providers.size(), b.providers.size()); - for (int i = 0; i < a.providers.size(); ++i) { - assertProvidersEqual(a.providers.get(i), b.providers.get(i)); + assertEquals(ArrayUtils.size(a.getProviders()), ArrayUtils.size(b.getProviders())); + for (int i = 0; i < ArrayUtils.size(a.getProviders()); ++i) { + assertProvidersEqual(a, a.getProviders().get(i), b, b.getProviders().get(i)); } - assertEquals(a.services.size(), b.services.size()); - for (int i = 0; i < a.services.size(); ++i) { - assertServicesEqual(a.services.get(i), b.services.get(i)); + assertEquals(ArrayUtils.size(a.getServices()), ArrayUtils.size(b.getServices())); + for (int i = 0; i < ArrayUtils.size(a.getServices()); ++i) { + assertServicesEqual(a, a.getServices().get(i), b, b.getServices().get(i)); } - assertEquals(a.instrumentation.size(), b.instrumentation.size()); - for (int i = 0; i < a.instrumentation.size(); ++i) { - assertInstrumentationEqual(a.instrumentation.get(i), b.instrumentation.get(i)); + assertEquals(ArrayUtils.size(a.getInstrumentations()), + ArrayUtils.size(b.getInstrumentations())); + for (int i = 0; i < ArrayUtils.size(a.getInstrumentations()); ++i) { + assertInstrumentationEqual(a.getInstrumentations().get(i), + b.getInstrumentations().get(i)); } - assertEquals(a.requestedPermissions, b.requestedPermissions); - assertEquals(a.protectedBroadcasts, b.protectedBroadcasts); - assertEquals(a.parentPackage, b.parentPackage); - assertEquals(a.childPackages, b.childPackages); - assertEquals(a.libraryNames, b.libraryNames); - assertEquals(a.usesLibraries, b.usesLibraries); - assertEquals(a.usesOptionalLibraries, b.usesOptionalLibraries); - assertTrue(Arrays.equals(a.usesLibraryFiles, b.usesLibraryFiles)); - assertEquals(a.mOriginalPackages, b.mOriginalPackages); - assertEquals(a.mRealPackage, b.mRealPackage); - assertEquals(a.mAdoptPermissions, b.mAdoptPermissions); - assertBundleApproximateEquals(a.mAppMetaData, b.mAppMetaData); - assertEquals(a.mVersionName, b.mVersionName); - assertEquals(a.mSharedUserId, b.mSharedUserId); - assertTrue(Arrays.equals(a.mSigningDetails.signatures, b.mSigningDetails.signatures)); - assertTrue(Arrays.equals(a.mLastPackageUsageTimeInMills, b.mLastPackageUsageTimeInMills)); - assertEquals(a.mExtras, b.mExtras); - assertEquals(a.mRestrictedAccountType, b.mRestrictedAccountType); - assertEquals(a.mRequiredAccountType, b.mRequiredAccountType); - assertEquals(a.mOverlayTarget, b.mOverlayTarget); - assertEquals(a.mOverlayTargetName, b.mOverlayTargetName); - assertEquals(a.mOverlayCategory, b.mOverlayCategory); - assertEquals(a.mOverlayPriority, b.mOverlayPriority); - assertEquals(a.mOverlayIsStatic, b.mOverlayIsStatic); - assertEquals(a.mSigningDetails.publicKeys, b.mSigningDetails.publicKeys); - assertEquals(a.mUpgradeKeySets, b.mUpgradeKeySets); - assertEquals(a.mKeySetMapping, b.mKeySetMapping); - assertEquals(a.cpuAbiOverride, b.cpuAbiOverride); - assertTrue(Arrays.equals(a.restrictUpdateHash, b.restrictUpdateHash)); + assertEquals(a.getRequestedPermissions(), b.getRequestedPermissions()); + assertEquals(a.getProtectedBroadcasts(), b.getProtectedBroadcasts()); + assertEquals(a.getLibraryNames(), b.getLibraryNames()); + assertEquals(a.getUsesLibraries(), b.getUsesLibraries()); + assertEquals(a.getUsesOptionalLibraries(), b.getUsesOptionalLibraries()); + assertArrayEquals(a.getUsesLibraryFiles(), b.getUsesLibraryFiles()); + assertEquals(a.getOriginalPackages(), b.getOriginalPackages()); + assertEquals(a.getRealPackage(), b.getRealPackage()); + assertEquals(a.getAdoptPermissions(), b.getAdoptPermissions()); + assertBundleApproximateEquals(a.getAppMetaData(), b.getAppMetaData()); + assertEquals(a.getVersionName(), b.getVersionName()); + assertEquals(a.getSharedUserId(), b.getSharedUserId()); + assertArrayEquals(a.getSigningDetails().signatures, b.getSigningDetails().signatures); + assertArrayEquals(a.getLastPackageUsageTimeInMills(), b.getLastPackageUsageTimeInMills()); + assertEquals(a.getRestrictedAccountType(), b.getRestrictedAccountType()); + assertEquals(a.getRequiredAccountType(), b.getRequiredAccountType()); + assertEquals(a.getOverlayTarget(), b.getOverlayTarget()); + assertEquals(a.getOverlayTargetName(), b.getOverlayTargetName()); + assertEquals(a.getOverlayCategory(), b.getOverlayCategory()); + assertEquals(a.getOverlayPriority(), b.getOverlayPriority()); + assertEquals(a.isOverlayIsStatic(), b.isOverlayIsStatic()); + assertEquals(a.getSigningDetails().publicKeys, b.getSigningDetails().publicKeys); + assertEquals(a.getUpgradeKeySets(), b.getUpgradeKeySets()); + assertEquals(a.getKeySetMapping(), b.getKeySetMapping()); + assertEquals(a.getCpuAbiOverride(), b.getCpuAbiOverride()); + assertArrayEquals(a.getRestrictUpdateHash(), b.getRestrictUpdateHash()); } private static void assertBundleApproximateEquals(Bundle a, Bundle b) { @@ -305,10 +333,10 @@ public class PackageParserTest { assertEquals(a.toString(), b.toString()); } - private static void assertComponentsEqual(PackageParser.Component<?> a, - PackageParser.Component<?> b) { + private static void assertComponentsEqual(ParsedComponent<?> a, + ParsedComponent<?> b) { assertEquals(a.className, b.className); - assertBundleApproximateEquals(a.metaData, b.metaData); + assertBundleApproximateEquals(a.getMetaData(), b.getMetaData()); assertEquals(a.getComponentName(), b.getComponentName()); if (a.intents != null && b.intents != null) { @@ -318,80 +346,104 @@ public class PackageParserTest { } for (int i = 0; i < a.intents.size(); ++i) { - PackageParser.IntentInfo aIntent = a.intents.get(i); - PackageParser.IntentInfo bIntent = b.intents.get(i); + ParsedIntentInfo aIntent = a.intents.get(i); + ParsedIntentInfo bIntent = b.intents.get(i); assertEquals(aIntent.hasDefault, bIntent.hasDefault); assertEquals(aIntent.labelRes, bIntent.labelRes); assertEquals(aIntent.nonLocalizedLabel, bIntent.nonLocalizedLabel); assertEquals(aIntent.icon, bIntent.icon); - assertEquals(aIntent.logo, bIntent.logo); - assertEquals(aIntent.banner, bIntent.banner); - assertEquals(aIntent.preferred, bIntent.preferred); } } - private static void assertPermissionsEqual(PackageParser.Permission a, - PackageParser.Permission b) { + private static void assertPermissionsEqual(ParsedPermission a, + ParsedPermission b) { assertComponentsEqual(a, b); assertEquals(a.tree, b.tree); // Verify basic flags in PermissionInfo to make sure they're consistent. We don't perform // a full structural equality here because the code that serializes them isn't parser // specific and is tested elsewhere. - assertEquals(a.info.protectionLevel, b.info.protectionLevel); - assertEquals(a.info.group, b.info.group); - assertEquals(a.info.flags, b.info.flags); + assertEquals(a.getProtection(), b.getProtection()); + assertEquals(a.getGroup(), b.getGroup()); + assertEquals(a.flags, b.flags); - if (a.group != null && b.group != null) { - assertPermissionGroupsEqual(a.group, b.group); - } else if (a.group != null || b.group != null) { + if (a.parsedPermissionGroup != null && b.parsedPermissionGroup != null) { + assertPermissionGroupsEqual(a.parsedPermissionGroup, b.parsedPermissionGroup); + } else if (a.parsedPermissionGroup != null || b.parsedPermissionGroup != null) { throw new AssertionError(); } } - private static void assertInstrumentationEqual(PackageParser.Instrumentation a, - PackageParser.Instrumentation b) { + private static void assertInstrumentationEqual(ParsedInstrumentation a, + ParsedInstrumentation b) { assertComponentsEqual(a, b); // Sanity check for InstrumentationInfo. - assertEquals(a.info.targetPackage, b.info.targetPackage); - assertEquals(a.info.targetProcesses, b.info.targetProcesses); - assertEquals(a.info.sourceDir, b.info.sourceDir); - assertEquals(a.info.publicSourceDir, b.info.publicSourceDir); + assertEquals(a.getTargetPackage(), b.getTargetPackage()); + assertEquals(a.getTargetProcesses(), b.getTargetProcesses()); + assertEquals(a.sourceDir, b.sourceDir); + assertEquals(a.publicSourceDir, b.publicSourceDir); } - private static void assertServicesEqual(PackageParser.Service a, PackageParser.Service b) { + private static void assertServicesEqual( + AndroidPackage aPkg, + ParsedService a, + AndroidPackage bPkg, + ParsedService b + ) { assertComponentsEqual(a, b); // Sanity check for ServiceInfo. - assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); - assertEquals(a.info.name, b.info.name); + ServiceInfo aInfo = PackageInfoUtils.generateServiceInfo(aPkg, a, 0, new PackageUserState(), + 0); + ServiceInfo bInfo = PackageInfoUtils.generateServiceInfo(bPkg, b, 0, new PackageUserState(), + 0); + assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); + assertEquals(a.getName(), b.getName()); } - private static void assertProvidersEqual(PackageParser.Provider a, PackageParser.Provider b) { + private static void assertProvidersEqual( + AndroidPackage aPkg, + ParsedProvider a, + AndroidPackage bPkg, + ParsedProvider b + ) { assertComponentsEqual(a, b); // Sanity check for ProviderInfo - assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); - assertEquals(a.info.name, b.info.name); + ProviderInfo aInfo = PackageInfoUtils.generateProviderInfo(aPkg, a, 0, + new PackageUserState(), 0); + ProviderInfo bInfo = PackageInfoUtils.generateProviderInfo(bPkg, b, 0, + new PackageUserState(), 0); + assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); + assertEquals(a.getName(), b.getName()); } - private static void assertActivitiesEqual(PackageParser.Activity a, PackageParser.Activity b) { + private static void assertActivitiesEqual( + AndroidPackage aPkg, + ParsedActivity a, + AndroidPackage bPkg, + ParsedActivity b + ) { assertComponentsEqual(a, b); // Sanity check for ActivityInfo. - assertApplicationInfoEqual(a.info.applicationInfo, b.info.applicationInfo); - assertEquals(a.info.name, b.info.name); + ActivityInfo aInfo = PackageInfoUtils.generateActivityInfo(aPkg, a, 0, + new PackageUserState(), 0); + ActivityInfo bInfo = PackageInfoUtils.generateActivityInfo(bPkg, b, 0, + new PackageUserState(), 0); + assertApplicationInfoEqual(aInfo.applicationInfo, bInfo.applicationInfo); + assertEquals(a.getName(), b.getName()); } - private static void assertPermissionGroupsEqual(PackageParser.PermissionGroup a, - PackageParser.PermissionGroup b) { + private static void assertPermissionGroupsEqual(ParsedPermissionGroup a, + ParsedPermissionGroup b) { assertComponentsEqual(a, b); // Sanity check for PermissionGroupInfo. - assertEquals(a.info.name, b.info.name); - assertEquals(a.info.descriptionRes, b.info.descriptionRes); + assertEquals(a.getName(), b.getName()); + assertEquals(a.descriptionRes, b.descriptionRes); } private static void assertApplicationInfoEqual(ApplicationInfo a, ApplicationInfo that) { @@ -424,11 +476,11 @@ public class PackageParserTest { assertEquals(a.scanPublicSourceDir, that.scanPublicSourceDir); assertEquals(a.sourceDir, that.sourceDir); assertEquals(a.publicSourceDir, that.publicSourceDir); - assertTrue(Arrays.equals(a.splitSourceDirs, that.splitSourceDirs)); - assertTrue(Arrays.equals(a.splitPublicSourceDirs, that.splitPublicSourceDirs)); - assertTrue(Arrays.equals(a.resourceDirs, that.resourceDirs)); + assertArrayEquals(a.splitSourceDirs, that.splitSourceDirs); + assertArrayEquals(a.splitPublicSourceDirs, that.splitPublicSourceDirs); + assertArrayEquals(a.resourceDirs, that.resourceDirs); assertEquals(a.seInfo, that.seInfo); - assertTrue(Arrays.equals(a.sharedLibraryFiles, that.sharedLibraryFiles)); + assertArrayEquals(a.sharedLibraryFiles, that.sharedLibraryFiles); assertEquals(a.dataDir, that.dataDir); assertEquals(a.deviceProtectedDataDir, that.deviceProtectedDataDir); assertEquals(a.credentialProtectedDataDir, that.credentialProtectedDataDir); @@ -439,132 +491,93 @@ public class PackageParserTest { assertEquals(a.secondaryCpuAbi, that.secondaryCpuAbi); } - public static void setKnownFields(PackageParser.Package pkg) { - pkg.baseRevisionCode = 100; - pkg.baseHardwareAccelerated = true; - pkg.mVersionCode = 100; - pkg.mSharedUserLabel = 100; - pkg.mPreferredOrder = 100; - pkg.installLocation = 100; - pkg.coreApp = true; - pkg.mRequiredForAllUsers = true; - pkg.use32bitAbi = true; - pkg.packageName = "foo"; - pkg.splitNames = new String[] { "foo2" }; - pkg.volumeUuid = "foo3"; - pkg.codePath = "foo4"; - pkg.baseCodePath = "foo5"; - pkg.splitCodePaths = new String[] { "foo6" }; - pkg.splitRevisionCodes = new int[] { 100 }; - pkg.splitFlags = new int[] { 100 }; - pkg.splitPrivateFlags = new int[] { 100 }; - pkg.applicationInfo = new ApplicationInfo(); - - pkg.permissions.add(new PackageParser.Permission(pkg, (String) null)); - pkg.permissionGroups.add(new PackageParser.PermissionGroup(pkg, ID_NULL, ID_NULL, ID_NULL)); - - final PackageParser.ParseComponentArgs dummy = new PackageParser.ParseComponentArgs( - pkg, new String[1], 0, 0, 0, 0, 0, 0, null, 0, 0, 0); - - pkg.activities.add(new PackageParser.Activity(dummy, new ActivityInfo())); - pkg.receivers.add(new PackageParser.Activity(dummy, new ActivityInfo())); - pkg.providers.add(new PackageParser.Provider(dummy, new ProviderInfo())); - pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo())); - pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo())); - pkg.requestedPermissions.add("foo7"); - pkg.implicitPermissions.add("foo25"); - - pkg.protectedBroadcasts = new ArrayList<>(); - pkg.protectedBroadcasts.add("foo8"); - - pkg.parentPackage = new PackageParser.Package("foo9"); - - pkg.childPackages = new ArrayList<>(); - pkg.childPackages.add(new PackageParser.Package("bar")); - - pkg.staticSharedLibName = "foo23"; - pkg.staticSharedLibVersion = 100; - pkg.usesStaticLibraries = new ArrayList<>(); - pkg.usesStaticLibraries.add("foo23"); - pkg.usesStaticLibrariesCertDigests = new String[1][]; - pkg.usesStaticLibrariesCertDigests[0] = new String[] { "digest" }; - pkg.usesStaticLibrariesVersions = new long[] { 100 }; - - pkg.libraryNames = new ArrayList<>(); - pkg.libraryNames.add("foo10"); - - pkg.usesLibraries = new ArrayList<>(); - pkg.usesLibraries.add("foo11"); - - pkg.usesOptionalLibraries = new ArrayList<>(); - pkg.usesOptionalLibraries.add("foo12"); - - pkg.usesLibraryFiles = new String[] { "foo13"}; - - pkg.usesLibraryInfos = new ArrayList<>(); - pkg.usesLibraryInfos.add( - new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null)); - - pkg.mOriginalPackages = new ArrayList<>(); - pkg.mOriginalPackages.add("foo14"); - - pkg.mRealPackage = "foo15"; - - pkg.mAdoptPermissions = new ArrayList<>(); - pkg.mAdoptPermissions.add("foo16"); - - pkg.mAppMetaData = new Bundle(); - pkg.mVersionName = "foo17"; - pkg.mSharedUserId = "foo18"; - pkg.mSigningDetails = - new PackageParser.SigningDetails( - new Signature[] { new Signature(new byte[16]) }, - 2, - new ArraySet<>(), - null); - pkg.mExtras = new Bundle(); - pkg.mRestrictedAccountType = "foo19"; - pkg.mRequiredAccountType = "foo20"; - pkg.mOverlayTarget = "foo21"; - pkg.mOverlayPriority = 100; - pkg.mUpgradeKeySets = new ArraySet<>(); - pkg.mKeySetMapping = new ArrayMap<>(); - pkg.cpuAbiOverride = "foo22"; - pkg.restrictUpdateHash = new byte[16]; - - pkg.preferredActivityFilters = new ArrayList<>(); - pkg.preferredActivityFilters.add(new PackageParser.ActivityIntentInfo( - new PackageParser.Activity(dummy, new ActivityInfo()))); - - pkg.configPreferences = new ArrayList<>(); - pkg.configPreferences.add(new ConfigurationInfo()); - - pkg.reqFeatures = new ArrayList<>(); - pkg.reqFeatures.add(new FeatureInfo()); - - pkg.featureGroups = new ArrayList<>(); - pkg.featureGroups.add(new FeatureGroupInfo()); - - pkg.mCompileSdkVersionCodename = "foo23"; - pkg.mCompileSdkVersion = 100; - pkg.mVersionCodeMajor = 100; - - pkg.mOverlayCategory = "foo24"; - pkg.mOverlayIsStatic = true; - pkg.mOverlayTargetName = "foo26"; - - pkg.baseHardwareAccelerated = true; - pkg.coreApp = true; - pkg.mRequiredForAllUsers = true; - pkg.visibleToInstantApps = true; - pkg.use32bitAbi = true; - pkg.mForceQueryable = true; - pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27")); - pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28"))); + public static void setKnownFields(ParsingPackage pkg) { + Bundle bundle = new Bundle(); + bundle.putString("key", "value"); + + ParsedPermission permission = new ParsedPermission(); + permission.parsedPermissionGroup = new ParsedPermissionGroup(); + + pkg.setBaseRevisionCode(100) + .setBaseHardwareAccelerated(true) + .setSharedUserLabel(100) + .setPreferredOrder(100) + .setInstallLocation(100) + .setRequiredForAllUsers(true) + .asSplit( + new String[]{"foo2"}, + new String[]{"foo6"}, + new int[]{100}, + null + ) + .setUse32BitAbi(true) + .setVolumeUuid("foo3") + .setCodePath("foo4") + .addPermission(permission) + .addPermissionGroup(new ParsedPermissionGroup()) + .addActivity(new ParsedActivity()) + .addReceiver(new ParsedActivity()) + .addProvider(new ParsedProvider()) + .addService(new ParsedService()) + .addInstrumentation(new ParsedInstrumentation()) + .addRequestedPermission("foo7") + .addImplicitPermission("foo25") + .addProtectedBroadcast("foo8") + .setStaticSharedLibName("foo23") + .setStaticSharedLibVersion(100) + .addUsesStaticLibrary("foo23") + .addUsesStaticLibraryCertDigests(new String[]{"digest"}) + .addUsesStaticLibraryVersion(100) + .addLibraryName("foo10") + .addUsesLibrary("foo11") + .addUsesOptionalLibrary("foo12") + .addOriginalPackage("foo14") + .setRealPackage("foo15") + .addAdoptPermission("foo16") + .setAppMetaData(bundle) + .setVersionName("foo17") + .setSharedUserId("foo18") + .setSigningDetails( + new PackageParser.SigningDetails( + new Signature[]{new Signature(new byte[16])}, + 2, + new ArraySet<>(), + null) + ) + .setRestrictedAccountType("foo19") + .setRequiredAccountType("foo20") + .setOverlayTarget("foo21") + .setOverlayPriority(100) + .setUpgradeKeySets(new ArraySet<>()) + .addPreferredActivityFilter( + new ComponentParseUtils.ParsedActivityIntentInfo("foo", "className")) + .addConfigPreference(new ConfigurationInfo()) + .addReqFeature(new FeatureInfo()) + .addFeatureGroup(new FeatureGroupInfo()) + .setCompileSdkVersionCodename("foo23") + .setCompileSdkVersion(100) + .setOverlayCategory("foo24") + .setOverlayIsStatic(true) + .setOverlayTargetName("foo26") + .setVisibleToInstantApps(true) + .setSplitHasCode(0, true) + .hideAsParsed() + .setBaseCodePath("foo5") + .setVersionCode(100) + .setCpuAbiOverride("foo22") + .setRestrictUpdateHash(new byte[16]) + .setVersionCodeMajor(100) + .setCoreApp(true) + .hideAsFinal() + .mutate() + .setUsesLibraryInfos(Arrays.asList( + new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null) + )) + .setUsesLibraryFiles(new String[]{"foo13"}); } - private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception { - Field[] fields = PackageParser.Package.class.getDeclaredFields(); + private static void assertAllFieldsExist(ParsedPackage pkg) throws Exception { + Field[] fields = ParsedPackage.class.getDeclaredFields(); Set<String> nonSerializedFields = new HashSet<>(); nonSerializedFields.add("mExtras"); @@ -601,7 +614,7 @@ public class PackageParserTest { } else if (fieldType == boolean.class) { // boolean fields: Check that they're set to true. boolean value = (boolean) f.get(pkg); - assertEquals("Bad value for field: " + f, true, value); + assertTrue("Bad value for field: " + f, value); } else { // All other fields: Check that they're set. Object o = f.get(pkg); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java index 06c6314ab907..ca9e5b1efb58 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java @@ -16,12 +16,11 @@ package com.android.server.pm; -import android.content.pm.PackageParser; import android.content.pm.PackageUserState; +import android.content.pm.parsing.AndroidPackage; import android.util.SparseArray; import java.io.File; -import java.util.List; class PackageSettingBuilder { private String mName; @@ -35,16 +34,14 @@ class PackageSettingBuilder { private long mPVersionCode; private int mPkgFlags; private int mPrivateFlags; - private String mParentPackageName; - private List<String> mChildPackageNames; private int mSharedUserId; private String[] mUsesStaticLibraries; private long[] mUsesStaticLibrariesVersions; private String mVolumeUuid; private SparseArray<PackageUserState> mUserStates = new SparseArray<>(); - private PackageParser.Package mPkg; + private AndroidPackage mPkg; - public PackageSettingBuilder setPackage(PackageParser.Package pkg) { + public PackageSettingBuilder setPackage(AndroidPackage pkg) { this.mPkg = pkg; return this; } @@ -105,16 +102,6 @@ class PackageSettingBuilder { return this; } - public PackageSettingBuilder setParentPackageName(String parentPackageName) { - this.mParentPackageName = parentPackageName; - return this; - } - - public PackageSettingBuilder setChildPackageNames(List<String> childPackageNames) { - this.mChildPackageNames = childPackageNames; - return this; - } - public PackageSettingBuilder setSharedUserId(int sharedUserId) { this.mSharedUserId = sharedUserId; return this; @@ -148,9 +135,8 @@ class PackageSettingBuilder { final PackageSetting packageSetting = new PackageSetting(mName, mRealName, new File(mCodePath), new File(mResourcePath), mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString, - mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mParentPackageName, - mChildPackageNames, mSharedUserId, mUsesStaticLibraries, - mUsesStaticLibrariesVersions); + mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mSharedUserId, + mUsesStaticLibraries, mUsesStaticLibrariesVersions); packageSetting.pkg = mPkg; packageSetting.volumeUuid = this.mVolumeUuid; for (int i = 0; i < mUserStates.size(); i++) { diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java index d3a77d3e80f1..04e769d7dcfb 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java @@ -16,8 +16,8 @@ package com.android.server.pm; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -467,8 +467,7 @@ public class PackageSignaturesTest { File appPath = new File("/data/app/app"); PackageSetting result = new PackageSetting("test.app", null, appPath, appPath, "/data/app/app", null, null, null, - 1, 940097092, 0, null, - null, 0 /*userId*/, null, null); + 1, 940097092, 0, 0 /*userId*/, null, null); return result; } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java index 41489dc42a6a..a0efc8a03719 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ParallelPackageParserTest.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.content.pm.PackageParser; +import android.content.pm.parsing.ParsedPackage; import android.util.Log; import androidx.test.runner.AndroidJUnit4; @@ -74,7 +75,7 @@ public class ParallelPackageParserTest { } @Override - protected PackageParser.Package parsePackage(PackageParser packageParser, File scanFile, + protected ParsedPackage parsePackage(PackageParser packageParser, File scanFile, int parseFlags) throws PackageParser.PackageParserException { // Do not actually parse the package for testing return null; diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java index 34a3f860496a..11f154be688b 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanRequestBuilder.java @@ -16,12 +16,13 @@ package com.android.server.pm; -import android.content.pm.PackageParser; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.ParsedPackage; import android.os.UserHandle; class ScanRequestBuilder { - private final PackageParser.Package mPkg; - private PackageParser.Package mOldPkg; + private final ParsedPackage mPkg; + private AndroidPackage mOldPkg; private SharedUserSetting mSharedUserSetting; private PackageSetting mPkgSetting; private PackageSetting mDisabledPkgSetting; @@ -32,11 +33,11 @@ class ScanRequestBuilder { private UserHandle mUser; private boolean mIsPlatformPackage; - ScanRequestBuilder(PackageParser.Package pkg) { + ScanRequestBuilder(ParsedPackage pkg) { this.mPkg = pkg; } - public ScanRequestBuilder setOldPkg(PackageParser.Package oldPkg) { + public ScanRequestBuilder setOldPkg(AndroidPackage oldPkg) { this.mOldPkg = oldPkg; return this; } diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java index 05905d94dda7..1f027a31fbe3 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java @@ -35,13 +35,17 @@ import static org.junit.Assert.assertNotSame; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.Manifest; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; -import android.content.pm.PackageParser; import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackage; +import android.content.res.TypedArray; import android.os.Environment; import android.os.UserHandle; import android.os.UserManagerInternal; @@ -58,6 +62,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.io.File; +import java.util.UUID; @RunWith(MockitoJUnitRunner.class) @Presubmit @@ -66,6 +71,9 @@ public class ScanTests { private static final String DUMMY_PACKAGE_NAME = "some.app.to.test"; + private static final UUID UUID_ONE = UUID.randomUUID(); + private static final UUID UUID_TWO = UUID.randomUUID(); + @Mock PackageAbiHelper mMockPackageAbiHelper; @Mock @@ -87,25 +95,25 @@ public class ScanTests { @Before public void setupDefaultAbiBehavior() throws Exception { when(mMockPackageAbiHelper.derivePackageAbi( - any(PackageParser.Package.class), nullable(String.class), anyBoolean())) + any(ParsedPackage.class), nullable(String.class), anyBoolean())) .thenReturn(new Pair<>( new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"), new PackageAbiHelper.NativeLibraryPaths( "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2"))); when(mMockPackageAbiHelper.getNativeLibraryPaths( - any(PackageParser.Package.class), any(File.class))) + any(ParsedPackage.class), any(File.class))) .thenReturn(new PackageAbiHelper.NativeLibraryPaths( "getRootDir", true, "getNativeDir", "getNativeDir2" )); when(mMockPackageAbiHelper.getBundledAppAbis( - any(PackageParser.Package.class))) + any(ParsedPackage.class))) .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary")); } @Test public void newInstallSimpleAllNominal() throws Exception { final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL) .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP) .build(); @@ -123,7 +131,7 @@ public class ScanTests { when(mMockUserManager.getUserIds()).thenReturn(userIds); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setRealPkgName(null) .addScanFlag(PackageManagerService.SCAN_NEW_INSTALL) .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP) @@ -138,7 +146,7 @@ public class ScanTests { @Test public void installRealPackageName() throws Exception { final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setRealPkgName("com.package.real") .build(); @@ -149,7 +157,7 @@ public class ScanTests { final PackageManagerService.ScanRequest scanRequestNoRealPkg = createBasicScanRequestBuilder( createBasicPackage(DUMMY_PACKAGE_NAME) - .setRealPackageName("com.package.real").build()) + .setRealPackage("com.package.real")) .build(); final PackageManagerService.ScanResult scanResultNoReal = executeScan(scanRequestNoRealPkg); @@ -165,7 +173,7 @@ public class ScanTests { .setSecondaryCpuAbiString("secondaryCpuAbi") .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP) .setPkgSetting(pkgSetting) .build(); @@ -197,7 +205,7 @@ public class ScanTests { .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setPkgSetting(existingPkgSetting) .build(); @@ -209,17 +217,18 @@ public class ScanTests { @Test public void installStaticSharedLibrary() throws Exception { - final PackageParser.Package pkg = createBasicPackage("static.lib.pkg.123") - .setStaticSharedLib("static.lib", 123L) - .setManifestPackageName("static.lib.pkg") + final ParsedPackage pkg = createBasicPackage("static.lib.pkg") + .setStaticSharedLibName("static.lib") + .setStaticSharedLibVersion(123L) + .hideAsParsed() + .setPackageName("static.lib.pkg.123") .setVersionCodeMajor(1) .setVersionCode(234) .setBaseCodePath("/some/path.apk") - .addSplitCodePath("/some/other/path.apk") - .build(); + .setSplitCodePaths(new String[] {"/some/other/path.apk"}); - final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder( - pkg).setUser(UserHandle.of(0)).build(); + final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg) + .setUser(UserHandle.of(0)).build(); final PackageManagerService.ScanResult scanResult = executeScan(scanRequest); @@ -240,15 +249,14 @@ public class ScanTests { @Test public void installDynamicLibraries() throws Exception { - final PackageParser.Package pkg = createBasicPackage("dynamic.lib.pkg") - .setManifestPackageName("dynamic.lib.pkg") + final ParsedPackage pkg = createBasicPackage("dynamic.lib.pkg") .addLibraryName("liba") .addLibraryName("libb") + .hideAsParsed() .setVersionCodeMajor(1) .setVersionCode(234) .setBaseCodePath("/some/path.apk") - .addSplitCodePath("/some/other/path.apk") - .build(); + .setSplitCodePaths(new String[] {"/some/other/path.apk"}); final PackageManagerService.ScanRequest scanRequest = new ScanRequestBuilder(pkg).setUser(UserHandle.of(0)).build(); @@ -290,15 +298,15 @@ public class ScanTests { .setVolumeUuid("someUuid") .build(); - final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .setApplicationInfoVolumeUuid("someNewUuid") - .build(); + final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) + .hideAsParsed() + .setApplicationVolumeUuid(UUID_TWO.toString()); final PackageManagerService.ScanResult scanResult = executeScan( new ScanRequestBuilder(basicPackage).setPkgSetting(pkgSetting).build()); - assertThat(scanResult.pkgSetting.volumeUuid, is("someNewUuid")); + assertThat(scanResult.pkgSetting.volumeUuid, is(UUID_TWO.toString())); } @Test @@ -306,10 +314,10 @@ public class ScanTests { final PackageSetting pkgSetting = createBasicPackageSettingBuilder(DUMMY_PACKAGE_NAME).build(); - final PackageParser.Package basicPackage = + final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .setCpuAbiOVerride("testOverride") - .build(); + .hideAsParsed() + .setCpuAbiOverride("testOverride"); final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder( @@ -326,9 +334,9 @@ public class ScanTests { final PackageSetting originalPkgSetting = createBasicPackageSettingBuilder("original.package").build(); - final PackageParser.Package basicPackage = + final ParsedPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .build(); + .hideAsParsed(); final PackageManagerService.ScanResult result = @@ -336,7 +344,7 @@ public class ScanTests { .setOriginalPkgSetting(originalPkgSetting) .build()); - assertThat(result.request.pkg.packageName, is("original.package")); + assertThat(result.request.parsedPackage.getPackageName(), is("original.package")); } @Test @@ -349,7 +357,7 @@ public class ScanTests { .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setPkgSetting(existingPkgSetting) .addScanFlag(SCAN_AS_FULL_APP) .build(); @@ -370,7 +378,7 @@ public class ScanTests { .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setPkgSetting(existingPkgSetting) .addScanFlag(SCAN_AS_INSTANT_APP) .build(); @@ -389,7 +397,7 @@ public class ScanTests { .build(); final PackageManagerService.ScanRequest scanRequest = - createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME).build()) + createBasicScanRequestBuilder(createBasicPackage(DUMMY_PACKAGE_NAME)) .setPkgSetting(existingPkgSetting) .setDisabledPkgSetting(existingPkgSetting) .addScanFlag(SCAN_NEW_INSTALL) @@ -397,15 +405,14 @@ public class ScanTests { final PackageManagerService.ScanResult scanResult = executeScan(scanRequest); - assertThat(scanResult.request.pkg.applicationInfo.flags, + assertThat(scanResult.request.parsedPackage.getFlags(), hasFlag(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)); } @Test public void factoryTestFlagSet() throws Exception { - final PackageParser.Package basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) - .addPermissionRequest(Manifest.permission.FACTORY_TEST) - .build(); + final ParsingPackage basicPackage = createBasicPackage(DUMMY_PACKAGE_NAME) + .addRequestedPermission(Manifest.permission.FACTORY_TEST); final PackageManagerService.ScanResult scanResult = PackageManagerService.scanPackageOnlyLI( createBasicScanRequestBuilder(basicPackage).build(), @@ -413,15 +420,15 @@ public class ScanTests { true /*isUnderFactoryTest*/, System.currentTimeMillis()); - assertThat(scanResult.request.pkg.applicationInfo.flags, + assertThat(scanResult.request.parsedPackage.getFlags(), hasFlag(ApplicationInfo.FLAG_FACTORY_TEST)); } @Test public void scanSystemApp_isOrphanedTrue() throws Exception { - final PackageParser.Package pkg = createBasicPackage(DUMMY_PACKAGE_NAME) - .addApplicationInfoFlag(ApplicationInfo.FLAG_SYSTEM) - .build(); + final ParsedPackage pkg = createBasicPackage(DUMMY_PACKAGE_NAME) + .hideAsParsed() + .setSystem(true); final PackageManagerService.ScanRequest scanRequest = createBasicScanRequestBuilder(pkg) @@ -476,22 +483,29 @@ public class ScanTests { .setResourcePath(createResourcePath(packageName)); } - private static ScanRequestBuilder createBasicScanRequestBuilder(PackageParser.Package pkg) { - return new ScanRequestBuilder(pkg) + private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) { + return new ScanRequestBuilder(pkg.hideAsParsed()) .setUser(UserHandle.of(0)); } + private static ScanRequestBuilder createBasicScanRequestBuilder(ParsedPackage pkg) { + return new ScanRequestBuilder(pkg) + .setUser(UserHandle.of(0)); + } - private static PackageBuilder createBasicPackage(String packageName) { - return new PackageBuilder(packageName) + private static ParsingPackage createBasicPackage(String packageName) { + // TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps + return new PackageImpl(packageName, null, mock(TypedArray.class), false) .setCodePath("/data/tmp/randompath") .setApplicationInfoCodePath(createCodePath(packageName)) .setApplicationInfoResourcePath(createResourcePath(packageName)) - .setApplicationInfoVolumeUuid("volumeUuid") + .setApplicationVolumeUuid(UUID_ONE.toString()) .setBaseCodePath("/data/tmp/randompath/base.apk") - .addUsesStaticLibrary("some.static.library", 234L) - .addUsesStaticLibrary("some.other.static.library", 456L) - .setApplicationInfoNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib") + .addUsesStaticLibrary("some.static.library") + .addUsesStaticLibraryVersion(234L) + .addUsesStaticLibrary("some.other.static.library") + .addUsesStaticLibraryVersion(456L) + .setNativeLibraryRootDir("/data/tmp/randompath/base.apk:/lib") .setVersionCodeMajor(1) .setVersionCode(2345); } @@ -503,20 +517,18 @@ public class ScanTests { final PackageSetting pkgSetting = scanResult.pkgSetting; assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting); - final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo; + final ApplicationInfo applicationInfo = pkgSetting.pkg.toAppInfo(); assertBasicApplicationInfo(scanResult, applicationInfo); - } private static void assertBasicPackageSetting(PackageManagerService.ScanResult scanResult, String packageName, boolean isInstant, PackageSetting pkgSetting) { - assertThat(pkgSetting.pkg.packageName, is(packageName)); + assertThat(pkgSetting.pkg.getPackageName(), is(packageName)); assertThat(pkgSetting.getInstantApp(0), is(isInstant)); assertThat(pkgSetting.usesStaticLibraries, arrayContaining("some.static.library", "some.other.static.library")); assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L})); - assertThat(pkgSetting.pkg, is(scanResult.request.pkg)); - assertThat(pkgSetting.pkg.mExtras, is(pkgSetting)); + assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage)); assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName)))); assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName)))); assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345))); @@ -524,20 +536,21 @@ public class ScanTests { private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult, ApplicationInfo applicationInfo) { - assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName)); + assertThat(applicationInfo.processName, + is(scanResult.request.parsedPackage.getPackageName())); final int uid = applicationInfo.uid; assertThat(UserHandle.getUserId(uid), is(UserHandle.USER_SYSTEM)); final String calculatedCredentialId = Environment.getDataUserCePackageDirectory( applicationInfo.volumeUuid, UserHandle.USER_SYSTEM, - scanResult.request.pkg.packageName).getAbsolutePath(); + scanResult.request.parsedPackage.getPackageName()).getAbsolutePath(); assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId)); assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir)); } private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) { - final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo; + final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.toAppInfo(); assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary")); assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary")); @@ -549,7 +562,7 @@ public class ScanTests { } private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) { - final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo; + final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.toAppInfo(); assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir")); assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir")); assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true)); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java index f0b0328ff7d4..ddda10ec19d5 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java @@ -37,8 +37,9 @@ import static org.junit.Assert.fail; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageParser; import android.content.pm.UserInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; import android.os.Looper; import android.os.SystemProperties; import android.os.UserManager; @@ -220,10 +221,10 @@ public class UserSystemPackageInstallerTest { final UserSystemPackageInstaller uspi = new UserSystemPackageInstaller(null, pkgFlgMap); - final PackageParser.Package pkg1 = new PackageParser.Package(packageName1); - final PackageParser.Package pkg2 = new PackageParser.Package(packageName2); - final PackageParser.Package pkg3 = new PackageParser.Package(packageName3); - final PackageParser.Package pkg4 = new PackageParser.Package(packageName4); + final AndroidPackage pkg1 = PackageImpl.forParsing(packageName1).hideAsParsed().hideAsFinal(); + final AndroidPackage pkg2 = PackageImpl.forParsing(packageName2).hideAsParsed().hideAsFinal(); + final AndroidPackage pkg3 = PackageImpl.forParsing(packageName3).hideAsParsed().hideAsFinal(); + final AndroidPackage pkg4 = PackageImpl.forParsing(packageName4).hideAsParsed().hideAsFinal(); // No implicit whitelist, so only install pkg1. boolean implicit = false; diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java index 3a55c2290157..66a4946ecc20 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java @@ -22,8 +22,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import android.content.pm.ApplicationInfo; import android.content.pm.SharedLibraryInfo; +import android.content.pm.parsing.AndroidPackage; +import android.content.pm.parsing.PackageImpl; +import android.content.pm.parsing.ParsedPackage; +import android.content.pm.parsing.ParsingPackage; import android.util.SparseArray; import androidx.test.filters.SmallTest; @@ -51,17 +54,18 @@ public class DexoptUtilsTest { DelegateLastClassLoader.class.getName(); private static class TestData { - ApplicationInfo info; + AndroidPackage pkg; boolean[] pathsWithCode; } private TestData createMockApplicationInfo(String baseClassLoader, boolean addSplits, - boolean addSplitDependencies) { - ApplicationInfo ai = new ApplicationInfo(); + boolean addSplitDependencies, boolean isolatedSplitLoading) { String codeDir = "/data/app/mock.android.com"; - ai.setBaseCodePath(codeDir + "/base.dex"); - ai.classLoaderName = baseClassLoader; - ai.privateFlags = ai.privateFlags | ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING; + ParsingPackage parsingPackage = PackageImpl.forParsing("mock.android.com") + .setClassLoaderName(baseClassLoader); + + parsingPackage.setIsolatedSplitLoading(isolatedSplitLoading); + boolean[] pathsWithCode; if (!addSplits) { pathsWithCode = new boolean[] {true}; @@ -70,7 +74,7 @@ public class DexoptUtilsTest { Arrays.fill(pathsWithCode, true); pathsWithCode[7] = false; // config split - ai.setSplitCodePaths(new String[]{ + String[] splitCodePaths = new String[]{ codeDir + "/base-1.dex", codeDir + "/base-2.dex", codeDir + "/base-3.dex", @@ -78,32 +82,51 @@ public class DexoptUtilsTest { codeDir + "/base-5.dex", codeDir + "/base-6.dex", codeDir + "/config-split-7.dex", - codeDir + "/feature-no-deps.dex"}); - - ai.splitClassLoaderNames = new String[]{ - DELEGATE_LAST_CLASS_LOADER_NAME, - DELEGATE_LAST_CLASS_LOADER_NAME, - PATH_CLASS_LOADER_NAME, - DEX_CLASS_LOADER_NAME, - PATH_CLASS_LOADER_NAME, - null, // A null class loader name should default to PathClassLoader. - null, // The config split gets a null class loader. - null}; // The feature split with no dependency and no specified class loader. + codeDir + "/feature-no-deps.dex" + }; + + String[] splitNames = new String[splitCodePaths.length]; + int[] splitRevisionCodes = new int[splitCodePaths.length]; + SparseArray<int[]> splitDependencies = null; + if (addSplitDependencies) { - ai.splitDependencies = new SparseArray<>(ai.splitClassLoaderNames.length + 1); - ai.splitDependencies.put(0, new int[] {-1}); // base has no dependency - ai.splitDependencies.put(1, new int[] {2}); // split 1 depends on 2 - ai.splitDependencies.put(2, new int[] {4}); // split 2 depends on 4 - ai.splitDependencies.put(3, new int[] {4}); // split 3 depends on 4 - ai.splitDependencies.put(4, new int[] {0}); // split 4 depends on base - ai.splitDependencies.put(5, new int[] {0}); // split 5 depends on base - ai.splitDependencies.put(6, new int[] {5}); // split 6 depends on 5 + splitDependencies = new SparseArray<>(splitCodePaths.length); + splitDependencies.put(0, new int[] {-1}); // base has no dependency + splitDependencies.put(1, new int[] {2}); // split 1 depends on 2 + splitDependencies.put(2, new int[] {4}); // split 2 depends on 4 + splitDependencies.put(3, new int[] {4}); // split 3 depends on 4 + splitDependencies.put(4, new int[] {0}); // split 4 depends on base + splitDependencies.put(5, new int[] {0}); // split 5 depends on base + splitDependencies.put(6, new int[] {5}); // split 6 depends on 5 // Do not add the config split to the dependency list. // Do not add the feature split with no dependency to the dependency list. } + + parsingPackage + .asSplit( + splitNames, + splitCodePaths, + splitRevisionCodes, + splitDependencies + ) + .setSplitClassLoaderName(0, DELEGATE_LAST_CLASS_LOADER_NAME) + .setSplitClassLoaderName(1, DELEGATE_LAST_CLASS_LOADER_NAME) + .setSplitClassLoaderName(2, PATH_CLASS_LOADER_NAME) + .setSplitClassLoaderName(3, DEX_CLASS_LOADER_NAME) + .setSplitClassLoaderName(4, PATH_CLASS_LOADER_NAME) + // A null class loader name should default to PathClassLoader + .setSplitClassLoaderName(5, null) + // The config split gets a null class loader + .setSplitClassLoaderName(6, null) + // The feature split with no dependency and no specified class loader. + .setSplitClassLoaderName(7, null); } + + ParsedPackage parsedPackage = parsingPackage.hideAsParsed() + .setBaseCodePath(codeDir + "/base.dex"); + TestData data = new TestData(); - data.info = ai; + data.pkg = parsedPackage.hideAsFinal(); data.pathsWithCode = pathsWithCode; return data; } @@ -118,11 +141,11 @@ public class DexoptUtilsTest { @Test public void testSplitChain() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -139,11 +162,11 @@ public class DexoptUtilsTest { @Test public void testSplitChainNoSplitDependencies() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -167,11 +190,9 @@ public class DexoptUtilsTest { @Test public void testSplitChainNoIsolationNoSharedLibrary() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true); - data.info.privateFlags = data.info.privateFlags - & (~ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true, false); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, null, data.pathsWithCode); + data.pkg, null, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("PCL[]", contexts[0]); @@ -192,9 +213,9 @@ public class DexoptUtilsTest { @Test public void testSplitChainNoSharedLibraries() { TestData data = createMockApplicationInfo( - DELEGATE_LAST_CLASS_LOADER_NAME, true, true); + DELEGATE_LAST_CLASS_LOADER_NAME, true, true, true); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, null, data.pathsWithCode); + data.pkg, null, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("DLC[]", contexts[0]); @@ -211,11 +232,11 @@ public class DexoptUtilsTest { @Test public void testSplitChainWithNullPrimaryClassLoader() { // A null classLoaderName should mean PathClassLoader. - TestData data = createMockApplicationInfo(null, true, true); + TestData data = createMockApplicationInfo(null, true, true, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -233,11 +254,11 @@ public class DexoptUtilsTest { @Test public void tesNoSplits() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -245,11 +266,11 @@ public class DexoptUtilsTest { @Test public void tesNoSplitsNullClassLoaderName() { - TestData data = createMockApplicationInfo(null, false, false); + TestData data = createMockApplicationInfo(null, false, false, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -258,11 +279,11 @@ public class DexoptUtilsTest { @Test public void tesNoSplitDelegateLast() { TestData data = createMockApplicationInfo( - DELEGATE_LAST_CLASS_LOADER_NAME, false, false); + DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("DLC[]{PCL[a.dex:b.dex]}", contexts[0]); @@ -270,9 +291,9 @@ public class DexoptUtilsTest { @Test public void tesNoSplitsNoSharedLibraries() { - TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false); + TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false, true); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, null, data.pathsWithCode); + data.pkg, null, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("PCL[]", contexts[0]); @@ -281,9 +302,9 @@ public class DexoptUtilsTest { @Test public void tesNoSplitDelegateLastNoSharedLibraries() { TestData data = createMockApplicationInfo( - DELEGATE_LAST_CLASS_LOADER_NAME, false, false); + DELEGATE_LAST_CLASS_LOADER_NAME, false, false, true); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, null, data.pathsWithCode); + data.pkg, null, data.pathsWithCode); assertEquals(1, contexts.length); assertEquals("DLC[]", contexts[0]); @@ -291,13 +312,13 @@ public class DexoptUtilsTest { @Test public void testContextWithNoCode() { - TestData data = createMockApplicationInfo(null, true, false); + TestData data = createMockApplicationInfo(null, true, false, true); Arrays.fill(data.pathsWithCode, false); List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals(null, contexts[0]); @@ -312,12 +333,12 @@ public class DexoptUtilsTest { @Test public void testContextBaseNoCode() { - TestData data = createMockApplicationInfo(null, true, true); + TestData data = createMockApplicationInfo(null, true, true, true); data.pathsWithCode[0] = false; List<SharedLibraryInfo> sharedLibrary = createMockSharedLibrary(new String[] {"a.dex", "b.dex"}); String[] contexts = DexoptUtils.getClassLoaderContexts( - data.info, sharedLibrary, data.pathsWithCode); + data.pkg, sharedLibrary, data.pathsWithCode); assertEquals(9, contexts.length); assertEquals(null, contexts[0]); diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java index 0b8c2a55b45e..0c5451f4ec31 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java @@ -16,7 +16,6 @@ package com.android.server.rollback; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -271,15 +270,4 @@ public class AppDataRollbackHelperTest { inOrder.verifyNoMoreInteractions(); } - - @Test - public void snapshotAddDataSavesSnapshottedUsersToInfo() { - Installer installer = mock(Installer.class); - AppDataRollbackHelper helper = new AppDataRollbackHelper(installer); - - PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar"); - helper.snapshotAppData(5, info, new int[]{10, 11}); - - assertArrayEquals(info.getSnapshottedUsers().toArray(), new int[]{10, 11}); - } } diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java index b5925a6e750f..151b6e2890bb 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java +++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java @@ -18,22 +18,48 @@ package com.android.server.rollback; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.util.IntArray; import android.util.SparseLongArray; +import com.google.common.collect.Range; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.ArgumentMatcher; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.io.File; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @RunWith(JUnit4.class) public class RollbackUnitTest { + private static final String PKG_1 = "test.testpackage.pkg1"; + private static final String PKG_2 = "test.testpackage.pkg2"; + private static final String PKG_3 = "com.blah.hello.three"; + private static final String PKG_4 = "com.something.4pack"; + + @Mock private AppDataRollbackHelper mMockDataHelper; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + @Test public void newEmptyStagedRollbackDefaults() { int rollbackId = 123; @@ -61,82 +87,229 @@ public class RollbackUnitTest { } @Test - public void rollbackStateChanges() { + public void rollbackMadeAvailable() { Rollback rollback = new Rollback(123, new File("/test/testing"), -1); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.isAvailable()).isFalse(); assertThat(rollback.isCommitted()).isFalse(); - rollback.setAvailable(); + Instant availableTime = Instant.now(); + rollback.makeAvailable(); assertThat(rollback.isEnabling()).isFalse(); assertThat(rollback.isAvailable()).isTrue(); assertThat(rollback.isCommitted()).isFalse(); - rollback.setCommitted(); + assertThat(rollback.getTimestamp()).isIn(Range.closed(availableTime, Instant.now())); + } + + @Test + public void deletedRollbackCannotBeMadeAvailable() { + Rollback rollback = new Rollback(123, new File("/test/testing"), -1); + + rollback.delete(mMockDataHelper); + + assertThat(rollback.isDeleted()).isTrue(); + + rollback.makeAvailable(); - assertThat(rollback.isEnabling()).isFalse(); assertThat(rollback.isAvailable()).isFalse(); - assertThat(rollback.isCommitted()).isTrue(); + assertThat(rollback.isDeleted()).isTrue(); } @Test public void getPackageNamesAllAndJustApex() { - String pkg1 = "test.testpackage.pkg1"; - String pkg2 = "test.testpackage.pkg2"; - String pkg3 = "com.blah.hello.three"; - String pkg4 = "com.something.4pack"; - Rollback rollback = new Rollback(123, new File("/test/testing"), -1); - PackageRollbackInfo pkgInfo1 = pkgInfoFor(pkg1, 12, 10, false); - PackageRollbackInfo pkgInfo2 = pkgInfoFor(pkg2, 12, 10, true); - PackageRollbackInfo pkgInfo3 = pkgInfoFor(pkg3, 12, 10, false); - PackageRollbackInfo pkgInfo4 = pkgInfoFor(pkg4, 12, 10, true); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 11, true); + PackageRollbackInfo pkgInfo3 = newPkgInfoFor(PKG_3, 19, 1, false); + PackageRollbackInfo pkgInfo4 = newPkgInfoFor(PKG_4, 12, 1, true); rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2, pkgInfo3, pkgInfo4)); - assertThat(rollback.getPackageNames()).containsExactly(pkg1, pkg2, pkg3, pkg4); - assertThat(rollback.getApexPackageNames()).containsExactly(pkg2, pkg4); + assertThat(rollback.getPackageNames()).containsExactly(PKG_1, PKG_2, PKG_3, PKG_4); + assertThat(rollback.getApexPackageNames()).containsExactly(PKG_2, PKG_4); } @Test - public void includesPackages() { - String pkg1 = "test.testpackage.pkg1"; - String pkg2 = "test.testpackage.pkg2"; - String pkg3 = "com.blah.hello.three"; - String pkg4 = "com.something.4pack"; - + public void includesPackagesAfterEnable() { Rollback rollback = new Rollback(123, new File("/test/testing"), -1); - PackageRollbackInfo pkgInfo1 = pkgInfoFor(pkg1, 12, 10, false); - PackageRollbackInfo pkgInfo2 = pkgInfoFor(pkg2, 18, 12, true); - PackageRollbackInfo pkgInfo3 = pkgInfoFor(pkg3, 157, 156, false); - PackageRollbackInfo pkgInfo4 = pkgInfoFor(pkg4, 99, 1, true); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true); + PackageRollbackInfo pkgInfo3 = newPkgInfoFor(PKG_3, 157, 156, false); + PackageRollbackInfo pkgInfo4 = newPkgInfoFor(PKG_4, 99, 1, true); rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2, pkgInfo3, pkgInfo4)); - assertThat(rollback.includesPackage(pkg2)).isTrue(); - assertThat(rollback.includesPackage(pkg3)).isTrue(); + assertThat(rollback.includesPackage(PKG_2)).isTrue(); + assertThat(rollback.includesPackage(PKG_3)).isTrue(); assertThat(rollback.includesPackage("com.something.else")).isFalse(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg1, 12)).isFalse(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg1, 1)).isTrue(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_1, 12)).isFalse(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_1, 1)).isTrue(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg2, 18)).isFalse(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg2, 12)).isTrue(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_2, 18)).isFalse(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_2, 12)).isTrue(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg3, 157)).isFalse(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg3, 156)).isTrue(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg3, 15)).isTrue(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_3, 157)).isFalse(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_3, 156)).isTrue(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_3, 15)).isTrue(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg4, 99)).isFalse(); - assertThat(rollback.includesPackageWithDifferentVersion(pkg4, 100)).isTrue(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_4, 99)).isFalse(); + assertThat(rollback.includesPackageWithDifferentVersion(PKG_4, 100)).isTrue(); } - private static PackageRollbackInfo pkgInfoFor( + @Test + public void snapshotWhenEnabling() { + Rollback rollback = new Rollback(123, new File("/test/testing"), -1); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true); + rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2)); + + assertThat(rollback.isEnabling()).isTrue(); + + int[] userIds = {4, 77}; + rollback.snapshotUserData(PKG_2, userIds, mMockDataHelper); + + // Data is snapshotted for the specified package. + verify(mMockDataHelper).snapshotAppData(eq(123), pkgRollbackInfoFor(PKG_2), eq(userIds)); + verify(mMockDataHelper, never()) + .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_1), any()); + } + + @Test + public void snapshotWhenAvailable() { + Rollback rollback = new Rollback(123, new File("/test/testing"), -1); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true); + rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2)); + + rollback.makeAvailable(); + + assertThat(rollback.isAvailable()).isTrue(); + + int[] userIds = {4, 77}; + rollback.snapshotUserData(PKG_2, userIds, mMockDataHelper); + + // No data is snapshotted as rollback was not in the enabling state. + verify(mMockDataHelper, never()) + .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_1), any()); + verify(mMockDataHelper, never()) + .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_2), any()); + } + + @Test + public void snapshotWhenDeleted() { + Rollback rollback = new Rollback(123, new File("/test/testing"), -1); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true); + rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2)); + + rollback.delete(mMockDataHelper); + + assertThat(rollback.isDeleted()).isTrue(); + + int[] userIds = {4, 77}; + rollback.snapshotUserData(PKG_2, userIds, mMockDataHelper); + + // No data is snapshotted as rollback was not in the enabling state. + verify(mMockDataHelper, never()) + .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_1), any()); + verify(mMockDataHelper, never()) + .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_2), any()); + } + + @Test + public void snapshotThenDelete() { + Rollback rollback = new Rollback(123, new File("/test/testing"), -1); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true); + rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2)); + + int[] userIds = {12, 18}; + rollback.snapshotUserData(PKG_2, userIds, mMockDataHelper); + + verify(mMockDataHelper).snapshotAppData(eq(123), pkgRollbackInfoFor(PKG_2), eq(userIds)); + + rollback.delete(mMockDataHelper); + + verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(12)); + verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(18)); + + assertThat(rollback.isDeleted()).isTrue(); + } + + @Test + public void restoreUserDataDoesNothingIfNotInProgress() { + Rollback rollback = new Rollback(123, new File("/test/testing"), -1); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true); + rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2)); + + assertThat(rollback.isRestoreUserDataInProgress()).isFalse(); + + assertThat(rollback.restoreUserDataForPackageIfInProgress( + PKG_1, new int[] { 5 }, 333, "", mMockDataHelper)).isFalse(); + + verify(mMockDataHelper, never()).restoreAppData(anyInt(), any(), anyInt(), anyInt(), any()); + } + + @Test + public void restoreUserDataDoesNothingIfPackageNotFound() { + Rollback rollback = new Rollback(123, new File("/test/testing"), -1); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true); + rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2)); + + rollback.setRestoreUserDataInProgress(true); + assertThat(rollback.isRestoreUserDataInProgress()).isTrue(); + + assertThat(rollback.restoreUserDataForPackageIfInProgress( + PKG_3, new int[] { 5 }, 333, "", mMockDataHelper)).isFalse(); + + verify(mMockDataHelper, never()).restoreAppData(anyInt(), any(), anyInt(), anyInt(), any()); + } + + @Test + public void restoreUserDataRestoresIfInProgressAndPackageFound() { + Rollback rollback = new Rollback(123, new File("/test/testing"), -1); + PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false); + PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true); + rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2)); + + rollback.setRestoreUserDataInProgress(true); + assertThat(rollback.isRestoreUserDataInProgress()).isTrue(); + + assertThat(rollback.restoreUserDataForPackageIfInProgress( + PKG_1, new int[] { 5, 7 }, 333, "blah", mMockDataHelper)).isTrue(); + + verify(mMockDataHelper).restoreAppData(123, pkgInfo1, 5, 333, "blah"); + verify(mMockDataHelper).restoreAppData(123, pkgInfo1, 7, 333, "blah"); + } + + private static PackageRollbackInfo newPkgInfoFor( String packageName, long fromVersion, long toVersion, boolean isApex) { return new PackageRollbackInfo(new VersionedPackage(packageName, fromVersion), new VersionedPackage(packageName, toVersion), new IntArray(), new ArrayList<>(), isApex, new IntArray(), new SparseLongArray()); } + + private static class PackageRollbackInfoForPackage implements + ArgumentMatcher<PackageRollbackInfo> { + private final String mPkg; + + PackageRollbackInfoForPackage(String pkg) { + mPkg = pkg; + } + + @Override + public boolean matches(PackageRollbackInfo pkgRollbackInfo) { + return pkgRollbackInfo.getPackageName().equals(mPkg); + } + } + + private static PackageRollbackInfo pkgRollbackInfoFor(String pkg) { + return argThat(new PackageRollbackInfoForPackage(pkg)); + } } diff --git a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java index dd2ee5cce13b..d1ac19c540a4 100644 --- a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java +++ b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java @@ -15,6 +15,7 @@ */ package com.android.server.stats; +import static com.android.server.stats.ProcfsMemoryUtil.parseCmdline; import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus; import static com.google.common.truth.Truth.assertThat; @@ -25,6 +26,8 @@ import com.android.server.stats.ProcfsMemoryUtil.MemorySnapshot; import org.junit.Test; +import java.io.ByteArrayOutputStream; + /** * Build/Install/Run: * atest FrameworksServicesTests:ProcfsMemoryUtilTest @@ -100,4 +103,39 @@ public class ProcfsMemoryUtilTest { MemorySnapshot snapshot = parseMemorySnapshotFromStatus(""); assertThat(snapshot).isNull(); } + + @Test + public void testParseCmdline_invalidValue() { + byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test + + assertThat(parseCmdline(bytesToString(nothing))).isEmpty(); + } + + @Test + public void testParseCmdline_correctValue_noNullBytes() { + assertThat(parseCmdline("com.google.app")).isEqualTo("com.google.app"); + } + + @Test + public void testParseCmdline_correctValue_withNullBytes() { + byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0 + + assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test"); + + // test\0\0test + byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74}; + + assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test"); + } + + @Test + public void testParseCmdline_emptyContents() { + assertThat(parseCmdline("")).isEmpty(); + } + + private static String bytesToString(byte[] bytes) { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + output.write(bytes, 0, bytes.length); + return output.toString(); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 0110e94eb1cd..bb80e5e4ddde 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -20,9 +20,11 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -124,6 +126,7 @@ public class DragDropControllerTests extends WindowTestsBase { mDisplayContent = spy(mDisplayContent); mWindow = createDropTargetWindow("Drag test window", 0); doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0); + when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true); synchronized (mWm.mGlobalLock) { mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow); @@ -177,6 +180,7 @@ public class DragDropControllerTests extends WindowTestsBase { .setFormat(PixelFormat.TRANSLUCENT) .build(); + assertTrue(mWm.mInputManager.transferTouchFocus(null, null)); mToken = mTarget.performDrag( new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0, data); diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java index 8d2a79b6b5db..2ad40f2dc577 100644 --- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java +++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java @@ -97,11 +97,6 @@ public class StubTransaction extends SurfaceControl.Transaction { } @Override - public SurfaceControl.Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) { - return this; - } - - @Override public SurfaceControl.Transaction setGeometry(SurfaceControl sc, Rect sourceCrop, Rect destFrame, @Surface.Rotation int orientation) { return this; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java index 714d2f2f94a1..eb351b63a469 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -57,6 +58,10 @@ public class TaskPositioningControllerTests extends WindowTestsBase { assertNotNull(mWm.mTaskPositioningController); mTarget = mWm.mTaskPositioningController; + when(mWm.mInputManager.transferTouchFocus( + any(InputChannel.class), + any(InputChannel.class))).thenReturn(true); + mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window"); mWindow.mInputChannel = new InputChannel(); synchronized (mWm.mGlobalLock) { diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp index 3c916a6d00cd..608fc2c7a55e 100644 --- a/services/wifi/Android.bp +++ b/services/wifi/Android.bp @@ -5,6 +5,9 @@ java_library_static { "java/**/*.java", "java/**/*.aidl", ], + aidl: { + local_include_dirs: ["java"] + }, libs: [ "services.net", ], diff --git a/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl b/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl index eadc7260e81b..3af4666b8d9c 100644 --- a/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl +++ b/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl @@ -15,8 +15,9 @@ */ package android.net.wifi; +import android.net.wifi.WifiApiServiceInfo; + /** @hide */ interface IWifiStackConnector { - IBinder retrieveApiServiceImpl(String serviceName); - boolean startApiService(String serviceName); + List<WifiApiServiceInfo> getWifiApiServiceInfos(); } diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java b/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl index 10d0551a3a6f..45e4c69102f0 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java +++ b/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 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. @@ -12,13 +12,12 @@ * 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 com.android.frameworks.coretests; - -import android.app.Activity; - -public class TestActivity extends Activity { +package android.net.wifi; +/** @hide */ +parcelable WifiApiServiceInfo { + String name; + IBinder binder; } diff --git a/services/wifi/java/android/net/wifi/WifiStackClient.java b/services/wifi/java/android/net/wifi/WifiStackClient.java index 64af7a8845a7..dcdfbc54687c 100644 --- a/services/wifi/java/android/net/wifi/WifiStackClient.java +++ b/services/wifi/java/android/net/wifi/WifiStackClient.java @@ -21,12 +21,13 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityModuleConnector; -import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import java.util.List; + /** * Service used to communicate with the wifi stack, which could be running in a separate * module. @@ -56,21 +57,23 @@ public class WifiStackClient { @Override public void onModuleServiceConnected(IBinder service) { Log.i(TAG, "Wifi stack connected"); + registerWifiStackService(service); + + IWifiStackConnector connector = IWifiStackConnector.Stub.asInterface(service); - // spin up a new thread to not block system_server main thread - HandlerThread thread = new HandlerThread("InitWifiServicesThread"); - thread.start(); - thread.getThreadHandler().post(() -> { - registerWifiStackService(service); - IWifiStackConnector connector = IWifiStackConnector.Stub.asInterface(service); - registerApiServiceAndStart(connector, Context.WIFI_SCANNING_SERVICE); - registerApiServiceAndStart(connector, Context.WIFI_SERVICE); - registerApiServiceAndStart(connector, Context.WIFI_P2P_SERVICE); - registerApiServiceAndStart(connector, Context.WIFI_AWARE_SERVICE); - registerApiServiceAndStart(connector, Context.WIFI_RTT_RANGING_SERVICE); + List<WifiApiServiceInfo> wifiApiServiceInfos; + try { + wifiApiServiceInfos = connector.getWifiApiServiceInfos(); + } catch (RemoteException e) { + throw new RuntimeException("Failed to getWifiApiServiceInfos()", e); + } - thread.quitSafely(); - }); + for (WifiApiServiceInfo wifiApiServiceInfo : wifiApiServiceInfos) { + String serviceName = wifiApiServiceInfo.name; + IBinder binder = wifiApiServiceInfo.binder; + Log.i(TAG, "Registering " + serviceName); + ServiceManager.addService(serviceName, binder); + } } } @@ -81,32 +84,6 @@ public class WifiStackClient { Log.i(TAG, "Wifi stack service registered"); } - private void registerApiServiceAndStart( - IWifiStackConnector stackConnector, String serviceName) { - IBinder service = null; - try { - service = stackConnector.retrieveApiServiceImpl(serviceName); - } catch (RemoteException e) { - throw new RuntimeException("Failed to retrieve service impl " + serviceName, e); - } - if (service == null) { - Log.i(TAG, "Service " + serviceName + " not available"); - return; - } - Log.i(TAG, "Registering " + serviceName); - ServiceManager.addService(serviceName, service); - - boolean success = false; - try { - success = stackConnector.startApiService(serviceName); - } catch (RemoteException e) { - throw new RuntimeException("Failed to start service " + serviceName, e); - } - if (!success) { - throw new RuntimeException("Service " + serviceName + " start failed"); - } - } - /** * Start the wifi stack. Should be called only once on device startup. * diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 4fcda4d00883..704749844c19 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -302,6 +302,11 @@ interface ITelecomService { void setTestAutoModeApp(String packageName); /** + * @see TelecomServiceImpl#setSystemDialerPackage + */ + void setSystemDialerPackage(in String packageName); + + /** * @see TelecomServiceImpl#setTestDefaultDialer */ void setTestDefaultDialer(in String packageName); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index b4495787bb80..1d5c18d6aae3 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1739,9 +1739,8 @@ public class CarrierConfigManager { "allow_emergency_video_calls_bool"; /** - * Flag indicating whether the carrier supports RCS presence indication for video calls. When - * {@code true}, the carrier supports RCS presence indication for video calls. When presence - * is supported, the device should use the + * Flag indicating whether the carrier supports RCS presence indication for + * User Capability Exchange (UCE). When presence is supported, the device should use the * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit to indicate * whether each contact supports video calling. The UI is made aware that presence is enabled @@ -1752,6 +1751,12 @@ public class CarrierConfigManager { public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool"; /** + * Flag indicating whether the carrier supports RCS SIP OPTIONS indication for + * User Capability Exchange (UCE). + */ + public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool"; + + /** * The duration in seconds that platform call and message blocking is disabled after the user * contacts emergency services. Platform considers values for below cases: * 1) 0 <= VALUE <= 604800(one week): the value will be used as the duration directly. @@ -3435,6 +3440,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true); sDefaults.putInt(KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT, 0); sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false); + sDefaults.putBoolean(KEY_USE_RCS_SIP_OPTIONS_BOOL, false); sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false); sDefaults.putInt( KEY_CDMA_ROAMING_MODE_INT, TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT); diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 1ffed2543ee4..1e1e3daff3ec 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Build; @@ -366,6 +367,7 @@ public class PhoneStateListener { * @hide */ @SystemApi + @TestApi @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER = 0x10000000; @@ -378,6 +380,7 @@ public class PhoneStateListener { * @hide */ @SystemApi + @TestApi @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER = 0x20000000; @@ -869,6 +872,7 @@ public class PhoneStateListener { * to. * @hide */ + @SystemApi public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber) { // default implementation empty } @@ -879,6 +883,7 @@ public class PhoneStateListener { * @param sentEmergencyNumber the emergency number {@link EmergencyNumber} the SMS is sent to. * @hide */ + @SystemApi public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber) { // default implementation empty } diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index fe76b7c13f12..d7a7af1d530f 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -93,6 +93,10 @@ interface ITelephonyRegistry { void notifyActiveDataSubIdChanged(int activeDataSubId); void notifyRadioPowerStateChanged(in int phoneId, in int subId, in int state); void notifyEmergencyNumberList(in int phoneId, in int subId); + void notifyOutgoingEmergencyCall(in int phoneId, in int subId, + in EmergencyNumber emergencyNumber); + void notifyOutgoingEmergencySms(in int phoneId, in int subId, + in EmergencyNumber emergencyNumber); void notifyCallQualityChanged(in CallQuality callQuality, int phoneId, int subId, int callNetworkType); void notifyImsDisconnectCause(int subId, in ImsReasonInfo imsReasonInfo); diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java new file mode 100644 index 000000000000..022f798e82f5 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 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 com.android.server.wm.flicker; + +import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.LargeTest; + +import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper; + +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; + +/** + * Test IME window closing back to app window transitions. + * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest} + */ +@LargeTest +@RunWith(Parameterized.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class CloseImeAutoOpenWindowToAppTest extends CloseImeWindowToAppTest { + + public CloseImeAutoOpenWindowToAppTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); + + mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation()); + } + + @Before + public void runTransition() { + run(editTextLoseFocusToApp((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation) + .includeJankyRuns().build()); + } + + @FlakyTest(bugId = 141458352) + @Ignore("Waiting bug feedback") + @Test + public void checkVisibility_imeLayerBecomesInvisible() { + super.checkVisibility_imeLayerBecomesInvisible(); + } + + @FlakyTest(bugId = 141458352) + @Ignore("Waiting bug feedback") + @Test + public void checkVisibility_imeAppLayerIsAlwaysVisible() { + super.checkVisibility_imeAppLayerIsAlwaysVisible(); + } + + @FlakyTest(bugId = 141458352) + @Ignore("Waiting bug feedback") + @Test + public void checkVisibility_imeAppWindowIsAlwaysVisible() { + super.checkVisibility_imeAppWindowIsAlwaysVisible(); + } + +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java new file mode 100644 index 000000000000..d6f994b5c0d5 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 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 com.android.server.wm.flicker; + +import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.LargeTest; + +import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper; + +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; + +/** + * Test IME window closing back to app window transitions. + * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest} + */ +@LargeTest +@RunWith(Parameterized.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class CloseImeAutoOpenWindowToHomeTest extends CloseImeWindowToHomeTest { + + public CloseImeAutoOpenWindowToHomeTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); + + mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation()); + } + + @Before + public void runTransition() { + run(editTextLoseFocusToHome((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation) + .includeJankyRuns().build()); + } + + @FlakyTest(bugId = 141458352) + @Ignore("Waiting bug feedback") + @Test + public void checkVisibility_imeWindowBecomesInvisible() { + super.checkVisibility_imeWindowBecomesInvisible(); + } + + @FlakyTest(bugId = 141458352) + @Ignore("Waiting bug feedback") + @Test + public void checkVisibility_imeLayerBecomesInvisible() { + super.checkVisibility_imeLayerBecomesInvisible(); + } +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java index 9deb97726542..28da3af2b7c5 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java @@ -17,37 +17,39 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp; -import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; - -import android.platform.helpers.IAppHelper; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.server.wm.flicker.helpers.ImeAppHelper; import org.junit.Before; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; /** * Test IME window closing back to app window transitions. * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest} */ @LargeTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class CloseImeWindowToAppTest extends FlickerTestBase { +public class CloseImeWindowToAppTest extends NonRotationTestBase { + + static final String IME_WINDOW_TITLE = "InputMethod"; + + public CloseImeWindowToAppTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); - private static final String IME_WINDOW_TITLE = "InputMethod"; - private IAppHelper mImeTestApp = new StandardAppHelper( - InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "ImeApp"); + mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); + } @Before public void runTransition() { - super.runTransition(editTextLoseFocusToApp(mUiDevice) + run(editTextLoseFocusToApp((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation) .includeJankyRuns().build()); } @@ -63,20 +65,14 @@ public class CloseImeWindowToAppTest extends FlickerTestBase { @Test public void checkVisibility_imeAppLayerIsAlwaysVisible() { checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(mImeTestApp.getPackage()) + .showsLayer(mTestApp.getPackage()) .forAllEntries()); } @Test public void checkVisibility_imeAppWindowIsAlwaysVisible() { checkResults(result -> WmTraceSubject.assertThat(result) - .showsAppWindowOnTop(mImeTestApp.getPackage()) + .showsAppWindowOnTop(mTestApp.getPackage()) .forAllEntries()); } - - @Test - public void checkCoveredRegion_noUncoveredRegions() { - checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion( - getDisplayBounds()).forAllEntries()); - } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java index cce5a2a7cc0d..fc6719e2f9d9 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java @@ -17,37 +17,39 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome; -import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; - -import android.platform.helpers.IAppHelper; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.server.wm.flicker.helpers.ImeAppHelper; import org.junit.Before; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; /** * Test IME window closing to home transitions. * To run this test: {@code atest FlickerTests:CloseImeWindowToHomeTest} */ @LargeTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class CloseImeWindowToHomeTest extends FlickerTestBase { +public class CloseImeWindowToHomeTest extends NonRotationTestBase { + + static final String IME_WINDOW_TITLE = "InputMethod"; + + public CloseImeWindowToHomeTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); - private static final String IME_WINDOW_TITLE = "InputMethod"; - private IAppHelper mImeTestApp = new StandardAppHelper( - InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "ImeApp"); + mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); + } @Before public void runTransition() { - super.runTransition(editTextLoseFocusToHome(mUiDevice) + run(editTextLoseFocusToHome((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation) .includeJankyRuns().build()); } @@ -72,24 +74,18 @@ public class CloseImeWindowToHomeTest extends FlickerTestBase { @Test public void checkVisibility_imeAppLayerBecomesInvisible() { checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(mImeTestApp.getPackage()) + .showsLayer(mTestApp.getPackage()) .then() - .hidesLayer(mImeTestApp.getPackage()) + .hidesLayer(mTestApp.getPackage()) .forAllEntries()); } @Test public void checkVisibility_imeAppWindowBecomesInvisible() { checkResults(result -> WmTraceSubject.assertThat(result) - .showsAppWindowOnTop(mImeTestApp.getPackage()) + .showsAppWindowOnTop(mTestApp.getPackage()) .then() - .hidesAppWindowOnTop(mImeTestApp.getPackage()) + .hidesAppWindowOnTop(mTestApp.getPackage()) .forAllEntries()); } - - @Test - public void checkCoveredRegion_noUncoveredRegions() { - checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion( - getDisplayBounds()).forAllEntries()); - } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java index 1d44ea490f25..fd31aa531107 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java @@ -37,10 +37,10 @@ import android.support.test.uiautomator.Until; import android.util.Rational; import android.view.Surface; -import androidx.test.InstrumentationRegistry; - import com.android.server.wm.flicker.TransitionRunner.TransitionBuilder; import com.android.server.wm.flicker.helpers.AutomationUtils; +import com.android.server.wm.flicker.helpers.ImeAppHelper; +import com.android.server.wm.flicker.helpers.PipAppHelper; /** * Collection of common transitions which can be used to test different apps or scenarios. @@ -73,26 +73,17 @@ class CommonTransitions { } } - private static void clickEditTextWidget(UiDevice device, IAppHelper testApp) { - UiObject2 editText = device.findObject(By.res(testApp.getPackage(), "plain_text_input")); - editText.click(); - sleep(500); - } - - private static void clickEnterPipButton(UiDevice device, IAppHelper testApp) { - UiObject2 enterPipButton = device.findObject(By.res(testApp.getPackage(), "enter_pip")); - enterPipButton.click(); - sleep(500); - } - static TransitionBuilder openAppWarm(IAppHelper testApp, UiDevice - device) { + device, int beginRotation) { return TransitionRunner.newBuilder() - .withTag("OpenAppWarm_" + testApp.getLauncherName()) + .withTag("OpenAppWarm_" + testApp.getLauncherName() + + rotationToString(beginRotation)) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) + .runBeforeAll(() -> setRotation(device, beginRotation)) .runBeforeAll(testApp::open) .runBefore(device::pressHome) .runBefore(device::waitForIdle) + .runBefore(() -> setRotation(device, beginRotation)) .run(testApp::open) .runAfterAll(testApp::exit) .runAfterAll(AutomationUtils::setDefaultWait) @@ -127,16 +118,19 @@ class CommonTransitions { .repeat(ITERATIONS); } - static TransitionBuilder getOpenAppCold(IAppHelper testApp, - UiDevice device) { + static TransitionBuilder openAppCold(IAppHelper testApp, + UiDevice device, int beginRotation) { return TransitionRunner.newBuilder() - .withTag("OpenAppCold_" + testApp.getLauncherName()) + .withTag("OpenAppCold_" + testApp.getLauncherName() + + rotationToString(beginRotation)) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) + .runBeforeAll(() -> setRotation(device, beginRotation)) .runBefore(testApp::exit) .runBefore(device::waitForIdle) .run(testApp::open) .runAfterAll(testApp::exit) + .runAfterAll(() -> setRotation(device, Surface.ROTATION_0)) .repeat(ITERATIONS); } @@ -201,28 +195,31 @@ class CommonTransitions { .repeat(ITERATIONS); } - static TransitionBuilder editTextSetFocus(UiDevice device) { - IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "ImeApp"); + static TransitionBuilder editTextSetFocus(ImeAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("editTextSetFocus_" + testApp.getLauncherName()) + .withTag("editTextSetFocus_" + testApp.getLauncherName() + + rotationToString(beginRotation)) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) + .runBefore(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) - .run(() -> clickEditTextWidget(device, testApp)) + .run(() -> testApp.clickEditTextWidget(device)) .runAfterAll(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder resizeSplitScreen(IAppHelper testAppTop, IAppHelper testAppBottom, - UiDevice device, Rational startRatio, Rational stopRatio) { + static TransitionBuilder resizeSplitScreen(IAppHelper testAppTop, ImeAppHelper testAppBottom, + UiDevice device, int beginRotation, Rational startRatio, Rational stopRatio) { String testTag = "resizeSplitScreen_" + testAppTop.getLauncherName() + "_" + testAppBottom.getLauncherName() + "_" + startRatio.toString().replace("/", ":") + "_to_" - + stopRatio.toString().replace("/", ":"); + + stopRatio.toString().replace("/", ":") + "_" + + rotationToString(beginRotation); return TransitionRunner.newBuilder() .withTag(testTag) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) + .runBeforeAll(() -> setRotation(device, beginRotation)) .runBeforeAll(() -> clearRecents(device)) .runBefore(testAppBottom::open) .runBefore(device::pressHome) @@ -234,6 +231,7 @@ class CommonTransitions { By.res(device.getLauncherPackageName(), "snapshot")); snapshot.click(); }) + .runBefore(() -> testAppBottom.clickEditTextWidget(device)) .runBefore(() -> AutomationUtils.resizeSplitScreen(device, startRatio)) .run(() -> AutomationUtils.resizeSplitScreen(device, stopRatio)) .runAfter(() -> exitSplitScreen(device)) @@ -243,74 +241,70 @@ class CommonTransitions { .repeat(ITERATIONS); } - static TransitionBuilder editTextLoseFocusToHome(UiDevice device) { - IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "ImeApp"); + static TransitionBuilder editTextLoseFocusToHome(ImeAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("editTextLoseFocusToHome_" + testApp.getLauncherName()) + .withTag("editTextLoseFocusToHome_" + testApp.getLauncherName() + + rotationToString(beginRotation)) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) + .runBefore(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) - .runBefore(() -> clickEditTextWidget(device, testApp)) + .runBefore(() -> testApp.clickEditTextWidget(device)) .run(device::pressHome) .run(device::waitForIdle) .runAfterAll(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder editTextLoseFocusToApp(UiDevice device) { - IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "ImeApp"); + static TransitionBuilder editTextLoseFocusToApp(ImeAppHelper testApp, UiDevice device, + int beginRotation) { return TransitionRunner.newBuilder() - .withTag("editTextLoseFocusToApp_" + testApp.getLauncherName()) + .withTag("editTextLoseFocusToApp_" + testApp.getLauncherName() + + rotationToString(beginRotation)) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) + .runBefore(() -> setRotation(device, beginRotation)) .runBefore(testApp::open) - .runBefore(() -> clickEditTextWidget(device, testApp)) + .runBefore(() -> testApp.clickEditTextWidget(device)) .run(device::pressBack) .run(device::waitForIdle) .runAfterAll(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder enterPipMode(UiDevice device) { - IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "PipApp"); + static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device) { return TransitionRunner.newBuilder() .withTag("enterPipMode_" + testApp.getLauncherName()) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) .runBefore(testApp::open) - .run(() -> clickEnterPipButton(device, testApp)) + .run(() -> testApp.clickEnterPipButton(device)) .runAfter(() -> closePipWindow(device)) .runAfterAll(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder exitPipModeToHome(UiDevice device) { - IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "PipApp"); + static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device) { return TransitionRunner.newBuilder() .withTag("exitPipModeToHome_" + testApp.getLauncherName()) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) .runBefore(testApp::open) - .runBefore(() -> clickEnterPipButton(device, testApp)) + .runBefore(() -> testApp.clickEnterPipButton(device)) .run(() -> closePipWindow(device)) .run(device::waitForIdle) .runAfterAll(testApp::exit) .repeat(ITERATIONS); } - static TransitionBuilder exitPipModeToApp(UiDevice device) { - IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "PipApp"); + static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device) { return TransitionRunner.newBuilder() .withTag("exitPipModeToApp_" + testApp.getLauncherName()) .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen) .runBefore(device::pressHome) .runBefore(testApp::open) - .runBefore(() -> clickEnterPipButton(device, testApp)) + .runBefore(() -> testApp.clickEnterPipButton(device)) .run(() -> expandPipWindow(device)) .run(device::waitForIdle) .runAfterAll(testApp::exit) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java index 9836655bc013..8f0177c7afc5 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java @@ -25,6 +25,9 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.wm.flicker.helpers.ImeAppHelper; +import com.android.server.wm.flicker.helpers.PipAppHelper; + import org.junit.FixMethodOrder; import org.junit.Ignore; import org.junit.Test; @@ -44,23 +47,25 @@ public class DebugTest { private UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); /** - * atest FlickerTest:DebugTests#openAppCold + * atest FlickerTests:DebugTest#openAppCold */ @Test public void openAppCold() { - CommonTransitions.getOpenAppCold(testApp, uiDevice).recordAllRuns().build().run(); + CommonTransitions.openAppCold(testApp, uiDevice, Surface.ROTATION_0) + .recordAllRuns().build().run(); } /** - * atest FlickerTest:DebugTests#openAppWarm + * atest FlickerTests:DebugTest#openAppWarm */ @Test public void openAppWarm() { - CommonTransitions.openAppWarm(testApp, uiDevice).recordAllRuns().build().run(); + CommonTransitions.openAppWarm(testApp, uiDevice, Surface.ROTATION_0) + .recordAllRuns().build().run(); } /** - * atest FlickerTest:DebugTests#changeOrientationFromNaturalToLeft + * atest FlickerTests:DebugTest#changeOrientationFromNaturalToLeft */ @Test public void changeOrientationFromNaturalToLeft() { @@ -69,7 +74,7 @@ public class DebugTest { } /** - * atest FlickerTest:DebugTests#closeAppWithBackKey + * atest FlickerTests:DebugTest#closeAppWithBackKey */ @Test public void closeAppWithBackKey() { @@ -77,7 +82,7 @@ public class DebugTest { } /** - * atest FlickerTest:DebugTests#closeAppWithHomeKey + * atest FlickerTests:DebugTest#closeAppWithHomeKey */ @Test public void closeAppWithHomeKey() { @@ -85,7 +90,7 @@ public class DebugTest { } /** - * atest FlickerTest:DebugTests#openAppToSplitScreen + * atest FlickerTests:DebugTest#openAppToSplitScreen */ @Test public void openAppToSplitScreen() { @@ -94,7 +99,7 @@ public class DebugTest { } /** - * atest FlickerTest:DebugTests#splitScreenToLauncher + * atest FlickerTests:DebugTest#splitScreenToLauncher */ @Test public void splitScreenToLauncher() { @@ -104,70 +109,80 @@ public class DebugTest { } /** - * atest FlickerTest:DebugTests#resizeSplitScreen + * atest FlickerTests:DebugTest#resizeSplitScreen */ @Test public void resizeSplitScreen() { - IAppHelper bottomApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), - "com.android.server.wm.flicker.testapp", "ImeApp"); - CommonTransitions.resizeSplitScreen(testApp, bottomApp, uiDevice, new Rational(1, 3), - new Rational(2, 3)).includeJankyRuns().recordEachRun().build().run(); + ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); + CommonTransitions.resizeSplitScreen(testApp, bottomApp, uiDevice, Surface.ROTATION_0, + new Rational(1, 3), new Rational(2, 3)) + .includeJankyRuns().recordEachRun().build().run(); } // IME tests /** - * atest FlickerTest:DebugTests#editTextSetFocus + * atest FlickerTests:DebugTest#editTextSetFocus */ @Test public void editTextSetFocus() { - CommonTransitions.editTextSetFocus(uiDevice).includeJankyRuns().recordEachRun() + ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); + CommonTransitions.editTextSetFocus(testApp, uiDevice, Surface.ROTATION_0) + .includeJankyRuns().recordEachRun() .build().run(); } /** - * atest FlickerTest:DebugTests#editTextLoseFocusToHome + * atest FlickerTests:DebugTest#editTextLoseFocusToHome */ @Test public void editTextLoseFocusToHome() { - CommonTransitions.editTextLoseFocusToHome(uiDevice).includeJankyRuns().recordEachRun() + ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); + CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0) + .includeJankyRuns().recordEachRun() .build().run(); } /** - * atest FlickerTest:DebugTests#editTextLoseFocusToApp + * atest FlickerTests:DebugTest#editTextLoseFocusToApp */ @Test public void editTextLoseFocusToApp() { - CommonTransitions.editTextLoseFocusToHome(uiDevice).includeJankyRuns().recordEachRun() + ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); + CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0) + .includeJankyRuns().recordEachRun() .build().run(); } // PIP tests /** - * atest FlickerTest:DebugTests#enterPipMode + * atest FlickerTests:DebugTest#enterPipMode */ @Test public void enterPipMode() { - CommonTransitions.enterPipMode(uiDevice).includeJankyRuns().recordEachRun().build().run(); + PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); + CommonTransitions.enterPipMode(testApp, uiDevice).includeJankyRuns().recordEachRun() + .build().run(); } /** - * atest FlickerTest:DebugTests#exitPipModeToHome + * atest FlickerTests:DebugTest#exitPipModeToHome */ @Test public void exitPipModeToHome() { - CommonTransitions.exitPipModeToHome(uiDevice).includeJankyRuns().recordEachRun() + PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); + CommonTransitions.exitPipModeToHome(testApp, uiDevice).includeJankyRuns().recordEachRun() .build().run(); } /** - * atest FlickerTest:DebugTests#exitPipModeToApp + * atest FlickerTests:DebugTest#exitPipModeToApp */ @Test public void exitPipModeToApp() { - CommonTransitions.exitPipModeToApp(uiDevice).includeJankyRuns().recordEachRun() + PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation()); + CommonTransitions.exitPipModeToApp(testApp, uiDevice).includeJankyRuns().recordEachRun() .build().run(); } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java index 6e8e0c3c76c5..883d59ea8a92 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java @@ -98,7 +98,7 @@ public class FlickerTestBase { /** * Runs a transition, returns a cached result if the transition has run before. */ - void runTransition(TransitionRunner transition) { + void run(TransitionRunner transition) { if (transitionResults.containsKey(transition.getTestTag())) { mResults = transitionResults.get(transition.getTestTag()); return; @@ -111,6 +111,13 @@ public class FlickerTestBase { } /** + * Runs a transition, returns a cached result if the transition has run before. + */ + void runTransition(TransitionRunner transition) { + run(transition); + } + + /** * Goes through a list of transition results and checks assertions on each result. */ void checkResults(Consumer<TransitionResult> assertion) { diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java new file mode 100644 index 000000000000..54941dc0f585 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 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 com.android.server.wm.flicker; + +import static android.view.Surface.rotationToString; + +import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; + +import android.graphics.Rect; +import android.view.Surface; + +import androidx.test.filters.FlakyTest; + +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runners.Parameterized.Parameters; + +import java.util.ArrayList; +import java.util.Collection; + +public abstract class NonRotationTestBase extends FlickerTestBase { + + int mBeginRotation; + + public NonRotationTestBase(String beginRotationName, int beginRotation) { + this.mBeginRotation = beginRotation; + } + + @Parameters(name = "{0}") + public static Collection<Object[]> getParams() { + int[] supportedRotations = + {Surface.ROTATION_0, Surface.ROTATION_90}; + Collection<Object[]> params = new ArrayList<>(); + + for (int begin : supportedRotations) { + params.add(new Object[]{rotationToString(begin), begin}); + } + + return params; + } + + @FlakyTest(bugId = 141361128) + @Ignore("Waiting bug feedback") + @Test + public void checkCoveredRegion_noUncoveredRegions() { + Rect displayBounds = getDisplayBounds(mBeginRotation); + checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion( + displayBounds).forAllEntries()); + } + + @FlakyTest(bugId = 141361128) + @Ignore("Waiting bug feedback") + @Test + public void checkVisibility_navBarLayerIsAlwaysVisible() { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()); + } + + @FlakyTest(bugId = 141361128) + @Ignore("Waiting bug feedback") + @Test + public void checkVisibility_statusBarLayerIsAlwaysVisible() { + checkResults(result -> LayersTraceSubject.assertThat(result) + .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()); + } +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java index 8d99054d907e..efdfaee60e64 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java @@ -16,14 +16,12 @@ package com.android.server.wm.flicker; -import static com.android.server.wm.flicker.CommonTransitions.getOpenAppCold; -import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; +import static com.android.server.wm.flicker.CommonTransitions.openAppCold; import static com.android.server.wm.flicker.WmTraceSubject.assertThat; import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.FixMethodOrder; @@ -31,36 +29,28 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; /** * Test cold launch app from launcher. * To run this test: {@code atest FlickerTests:OpenAppColdTest} */ @LargeTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class OpenAppColdTest extends FlickerTestBase { +public class OpenAppColdTest extends NonRotationTestBase { + + public OpenAppColdTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); - public OpenAppColdTest() { this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), "com.android.server.wm.flicker.testapp", "SimpleApp"); } @Before public void runTransition() { - super.runTransition(getOpenAppCold(mTestApp, mUiDevice).build()); - } - - @Test - public void checkVisibility_navBarWindowIsAlwaysVisible() { - checkResults(result -> assertThat(result) - .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()); - } - - @Test - public void checkVisibility_statusBarWindowIsAlwaysVisible() { - checkResults(result -> assertThat(result) - .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()); + run(openAppCold(mTestApp, mUiDevice, mBeginRotation) + .includeJankyRuns().build()); } @Test @@ -72,6 +62,8 @@ public class OpenAppColdTest extends FlickerTestBase { .forAllEntries()); } + @FlakyTest(bugId = 140855415) + @Ignore("Waiting bug feedback") @Test public void checkZOrder_appWindowReplacesLauncherAsTopWindow() { checkResults(result -> assertThat(result) @@ -83,26 +75,6 @@ public class OpenAppColdTest extends FlickerTestBase { } @Test - @FlakyTest(bugId = 141235985) - @Ignore("Waiting bug feedback") - public void checkCoveredRegion_noUncoveredRegions() { - checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion( - getDisplayBounds()).forAllEntries()); - } - - @Test - public void checkVisibility_navBarLayerIsAlwaysVisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()); - } - - @Test - public void checkVisibility_statusBarLayerIsAlwaysVisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()); - } - - @Test public void checkVisibility_wallpaperLayerBecomesInvisible() { checkResults(result -> LayersTraceSubject.assertThat(result) .showsLayer("Wallpaper") diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java index e8702c2dfa9f..7ce6315f529a 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java @@ -17,13 +17,11 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.openAppWarm; -import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; import static com.android.server.wm.flicker.WmTraceSubject.assertThat; import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; -import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.FixMethodOrder; @@ -31,36 +29,28 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; /** * Test warm launch app. * To run this test: {@code atest FlickerTests:OpenAppWarmTest} */ @LargeTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class OpenAppWarmTest extends FlickerTestBase { +public class OpenAppWarmTest extends NonRotationTestBase { + + public OpenAppWarmTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); - public OpenAppWarmTest() { this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), "com.android.server.wm.flicker.testapp", "SimpleApp"); } @Before public void runTransition() { - super.runTransition(openAppWarm(mTestApp, mUiDevice).includeJankyRuns().build()); - } - - @Test - public void checkVisibility_navBarIsAlwaysVisible() { - checkResults(result -> assertThat(result) - .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()); - } - - @Test - public void checkVisibility_statusBarIsAlwaysVisible() { - checkResults(result -> assertThat(result) - .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()); + super.runTransition(openAppWarm(mTestApp, mUiDevice, mBeginRotation) + .includeJankyRuns().build()); } @Test @@ -72,6 +62,8 @@ public class OpenAppWarmTest extends FlickerTestBase { .forAllEntries()); } + @FlakyTest(bugId = 140855415) + @Ignore("Waiting bug feedback") @Test public void checkZOrder_appWindowReplacesLauncherAsTopWindow() { checkResults(result -> assertThat(result) @@ -82,26 +74,6 @@ public class OpenAppWarmTest extends FlickerTestBase { .forAllEntries()); } - @FlakyTest(bugId = 141235985) - @Ignore("Waiting bug feedback") - @Test - public void checkCoveredRegion_noUncoveredRegions() { - checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion( - getDisplayBounds()).forAllEntries()); - } - - @Test - public void checkVisibility_navBarLayerIsAlwaysVisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()); - } - - @Test - public void checkVisibility_statusBarLayerIsAlwaysVisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()); - } - @Test public void checkVisibility_wallpaperLayerBecomesInvisible() { checkResults(result -> LayersTraceSubject.assertThat(result) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java index 9f5cfcedd38f..91d4a056d8fb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java @@ -17,31 +17,39 @@ package com.android.server.wm.flicker; import static com.android.server.wm.flicker.CommonTransitions.editTextSetFocus; -import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds; +import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.server.wm.flicker.helpers.ImeAppHelper; import org.junit.Before; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; /** * Test IME window opening transitions. * To run this test: {@code atest FlickerTests:OpenImeWindowTest} */ @LargeTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class OpenImeWindowTest extends FlickerTestBase { +public class OpenImeWindowTest extends NonRotationTestBase { private static final String IME_WINDOW_TITLE = "InputMethod"; + public OpenImeWindowTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); + + mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); + } + @Before public void runTransition() { - super.runTransition(editTextSetFocus(mUiDevice) + run(editTextSetFocus((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation) .includeJankyRuns().build()); } @@ -62,10 +70,4 @@ public class OpenImeWindowTest extends FlickerTestBase { .showsLayer(IME_WINDOW_TITLE) .forAllEntries()); } - - @Test - public void checkCoveredRegion_noUncoveredRegions() { - checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion( - getDisplayBounds()).forAllEntries()); - } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java index 1031baf7ec04..29b624005495 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java @@ -24,13 +24,13 @@ import static com.android.server.wm.flicker.WindowUtils.getNavigationBarHeight; import static com.google.common.truth.Truth.assertThat; import android.graphics.Rect; -import android.platform.helpers.IAppHelper; import android.util.Rational; import androidx.test.InstrumentationRegistry; import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.server.wm.flicker.helpers.ImeAppHelper; import org.junit.Before; import org.junit.FixMethodOrder; @@ -38,57 +38,48 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; /** * Test split screen resizing window transitions. * To run this test: {@code atest FlickerTests:ResizeSplitScreenTest} */ @LargeTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@FlakyTest(bugId = 140856143) +@FlakyTest(bugId = 140854698) @Ignore("Waiting bug feedback") -public class ResizeSplitScreenTest extends FlickerTestBase { +public class ResizeSplitScreenTest extends NonRotationTestBase { + + private static String sSimpleActivity = "SimpleActivity"; + private static String sImeActivity = "ImeActivity"; + + public ResizeSplitScreenTest(String beginRotationName, int beginRotation) { + super(beginRotationName, beginRotation); - public ResizeSplitScreenTest() { this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(), "com.android.server.wm.flicker.testapp", "SimpleApp"); } @Before public void runTransition() { - IAppHelper bottomApp = new StandardAppHelper(InstrumentationRegistry - .getInstrumentation(), - "com.android.server.wm.flicker.testapp", "ImeApp"); - super.runTransition(resizeSplitScreen(mTestApp, bottomApp, mUiDevice, new Rational(1, 3), - new Rational(2, 3)).includeJankyRuns().build()); - } - - @Test - public void checkVisibility_navBarLayerIsAlwaysVisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(NAVIGATION_BAR_WINDOW_TITLE) - .forAllEntries()); - } - - @Test - public void checkVisibility_statusBarLayerIsAlwaysVisible() { - checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer(STATUS_BAR_WINDOW_TITLE) - .forAllEntries()); + ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation()); + run(resizeSplitScreen(mTestApp, bottomApp, mUiDevice, mBeginRotation, + new Rational(1, 3), new Rational(2, 3)) + .includeJankyRuns().build()); } @Test public void checkVisibility_topAppLayerIsAlwaysVisible() { checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer("SimpleActivity") + .showsLayer(sSimpleActivity) .forAllEntries()); } @Test public void checkVisibility_bottomAppLayerIsAlwaysVisible() { checkResults(result -> LayersTraceSubject.assertThat(result) - .showsLayer("ImeActivity") + .showsLayer(sImeActivity) .forAllEntries()); } @@ -149,11 +140,11 @@ public class ResizeSplitScreenTest extends FlickerTestBase { displayBounds.bottom - getNavigationBarHeight()); LayersTraceSubject.assertThat(result) - .hasVisibleRegion("SimpleActivity", startingTopAppBounds) + .hasVisibleRegion(sSimpleActivity, startingTopAppBounds) .atTheEnd(); LayersTraceSubject.assertThat(result) - .hasVisibleRegion("ImeActivity", startingBottomAppBounds) + .hasVisibleRegion(sImeActivity, startingBottomAppBounds) .atTheEnd(); }); } @@ -175,14 +166,14 @@ public class ResizeSplitScreenTest extends FlickerTestBase { @Test public void checkVisibility_topAppWindowIsAlwaysVisible() { checkResults(result -> WmTraceSubject.assertThat(result) - .showsAppWindow("SimpleActivity") + .showsAppWindow(sSimpleActivity) .forAllEntries()); } @Test public void checkVisibility_bottomAppWindowIsAlwaysVisible() { checkResults(result -> WmTraceSubject.assertThat(result) - .showsAppWindow("ImeActivity") + .showsAppWindow(sImeActivity) .forAllEntries()); } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java new file mode 100644 index 000000000000..42977f549162 --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 com.android.server.wm.flicker.helpers; + +import android.app.Instrumentation; + +import com.android.server.wm.flicker.StandardAppHelper; + +public abstract class FlickerAppHelper extends StandardAppHelper { + + static int sFindTimeout = 10000; + static String sFlickerPackage = "com.android.server.wm.flicker.testapp"; + + public FlickerAppHelper(Instrumentation instr, String launcherName) { + super(instr, sFlickerPackage, launcherName); + } +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java new file mode 100644 index 000000000000..56e1118590ea --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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 com.android.server.wm.flicker.helpers; + +import android.app.Instrumentation; +import android.support.test.uiautomator.UiDevice; + +public class ImeAppAutoFocusHelper extends ImeAppHelper { + + public ImeAppAutoFocusHelper(Instrumentation instr) { + super(instr, "ImeAppAutoFocus"); + } + + public void clickEditTextWidget(UiDevice device) { + // do nothing (the app is focused automatically) + } +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java new file mode 100644 index 000000000000..098fd6d4250b --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 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 com.android.server.wm.flicker.helpers; + +import static android.os.SystemClock.sleep; + +import android.app.Instrumentation; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; + +public class ImeAppHelper extends FlickerAppHelper { + + ImeAppHelper(Instrumentation instr, String launcherName) { + super(instr, launcherName); + } + + public ImeAppHelper(Instrumentation instr) { + this(instr, "ImeApp"); + } + + public void clickEditTextWidget(UiDevice device) { + UiObject2 editText = device.findObject(By.res(getPackage(), "plain_text_input")); + editText.click(); + sleep(500); + } +} diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java new file mode 100644 index 000000000000..d00e11b2994d --- /dev/null +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 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 com.android.server.wm.flicker.helpers; + +import static com.android.server.wm.flicker.helpers.AutomationUtils.getPipWindowSelector; + +import android.app.Instrumentation; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; + +public class PipAppHelper extends FlickerAppHelper { + + public PipAppHelper(Instrumentation instr) { + super(instr, "PipApp"); + } + + public void clickEnterPipButton(UiDevice device) { + UiObject2 enterPipButton = device.findObject(By.res(getPackage(), "enter_pip")); + enterPipButton.click(); + UiObject2 pipWindow = device.wait(Until.findObject(getPipWindowSelector()), sFindTimeout); + + if (pipWindow == null) { + throw new RuntimeException("Unable to find PIP window"); + } + } + +} diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml index b694172d60ca..0fe968273567 100644 --- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml +++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml @@ -38,6 +38,15 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> + <activity android:name=".ImeActivityAutoFocus" + android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus" + android:windowSoftInputMode="stateVisible" + android:label="ImeAppAutoFocus"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> <activity android:name=".PipActivity" android:resizeableActivity="true" android:supportsPictureInPicture="true" diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml index d5eb02330441..4708cfd48381 100644 --- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml +++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:focusableInTouchMode="true" android:background="@android:color/holo_green_light"> <EditText android:id="@+id/plain_text_input" android:layout_height="wrap_content" diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java index faa6e9cff2b2..05da717620aa 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 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. @@ -12,19 +12,19 @@ * 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 com.android.frameworks.coretests; +package com.android.server.wm.flicker.testapp; -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; +import android.widget.EditText; -public class FirstChildTestService extends Service { +public class ImeActivityAutoFocus extends ImeActivity { @Override - public IBinder onBind(Intent intent) { - return null; + protected void onStart() { + super.onStart(); + + EditText editTextField = findViewById(R.id.plain_text_input); + editTextField.requestFocus(); } } diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index cd2bd26ef4bb..702921836b0d 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -561,11 +561,17 @@ public class PermissionMonitorTest { mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1}); } - private PackageInfo addPackage(String packageName, int uid, String[] permissions) + private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions) throws Exception { PackageInfo packageInfo = packageInfoWithPermissions(permissions, PARTITION_SYSTEM); when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo); when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName}); + return packageInfo; + } + + private PackageInfo addPackage(String packageName, int uid, String[] permissions) + throws Exception { + PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions); mObserver.onPackageAdded(packageName, uid); return packageInfo; } @@ -616,14 +622,13 @@ public class PermissionMonitorTest { } @Test - public void testPackageUpdate() throws Exception { + public void testPackageRemoveThenAdd() throws Exception { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); - // Remove and install the same package to simulate the update action when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); @@ -633,6 +638,20 @@ public class PermissionMonitorTest { } @Test + public void testPackageUpdate() throws Exception { + final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); + + addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {}); + mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1}); + + // When updating a package, the broadcast receiver gets two broadcasts (a remove and then an + // add), but the observer sees only one callback (an update). + setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); + mObserver.onPackageChanged(MOCK_PACKAGE1, MOCK_UID1); + mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); + } + + @Test public void testPackageUninstallWithMultiplePackages() throws Exception { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt index fa2b41adcacb..ad5bb9e2e2e8 100755 --- a/tools/codegen/src/com/android/codegen/Main.kt +++ b/tools/codegen/src/com/android/codegen/Main.kt @@ -132,11 +132,11 @@ fun main(args: Array<String>) { // $GENERATED_WARNING_PREFIX v$CODEGEN_VERSION. // // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code // // To regenerate run: // $ $cliExecutable ${cliArgs.dropLast(1).joinToString("") { "$it " }}$fileEscaped - // - // CHECKSTYLE:OFF Generated code + / """ if (FeatureFlag.CONST_DEFS()) generateConstDefs() diff --git a/tools/protologtool/README.md b/tools/protologtool/README.md index 3439357af598..ba639570f88c 100644 --- a/tools/protologtool/README.md +++ b/tools/protologtool/README.md @@ -8,8 +8,13 @@ ProtoLogTool incorporates three different modes of operation: ### Code transformation -Command: `process <protolog class path> <protolog implementation class path> - <protolog groups class path> <config.jar> [<input.java>] <output.srcjar>` +Command: `protologtool transform-protolog-calls + --protolog-class <protolog class name> + --protolog-impl-class <protolog implementation class name> + --loggroups-class <protolog groups class name> + --loggroups-jar <config jar path> + --output-srcjar <output.srcjar> + [<input.java>]` In this mode ProtoLogTool transforms every ProtoLog logging call in form of: ```java @@ -17,16 +22,20 @@ ProtoLog.x(ProtoLogGroup.GROUP_NAME, "Format string %d %s", value1, value2); ``` into: ```java -if (GROUP_NAME.isLogToAny()) { - ProtoLogImpl.x(ProtoLogGroup.GROUP_NAME, 123456, "Format string %d %s or null", value1, value2); +if (ProtoLogImpl.isEnabled(GROUP_NAME)) { + int protoLogParam0 = value1; + String protoLogParam1 = String.valueOf(value2); + ProtoLogImpl.x(ProtoLogGroup.GROUP_NAME, 123456, 0b0100, "Format string %d %s or null", protoLogParam0, protoLogParam1); } ``` where `ProtoLog`, `ProtoLogImpl` and `ProtoLogGroup` are the classes provided as arguments (can be imported, static imported or full path, wildcard imports are not allowed) and, `x` is the logging method. The transformation is done on the source level. A hash is generated from the format - string and log level and inserted after the `ProtoLogGroup` argument. The format string is replaced + string, log level and log group name and inserted after the `ProtoLogGroup` argument. After the hash + we insert a bitmask specifying the types of logged parameters. The format string is replaced by `null` if `ProtoLogGroup.GROUP_NAME.isLogToLogcat()` returns false. If `ProtoLogGroup.GROUP_NAME.isEnabled()` - returns false the log statement is removed entirely from the resultant code. + returns false the log statement is removed entirely from the resultant code. The real generated code is inlined + and a number of new line characters is added as to preserve line numbering in file. Input is provided as a list of java source file names. Transformed source is saved to a single source jar file. The ProtoLogGroup class with all dependencies should be provided as a compiled @@ -34,8 +43,12 @@ jar file (config.jar). ### Viewer config generation -Command: `viewerconf <protolog class path> <protolog implementation class path -<protolog groups class path> <config.jar> [<input.java>] <output.json>` +Command: `generate-viewer-config + --protolog-class <protolog class name> + --loggroups-class <protolog groups class name> + --loggroups-jar <config jar path> + --viewer-conf <viewer.json> + [<input.java>]` This command is similar in it's syntax to the previous one, only instead of creating a processed source jar it writes a viewer configuration file with following schema: @@ -46,8 +59,9 @@ it writes a viewer configuration file with following schema: "123456": { "message": "Format string %d %s", "level": "ERROR", - "group": "GROUP_NAME" - }, + "group": "GROUP_NAME", + "at": "com\/android\/server\/example\/Class.java" + } }, "groups": { "GROUP_NAME": { @@ -60,13 +74,13 @@ it writes a viewer configuration file with following schema: ### Binary log viewing -Command: `read <viewer.json> <wm_log.pb>` +Command: `read-log --viewer-conf <viewer.json> <wm_log.pb>` Reads the binary ProtoLog log file and outputs a human-readable LogCat-like text log. ## What is ProtoLog? -ProtoLog is a logging system created for the WindowManager project. It allows both binary and text logging +ProtoLog is a generic logging system created for the WindowManager project. It allows both binary and text logging and is tunable in runtime. It consists of 3 different submodules: * logging system built-in the Android app, * log viewer for reading binary logs, @@ -94,8 +108,7 @@ To add a new ProtoLogGroup simple create a new enum ProtoLogGroup member with de To add a new logging statement just add a new call to ProtoLog.x where x is a log level. -After doing any changes to logging groups or statements you should run `make update-protolog` to update -viewer configuration saved in the code repository. +After doing any changes to logging groups or statements you should build the project and follow instructions printed by the tool. ## How to change settings on device in runtime? Use the `adb shell su root cmd window logging` command. To get help just type diff --git a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt index cb2950802c5d..a52c8042582b 100644 --- a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt +++ b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt @@ -20,7 +20,6 @@ import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.ImportDeclaration import com.github.javaparser.ast.expr.BinaryExpr import com.github.javaparser.ast.expr.Expression -import com.github.javaparser.ast.expr.MethodCallExpr import com.github.javaparser.ast.expr.StringLiteralExpr object CodeUtils { @@ -33,9 +32,14 @@ object CodeUtils { .map { c -> c.toInt() }.reduce { h, c -> h * 31 + c } } - fun isWildcardStaticImported(code: CompilationUnit, className: String): Boolean { - return code.findAll(ImportDeclaration::class.java) - .any { im -> im.isStatic && im.isAsterisk && im.name.toString() == className } + fun checkWildcardStaticImported(code: CompilationUnit, className: String, fileName: String) { + code.findAll(ImportDeclaration::class.java) + .forEach { im -> + if (im.isStatic && im.isAsterisk && im.name.toString() == className) { + throw IllegalImportException("Wildcard static imports of $className " + + "methods are not supported.", ParsingContext(fileName, im)) + } + } } fun isClassImportedOrSamePackage(code: CompilationUnit, className: String): Boolean { @@ -59,25 +63,19 @@ object CodeUtils { .map { im -> im.name.toString().substringAfterLast('.') }.toSet() } - fun concatMultilineString(expr: Expression): String { + fun concatMultilineString(expr: Expression, context: ParsingContext): String { return when (expr) { is StringLiteralExpr -> expr.asString() is BinaryExpr -> when { expr.operator == BinaryExpr.Operator.PLUS -> - concatMultilineString(expr.left) + concatMultilineString(expr.right) + concatMultilineString(expr.left, context) + + concatMultilineString(expr.right, context) else -> throw InvalidProtoLogCallException( - "messageString must be a string literal " + - "or concatenation of string literals.", expr) + "expected a string literal " + + "or concatenation of string literals, got: $expr", context) } - else -> throw InvalidProtoLogCallException("messageString must be a string literal " + - "or concatenation of string literals.", expr) - } - } - - fun getPositionString(call: MethodCallExpr, fileName: String): String { - return when { - call.range.isPresent -> "$fileName:${call.range.get().begin.line}" - else -> fileName + else -> throw InvalidProtoLogCallException("expected a string literal " + + "or concatenation of string literals, got: $expr", context) } } } diff --git a/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt b/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt index 7759f35b33fe..e88f0f8231bd 100644 --- a/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt +++ b/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt @@ -22,7 +22,7 @@ enum class LogLevel { DEBUG, VERBOSE, INFO, WARN, ERROR, WTF; companion object { - fun getLevelForMethodName(name: String, node: Node): LogLevel { + fun getLevelForMethodName(name: String, node: Node, context: ParsingContext): LogLevel { return when (name) { "d" -> DEBUG "v" -> VERBOSE @@ -30,7 +30,8 @@ enum class LogLevel { "w" -> WARN "e" -> ERROR "wtf" -> WTF - else -> throw InvalidProtoLogCallException("Unknown log level $name", node) + else -> + throw InvalidProtoLogCallException("Unknown log level $name in $node", context) } } } diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java b/tools/protologtool/src/com/android/protolog/tool/ParsingContext.kt index e89f26489959..c6aedfc3093e 100644 --- a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java +++ b/tools/protologtool/src/com/android/protolog/tool/ParsingContext.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2019 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. @@ -12,13 +12,15 @@ * 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 com.android.frameworks.coretests; +package com.android.protolog.tool -import android.app.Activity; +import com.github.javaparser.ast.Node -public class SecondChildTestActivity extends Activity { +data class ParsingContext(val filePath: String, val lineNumber: Int) { + constructor(filePath: String, node: Node) + : this(filePath, if (node.range.isPresent) node.range.get().begin.line else -1) + constructor() : this("", -1) } diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt index eae63962161c..2181cf680f6c 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt @@ -38,23 +38,27 @@ open class ProtoLogCallProcessor( private fun getLogGroupName( expr: Expression, isClassImported: Boolean, - staticImports: Set<String> + staticImports: Set<String>, + fileName: String ): String { + val context = ParsingContext(fileName, expr) return when (expr) { is NameExpr -> when { expr.nameAsString in staticImports -> expr.nameAsString else -> - throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup", expr) + throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr", + context) } is FieldAccessExpr -> when { expr.scope.toString() == protoLogGroupClassName || isClassImported && expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString else -> - throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup", expr) + throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr", + context) } else -> throw InvalidProtoLogCallException("Invalid group argument " + - "- must be ProtoLogGroup enum member reference", expr) + "- must be ProtoLogGroup enum member reference: $expr", context) } } @@ -69,12 +73,10 @@ open class ProtoLogCallProcessor( !call.scope.isPresent && staticLogImports.contains(call.name.toString()) } - open fun process(code: CompilationUnit, callVisitor: ProtoLogCallVisitor?): CompilationUnit { - if (CodeUtils.isWildcardStaticImported(code, protoLogClassName) || - CodeUtils.isWildcardStaticImported(code, protoLogGroupClassName)) { - throw IllegalImportException("Wildcard static imports of $protoLogClassName " + - "and $protoLogGroupClassName methods are not supported.") - } + open fun process(code: CompilationUnit, callVisitor: ProtoLogCallVisitor?, fileName: String): + CompilationUnit { + CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName) + CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName) val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName) val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName) @@ -86,22 +88,25 @@ open class ProtoLogCallProcessor( .filter { call -> isProtoCall(call, isLogClassImported, staticLogImports) }.forEach { call -> + val context = ParsingContext(fileName, call) if (call.arguments.size < 2) { throw InvalidProtoLogCallException("Method signature does not match " + - "any ProtoLog method.", call) + "any ProtoLog method: $call", context) } - val messageString = CodeUtils.concatMultilineString(call.getArgument(1)) + val messageString = CodeUtils.concatMultilineString(call.getArgument(1), + context) val groupNameArg = call.getArgument(0) val groupName = - getLogGroupName(groupNameArg, isGroupClassImported, staticGroupImports) + getLogGroupName(groupNameArg, isGroupClassImported, + staticGroupImports, fileName) if (groupName !in groupMap) { throw InvalidProtoLogCallException("Unknown group argument " + - "- not a ProtoLogGroup enum member", call) + "- not a ProtoLogGroup enum member: $call", context) } callVisitor?.processCall(call, messageString, LogLevel.getLevelForMethodName( - call.name.toString(), call), groupMap.getValue(groupName)) + call.name.toString(), call, context), groupMap.getValue(groupName)) } return code } diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt index 53834a69ef9f..97f3de2c1221 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt @@ -17,7 +17,9 @@ package com.android.protolog.tool import com.android.protolog.tool.CommandOptions.Companion.USAGE +import com.github.javaparser.ParseProblemException import com.github.javaparser.StaticJavaParser +import com.github.javaparser.ast.CompilationUnit import java.io.File import java.io.FileInputStream import java.io.FileOutputStream @@ -48,7 +50,7 @@ object ProtoLogTool { command.javaSourceArgs.forEach { path -> val file = File(path) val text = file.readText() - val code = StaticJavaParser.parse(text) + val code = tryParse(text, path) val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration .get().nameAsString else "" val newPath = pack.replace('.', '/') + '/' + file.name @@ -66,6 +68,19 @@ object ProtoLogTool { out.close() } + private fun tryParse(code: String, fileName: String): CompilationUnit { + try { + return StaticJavaParser.parse(code) + } catch (ex: ParseProblemException) { + val problem = ex.problems.first() + throw ParsingException("Java parsing erro" + + "r: ${problem.verboseMessage}", + ParsingContext(fileName, problem.location.orElse(null) + ?.begin?.range?.orElse(null)?.begin?.line + ?: 0)) + } + } + private fun viewerConf(command: CommandOptions) { val groups = ProtoLogGroupReader() .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) @@ -76,7 +91,7 @@ object ProtoLogTool { val file = File(path) val text = file.readText() if (containsProtoLogText(text, command.protoLogClassNameArg)) { - val code = StaticJavaParser.parse(text) + val code = tryParse(text, path) val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration .get().nameAsString else "" val newPath = pack.replace('.', '/') + '/' + file.name @@ -104,8 +119,11 @@ object ProtoLogTool { CommandOptions.READ_LOG_CMD -> read(command) } } catch (ex: InvalidCommandException) { - println(ex.message) + println("\n${ex.message}\n") showHelpAndExit() + } catch (ex: CodeProcessingException) { + println("\n${ex.message}\n") + exitProcess(1) } } } diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt index 3f38bc01fc7c..00fd038079f9 100644 --- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt @@ -73,8 +73,7 @@ class SourceTransformer( } val ifStmt: IfStmt if (group.enabled) { - val position = CodeUtils.getPositionString(call, fileName) - val hash = CodeUtils.hash(position, messageString, level, group) + val hash = CodeUtils.hash(fileName, messageString, level, group) val newCall = call.clone() if (!group.textEnabled) { // Remove message string if text logging is not enabled by default. @@ -99,7 +98,8 @@ class SourceTransformer( NodeList<Expression>(newCall.arguments[0].clone())) if (argTypes.size != call.arguments.size - 2) { throw InvalidProtoLogCallException( - "Number of arguments does not mach format string", call) + "Number of arguments (${argTypes.size} does not mach format" + + " string in: $call", ParsingContext(fileName, call)) } val blockStmt = BlockStmt() if (argTypes.isNotEmpty()) { @@ -225,7 +225,7 @@ class SourceTransformer( processedCode = code.split('\n').toMutableList() offsets = IntArray(processedCode.size) LexicalPreservingPrinter.setup(compilationUnit) - protoLogCallProcessor.process(compilationUnit, this) + protoLogCallProcessor.process(compilationUnit, this, fileName) // return LexicalPreservingPrinter.print(compilationUnit) return processedCode.joinToString("\n") } diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt index 4c4179768b7f..941455a24ec8 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt @@ -32,13 +32,14 @@ class ViewerConfigBuilder( group: LogGroup ) { if (group.enabled) { - val position = CodeUtils.getPositionString(call, fileName) + val position = fileName val key = CodeUtils.hash(position, messageString, level, group) if (statements.containsKey(key)) { if (statements[key] != LogCall(messageString, level, group, position)) { throw HashCollisionException( "Please modify the log message \"$messageString\" " + - "or \"${statements[key]}\" - their hashes are equal.") + "or \"${statements[key]}\" - their hashes are equal.", + ParsingContext(fileName, call)) } } else { groups.add(group) @@ -54,7 +55,7 @@ class ViewerConfigBuilder( fun processClass(unit: CompilationUnit, fileName: String) { this.fileName = fileName - protoLogCallVisitor.process(unit, this) + protoLogCallVisitor.process(unit, this, fileName) } fun build(): String { diff --git a/tools/protologtool/src/com/android/protolog/tool/exceptions.kt b/tools/protologtool/src/com/android/protolog/tool/exceptions.kt index 0401d8f8baa0..ae00df123353 100644 --- a/tools/protologtool/src/com/android/protolog/tool/exceptions.kt +++ b/tools/protologtool/src/com/android/protolog/tool/exceptions.kt @@ -16,16 +16,23 @@ package com.android.protolog.tool -import com.github.javaparser.ast.Node import java.lang.Exception -import java.lang.RuntimeException -class HashCollisionException(message: String) : RuntimeException(message) +open class CodeProcessingException(message: String, context: ParsingContext) + : Exception("Code processing error in ${context.filePath}:${context.lineNumber}:\n" + + " $message") -class IllegalImportException(message: String) : Exception(message) +class HashCollisionException(message: String, context: ParsingContext) : + CodeProcessingException(message, context) -class InvalidProtoLogCallException(message: String, node: Node) - : RuntimeException("$message\nAt: $node") +class IllegalImportException(message: String, context: ParsingContext) : + CodeProcessingException("Illegal import: $message", context) + +class InvalidProtoLogCallException(message: String, context: ParsingContext) + : CodeProcessingException("InvalidProtoLogCall: $message", context) + +class ParsingException(message: String, context: ParsingContext) + : CodeProcessingException(message, context) class InvalidViewerConfigException(message: String) : Exception(message) diff --git a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt index 0acbc9074857..b916f8f00a68 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt @@ -55,40 +55,40 @@ class CodeUtilsTest { LogLevel.DEBUG, LogGroup("test2", true, true, "TAG"))) } - @Test - fun isWildcardStaticImported_true() { + @Test(expected = IllegalImportException::class) + fun checkWildcardStaticImported_true() { val code = """package org.example.test; import static org.example.Test.*; """ - assertTrue(CodeUtils.isWildcardStaticImported( - StaticJavaParser.parse(code), "org.example.Test")) + CodeUtils.checkWildcardStaticImported( + StaticJavaParser.parse(code), "org.example.Test", "") } @Test - fun isWildcardStaticImported_notStatic() { + fun checkWildcardStaticImported_notStatic() { val code = """package org.example.test; import org.example.Test.*; """ - assertFalse(CodeUtils.isWildcardStaticImported( - StaticJavaParser.parse(code), "org.example.Test")) + CodeUtils.checkWildcardStaticImported( + StaticJavaParser.parse(code), "org.example.Test", "") } @Test - fun isWildcardStaticImported_differentClass() { + fun checkWildcardStaticImported_differentClass() { val code = """package org.example.test; import static org.example.Test2.*; """ - assertFalse(CodeUtils.isWildcardStaticImported( - StaticJavaParser.parse(code), "org.example.Test")) + CodeUtils.checkWildcardStaticImported( + StaticJavaParser.parse(code), "org.example.Test", "") } @Test - fun isWildcardStaticImported_notWildcard() { + fun checkWildcardStaticImported_notWildcard() { val code = """package org.example.test; import org.example.Test.test; """ - assertFalse(CodeUtils.isWildcardStaticImported( - StaticJavaParser.parse(code), "org.example.Test")) + CodeUtils.checkWildcardStaticImported( + StaticJavaParser.parse(code), "org.example.Test", "") } @Test @@ -156,7 +156,7 @@ class CodeUtilsTest { @Test fun concatMultilineString_single() { val str = StringLiteralExpr("test") - val out = CodeUtils.concatMultilineString(str) + val out = CodeUtils.concatMultilineString(str, ParsingContext()) assertEquals("test", out) } @@ -166,7 +166,7 @@ class CodeUtilsTest { "test" + "abc" """ val code = StaticJavaParser.parseExpression<BinaryExpr>(str) - val out = CodeUtils.concatMultilineString(code) + val out = CodeUtils.concatMultilineString(code, ParsingContext()) assertEquals("testabc", out) } @@ -176,7 +176,7 @@ class CodeUtilsTest { "test" + "abc" + "1234" + "test" """ val code = StaticJavaParser.parseExpression<BinaryExpr>(str) - val out = CodeUtils.concatMultilineString(code) + val out = CodeUtils.concatMultilineString(code, ParsingContext()) assertEquals("testabc1234test", out) } } diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt index d20ce7ec4dcb..97f67a0a3fdb 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt @@ -66,7 +66,7 @@ class ProtoLogCallProcessorTest { """ groupMap["TEST"] = LogGroup("TEST", true, false, "WindowManager") groupMap["ERROR"] = LogGroup("ERROR", true, true, "WindowManagerERROR") - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") assertEquals(2, calls.size) var c = calls[0] assertEquals("test %b", c.messageString) @@ -93,7 +93,7 @@ class ProtoLogCallProcessorTest { } """ groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager") - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") checkCalls() } @@ -112,7 +112,7 @@ class ProtoLogCallProcessorTest { } """ groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager") - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") checkCalls() } @@ -130,7 +130,7 @@ class ProtoLogCallProcessorTest { } """ groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager") - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") } @Test @@ -147,7 +147,7 @@ class ProtoLogCallProcessorTest { } """ groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager") - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") assertEquals(0, calls.size) } @@ -162,7 +162,7 @@ class ProtoLogCallProcessorTest { } } """ - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") } @Test(expected = InvalidProtoLogCallException::class) @@ -176,7 +176,7 @@ class ProtoLogCallProcessorTest { } } """ - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") } @Test(expected = InvalidProtoLogCallException::class) @@ -190,7 +190,7 @@ class ProtoLogCallProcessorTest { } } """ - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") } @Test(expected = InvalidProtoLogCallException::class) @@ -204,7 +204,7 @@ class ProtoLogCallProcessorTest { } } """ - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") } @Test @@ -220,7 +220,7 @@ class ProtoLogCallProcessorTest { } """ groupMap["TEST"] = LogGroup("TEST", false, true, "WindowManager") - visitor.process(StaticJavaParser.parse(code), processor) + visitor.process(StaticJavaParser.parse(code), processor, "") checkCalls() } } diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt index f221fbd216b9..e746300646c8 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt @@ -78,7 +78,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1922613844, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -88,7 +88,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 805272208, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); } } @@ -100,8 +100,8 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1922613844, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1922613844, 9, "test %d %f", protoLogParam0, protoLogParam1); } - if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -154595499, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -111,7 +111,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { org.example.ProtoLogImpl.w(TEST_GROUP, 1913810354, 0, "test", (Object[]) null); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { org.example.ProtoLogImpl.w(TEST_GROUP, -1741986185, 0, "test", (Object[]) null); } } } """.trimIndent() @@ -121,7 +121,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1922613844, 9, null, protoLogParam0, protoLogParam1); } + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, null, protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -131,7 +131,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 805272208, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); + if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); } } @@ -175,7 +175,8 @@ class SourceTransformerTest { var code = StaticJavaParser.parse(TEST_CODE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f", @@ -199,7 +200,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1922613844", methodCall.arguments[1].toString()) + assertEquals("1698911065", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) assertEquals("\"test %d %f\"", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -212,7 +213,8 @@ class SourceTransformerTest { var code = StaticJavaParser.parse(TEST_CODE_MULTICALLS) Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor val calls = code.findAll(MethodCallExpr::class.java) @@ -241,7 +243,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1922613844", methodCall.arguments[1].toString()) + assertEquals("1698911065", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) assertEquals("\"test %d %f\"", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -254,7 +256,8 @@ class SourceTransformerTest { var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], @@ -279,7 +282,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(7, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("805272208", methodCall.arguments[1].toString()) + assertEquals("1780316587", methodCall.arguments[1].toString()) assertEquals(0b001001.toString(), methodCall.arguments[2].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) assertEquals("protoLogParam1", methodCall.arguments[5].toString()) @@ -292,7 +295,8 @@ class SourceTransformerTest { var code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS) Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test", @@ -316,7 +320,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(5, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1913810354", methodCall.arguments[1].toString()) + assertEquals("-1741986185", methodCall.arguments[1].toString()) assertEquals(0.toString(), methodCall.arguments[2].toString()) assertEquals(TRANSFORMED_CODE_NO_PARAMS, out) } @@ -326,7 +330,8 @@ class SourceTransformerTest { var code = StaticJavaParser.parse(TEST_CODE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f", @@ -350,7 +355,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1922613844", methodCall.arguments[1].toString()) + assertEquals("1698911065", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) assertEquals("null", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -363,7 +368,8 @@ class SourceTransformerTest { var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], @@ -388,7 +394,7 @@ class SourceTransformerTest { assertEquals("w", methodCall.name.asString()) assertEquals(7, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("805272208", methodCall.arguments[1].toString()) + assertEquals("1780316587", methodCall.arguments[1].toString()) assertEquals(0b001001.toString(), methodCall.arguments[2].toString()) assertEquals("null", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -402,7 +408,8 @@ class SourceTransformerTest { var code = StaticJavaParser.parse(TEST_CODE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f", @@ -426,7 +433,8 @@ class SourceTransformerTest { var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], diff --git a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt index d3f8c767e8b1..2b6abcdee7ed 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt @@ -50,7 +50,8 @@ class ViewerConfigBuilderTest { @Test fun processClass() { Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO, @@ -78,7 +79,8 @@ class ViewerConfigBuilderTest { @Test fun processClass_nonUnique() { Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO, @@ -102,7 +104,8 @@ class ViewerConfigBuilderTest { @Test fun processClass_disabled() { Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation -> + any(ProtoLogCallVisitor::class.java), any(String::class.java))) + .thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO, diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index eb5a717d2b07..2afb14a12110 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -1056,26 +1056,6 @@ public class WifiConfiguration implements Parcelable { } /** - * @hide - * Returns Randomized MAC address to use with the network. - * If it is not set/valid, creates a new randomized address. - * If it can't generate a valid mac, returns the default MAC. - */ - public @NonNull MacAddress getOrCreateRandomizedMacAddress() { - int randomMacGenerationCount = 0; - while (!isValidMacAddressForRandomization(mRandomizedMacAddress) - && randomMacGenerationCount < MAXIMUM_RANDOM_MAC_GENERATION_RETRY) { - mRandomizedMacAddress = MacAddress.createRandomUnicastAddress(); - randomMacGenerationCount++; - } - - if (!isValidMacAddressForRandomization(mRandomizedMacAddress)) { - mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); - } - return mRandomizedMacAddress; - } - - /** * Returns MAC address set to be the local randomized MAC address. * Depending on user preference, the device may or may not use the returned MAC address for * connections to this network. diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index ba9fc786afe7..6d7e621a9bc2 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -19,7 +19,6 @@ package android.net.wifi; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import android.net.MacAddress; @@ -62,7 +61,8 @@ public class WifiConfigurationTest { config.updateIdentifier = "1234"; config.fromWifiNetworkSpecifier = true; config.fromWifiNetworkSuggestion = true; - MacAddress macBeforeParcel = config.getOrCreateRandomizedMacAddress(); + config.setRandomizedMacAddress(MacAddress.createRandomUnicastAddress()); + MacAddress macBeforeParcel = config.getRandomizedMacAddress(); Parcel parcelW = Parcel.obtain(); config.writeToParcel(parcelW, 0); byte[] bytes = parcelW.marshall(); @@ -75,7 +75,7 @@ public class WifiConfigurationTest { // lacking a useful config.equals, check two fields near the end. assertEquals(cookie, reconfig.getMoTree()); - assertEquals(macBeforeParcel, reconfig.getOrCreateRandomizedMacAddress()); + assertEquals(macBeforeParcel, reconfig.getRandomizedMacAddress()); assertEquals(config.updateIdentifier, reconfig.updateIdentifier); assertFalse(reconfig.trusted); assertTrue(config.fromWifiNetworkSpecifier); @@ -193,19 +193,6 @@ public class WifiConfigurationTest { } @Test - public void testGetOrCreateRandomizedMacAddress_SavesAndReturnsSameAddress() { - WifiConfiguration config = new WifiConfiguration(); - MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); - assertEquals(defaultMac, config.getRandomizedMacAddress()); - - MacAddress firstMacAddress = config.getOrCreateRandomizedMacAddress(); - MacAddress secondMacAddress = config.getOrCreateRandomizedMacAddress(); - - assertNotEquals(defaultMac, firstMacAddress); - assertEquals(firstMacAddress, secondMacAddress); - } - - @Test public void testSetRandomizedMacAddress_ChangesSavedAddress() { WifiConfiguration config = new WifiConfiguration(); MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); @@ -219,36 +206,6 @@ public class WifiConfigurationTest { } @Test - public void testGetOrCreateRandomizedMacAddress_ReRandomizesInvalidAddress() { - WifiConfiguration config = new WifiConfiguration(); - - MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); - MacAddress macAddressZeroes = MacAddress.ALL_ZEROS_ADDRESS; - MacAddress macAddressMulticast = MacAddress.fromString("03:ff:ff:ff:ff:ff"); - MacAddress macAddressGlobal = MacAddress.fromString("fc:ff:ff:ff:ff:ff"); - - config.setRandomizedMacAddress(null); - MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertNotEquals(macAfterChange, null); - - config.setRandomizedMacAddress(defaultMac); - macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertNotEquals(macAfterChange, defaultMac); - - config.setRandomizedMacAddress(macAddressZeroes); - macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertNotEquals(macAfterChange, macAddressZeroes); - - config.setRandomizedMacAddress(macAddressMulticast); - macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertNotEquals(macAfterChange, macAddressMulticast); - - config.setRandomizedMacAddress(macAddressGlobal); - macAfterChange = config.getOrCreateRandomizedMacAddress(); - assertNotEquals(macAfterChange, macAddressGlobal); - } - - @Test public void testSetRandomizedMacAddress_DoesNothingWhenNull() { WifiConfiguration config = new WifiConfiguration(); MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); |