diff options
63 files changed, 1765 insertions, 912 deletions
diff --git a/Android.mk b/Android.mk index 0e5dfed53607..03b2533e8bc0 100644 --- a/Android.mk +++ b/Android.mk @@ -944,27 +944,8 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \ -werror -hide 111 -hide 113 \ -overview $(LOCAL_PATH)/core/java/overview.html -SUPPORT_API_DIR := ./frameworks/support/api - -# More API Level information for the Support Library, which is currently -# included as part of the core framework docs build. -framework_docs_LOCAL_DROIDDOC_OPTIONS += \ - -since $(SUPPORT_API_DIR)/22.0.0.txt 22.0.0 \ - -since $(SUPPORT_API_DIR)/22.0.0.txt 22.0.0 \ - -since $(SUPPORT_API_DIR)/22.1.0.txt 22.1.0 \ - -since $(SUPPORT_API_DIR)/22.2.0.txt 22.2.0 \ - -since $(SUPPORT_API_DIR)/22.2.1.txt 22.2.1 \ - -since $(SUPPORT_API_DIR)/23.0.0.txt 23.0.0 \ - -since $(SUPPORT_API_DIR)/23.1.0.txt 23.1.0 \ - -since $(SUPPORT_API_DIR)/23.1.1.txt 23.1.1 \ - -since $(SUPPORT_API_DIR)/23.2.0.txt 23.2.0 \ - -since $(SUPPORT_API_DIR)/23.2.1.txt 23.2.1 \ - -since $(SUPPORT_API_DIR)/23.4.0.txt 23.4.0 \ - -since $(SUPPORT_API_DIR)/24.0.0.txt 24.0.0 \ - -since $(SUPPORT_API_DIR)/24.1.0.txt 24.1.0 \ - -since $(SUPPORT_API_DIR)/24.2.0.txt 24.2.0 \ - -since $(SUPPORT_API_DIR)/25.0.0.txt 25.0.0 \ - -since $(SUPPORT_API_DIR)/25.1.0.txt 25.1.0 +# Allow the support library to add its own droiddoc options. +include $(LOCAL_PATH)/../support/droiddoc.mk framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \ $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON) @@ -1472,10 +1453,6 @@ LOCAL_PROTOC_FLAGS := \ LOCAL_SRC_FILES := \ $(call all-proto-files-under, core/proto) \ $(call all-proto-files-under, libs/incident/proto) -LOCAL_C_INCLUDES := \ - $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto -LOCAL_EXPORT_C_INCLUDES := \ - $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto include $(BUILD_STATIC_LIBRARY) # ==== c++ proto host library ============================== @@ -1490,10 +1467,6 @@ LOCAL_PROTOC_FLAGS := \ LOCAL_SRC_FILES := \ $(call all-proto-files-under, core/proto) \ $(call all-proto-files-under, libs/incident/proto) -LOCAL_C_INCLUDES := \ - $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto -LOCAL_EXPORT_C_INCLUDES := \ - $(call generated-sources-dir-for,STATIC_LIBRARIES,libplatformprotos,)/proto include $(BUILD_HOST_SHARED_LIBRARY) diff --git a/api/current.txt b/api/current.txt index 227601205369..aab29be21d0f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -746,6 +746,7 @@ package android { field public static final int isAsciiCapable = 16843753; // 0x10103e9 field public static final int isAuxiliary = 16843647; // 0x101037f field public static final int isDefault = 16843297; // 0x1010221 + field public static final int isFeatureSplit = 16844126; // 0x101055e field public static final int isGame = 16843764; // 0x10103f4 field public static final int isIndicator = 16843079; // 0x1010147 field public static final int isModifier = 16843334; // 0x1010246 @@ -7937,7 +7938,7 @@ package android.bluetooth.le { } public final class AdvertisingSet { - method public void enableAdvertising(boolean); + method public void enableAdvertising(boolean, int); method public void periodicAdvertisingEnable(boolean); method public void setAdvertisingData(android.bluetooth.le.AdvertiseData); method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters); @@ -7970,7 +7971,6 @@ package android.bluetooth.le { method public int getInterval(); method public int getPrimaryPhy(); method public int getSecondaryPhy(); - method public int getTimeout(); method public int getTxPowerLevel(); method public boolean includeTxPower(); method public boolean isAnonymous(); @@ -8004,7 +8004,6 @@ package android.bluetooth.le { method public android.bluetooth.le.AdvertisingSetParameters.Builder setLegacyMode(boolean); method public android.bluetooth.le.AdvertisingSetParameters.Builder setPrimaryPhy(int); method public android.bluetooth.le.AdvertisingSetParameters.Builder setSecondaryPhy(int); - method public android.bluetooth.le.AdvertisingSetParameters.Builder setTimeout(int); method public android.bluetooth.le.AdvertisingSetParameters.Builder setTxPowerLevel(int); } @@ -8013,6 +8012,8 @@ package android.bluetooth.le { method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback); method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback); method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler); + method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback); + method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler); method public void stopAdvertising(android.bluetooth.le.AdvertiseCallback); method public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback); } diff --git a/api/system-current.txt b/api/system-current.txt index 00fe0b66e742..0f42a5463319 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -859,6 +859,7 @@ package android { field public static final int isAsciiCapable = 16843753; // 0x10103e9 field public static final int isAuxiliary = 16843647; // 0x101037f field public static final int isDefault = 16843297; // 0x1010221 + field public static final int isFeatureSplit = 16844126; // 0x101055e field public static final int isGame = 16843764; // 0x10103f4 field public static final int isIndicator = 16843079; // 0x1010147 field public static final int isModifier = 16843334; // 0x1010246 @@ -8412,7 +8413,7 @@ package android.bluetooth.le { } public final class AdvertisingSet { - method public void enableAdvertising(boolean); + method public void enableAdvertising(boolean, int); method public void periodicAdvertisingEnable(boolean); method public void setAdvertisingData(android.bluetooth.le.AdvertiseData); method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters); @@ -8445,7 +8446,6 @@ package android.bluetooth.le { method public int getInterval(); method public int getPrimaryPhy(); method public int getSecondaryPhy(); - method public int getTimeout(); method public int getTxPowerLevel(); method public boolean includeTxPower(); method public boolean isAnonymous(); @@ -8479,7 +8479,6 @@ package android.bluetooth.le { method public android.bluetooth.le.AdvertisingSetParameters.Builder setLegacyMode(boolean); method public android.bluetooth.le.AdvertisingSetParameters.Builder setPrimaryPhy(int); method public android.bluetooth.le.AdvertisingSetParameters.Builder setSecondaryPhy(int); - method public android.bluetooth.le.AdvertisingSetParameters.Builder setTimeout(int); method public android.bluetooth.le.AdvertisingSetParameters.Builder setTxPowerLevel(int); } @@ -8488,6 +8487,8 @@ package android.bluetooth.le { method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback); method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback); method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler); + method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback); + method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler); method public void stopAdvertising(android.bluetooth.le.AdvertiseCallback); method public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback); } @@ -34433,6 +34434,7 @@ package android.os { method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); method public static boolean supportsMultipleUsers(); + field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED"; field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking"; field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; diff --git a/api/test-current.txt b/api/test-current.txt index dd25eb72c8b9..f91bbb9a045b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -746,6 +746,7 @@ package android { field public static final int isAsciiCapable = 16843753; // 0x10103e9 field public static final int isAuxiliary = 16843647; // 0x101037f field public static final int isDefault = 16843297; // 0x1010221 + field public static final int isFeatureSplit = 16844126; // 0x101055e field public static final int isGame = 16843764; // 0x10103f4 field public static final int isIndicator = 16843079; // 0x1010147 field public static final int isModifier = 16843334; // 0x1010246 @@ -7964,7 +7965,7 @@ package android.bluetooth.le { } public final class AdvertisingSet { - method public void enableAdvertising(boolean); + method public void enableAdvertising(boolean, int); method public void periodicAdvertisingEnable(boolean); method public void setAdvertisingData(android.bluetooth.le.AdvertiseData); method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters); @@ -7997,7 +7998,6 @@ package android.bluetooth.le { method public int getInterval(); method public int getPrimaryPhy(); method public int getSecondaryPhy(); - method public int getTimeout(); method public int getTxPowerLevel(); method public boolean includeTxPower(); method public boolean isAnonymous(); @@ -8031,7 +8031,6 @@ package android.bluetooth.le { method public android.bluetooth.le.AdvertisingSetParameters.Builder setLegacyMode(boolean); method public android.bluetooth.le.AdvertisingSetParameters.Builder setPrimaryPhy(int); method public android.bluetooth.le.AdvertisingSetParameters.Builder setSecondaryPhy(int); - method public android.bluetooth.le.AdvertisingSetParameters.Builder setTimeout(int); method public android.bluetooth.le.AdvertisingSetParameters.Builder setTxPowerLevel(int); } @@ -8040,6 +8039,8 @@ package android.bluetooth.le { method public void startAdvertising(android.bluetooth.le.AdvertiseSettings, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseCallback); method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback); method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler); + method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback); + method public void startAdvertisingSet(android.bluetooth.le.AdvertisingSetParameters, android.bluetooth.le.AdvertiseData, android.bluetooth.le.AdvertiseData, android.bluetooth.le.PeriodicAdvertisingParameters, android.bluetooth.le.AdvertiseData, int, android.bluetooth.le.AdvertisingSetCallback, android.os.Handler); method public void stopAdvertising(android.bluetooth.le.AdvertiseCallback); method public void stopAdvertisingSet(android.bluetooth.le.AdvertisingSetCallback); } @@ -31735,6 +31736,7 @@ package android.os { method public deprecated void setUserRestrictions(android.os.Bundle); method public deprecated void setUserRestrictions(android.os.Bundle, android.os.UserHandle); method public static boolean supportsMultipleUsers(); + field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED"; field public static final java.lang.String ALLOW_PARENT_PROFILE_APP_LINKING = "allow_parent_profile_app_linking"; field public static final java.lang.String DISALLOW_ADD_MANAGED_PROFILE = "no_add_managed_profile"; field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user"; @@ -35019,6 +35021,7 @@ package android.provider { field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype"; field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname"; field public static final java.lang.String SKIP_FIRST_USE_HINTS = "skip_first_use_hints"; + field public static final java.lang.String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; field public static final java.lang.String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled"; field public static final deprecated java.lang.String TTS_DEFAULT_COUNTRY = "tts_default_country"; field public static final deprecated java.lang.String TTS_DEFAULT_LANG = "tts_default_lang"; diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 91520f1a7d8e..827a77f24ee9 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -411,7 +411,8 @@ public final class Pm { if (file.isFile()) { try { ApkLite baseApk = PackageParser.parseApkLite(file, 0); - PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null); + PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, + null, null); params.sessionParams.setSize( PackageHelper.calculateInstalledSize(pkgLite, false, params.sessionParams.abiOverride)); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index ede9281264b3..8a3d9b197117 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -156,13 +156,13 @@ class ContextImpl extends Context { @GuardedBy("ContextImpl.class") private ArrayMap<String, File> mSharedPrefsPaths; - final ActivityThread mMainThread; - final LoadedApk mPackageInfo; - private ClassLoader mClassLoader; + final @NonNull ActivityThread mMainThread; + final @NonNull LoadedApk mPackageInfo; + private @Nullable ClassLoader mClassLoader; - private final IBinder mActivityToken; + private final @Nullable IBinder mActivityToken; - private final UserHandle mUser; + private final @Nullable UserHandle mUser; private final ApplicationContentResolver mContentResolver; @@ -181,6 +181,9 @@ class ContextImpl extends Context { private PackageManager mPackageManager; private Context mReceiverRestrictedContext = null; + // The name of the split this Context is representing. May be null. + private @Nullable String mSplitName = null; + private final Object mSync = new Object(); @GuardedBy("mSync") @@ -1914,17 +1917,25 @@ class ContextImpl extends Context { } } - private static Resources createResources(IBinder activityToken, LoadedApk pi, int displayId, - Configuration overrideConfig, CompatibilityInfo compatInfo) { + private static Resources createResources(IBinder activityToken, LoadedApk pi, String splitName, + int displayId, Configuration overrideConfig, CompatibilityInfo compatInfo) { + final String[] splitResDirs; + final ClassLoader classLoader; + try { + splitResDirs = pi.getSplitPaths(splitName); + classLoader = pi.getSplitClassLoader(splitName); + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } return ResourcesManager.getInstance().getResources(activityToken, pi.getResDir(), - pi.getSplitResDirs(), + splitResDirs, pi.getOverlayDirs(), pi.getApplicationInfo().sharedLibraryFiles, displayId, overrideConfig, compatInfo, - pi.getClassLoader()); + classLoader); } @Override @@ -1933,14 +1944,13 @@ class ContextImpl extends Context { LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE); if (pi != null) { - ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, - new UserHandle(UserHandle.getUserId(application.uid)), flags, - null); + ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, + new UserHandle(UserHandle.getUserId(application.uid)), flags, null); final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; - c.setResources(createResources(mActivityToken, pi, displayId, null, + c.setResources(createResources(mActivityToken, pi, null, displayId, null, getDisplayAdjustments(displayId).getCompatibilityInfo())); if (c.mResources != null) { return c; @@ -1964,20 +1974,20 @@ class ContextImpl extends Context { if (packageName.equals("system") || packageName.equals("android")) { // The system resources are loaded in every application, so we can safely copy // the context without reloading Resources. - return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, user, flags, - null); + return new ContextImpl(this, mMainThread, mPackageInfo, null, mActivityToken, user, + flags, null); } LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier()); if (pi != null) { - ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, user, flags, - null); + ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user, + flags, null); final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; - c.setResources(createResources(mActivityToken, pi, displayId, null, + c.setResources(createResources(mActivityToken, pi, null, displayId, null, getDisplayAdjustments(displayId).getCompatibilityInfo())); if (c.mResources != null) { return c; @@ -1999,7 +2009,7 @@ class ContextImpl extends Context { final ClassLoader classLoader = mPackageInfo.getSplitClassLoader(splitName); final String[] paths = mPackageInfo.getSplitPaths(splitName); - final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, + final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, splitName, mActivityToken, mUser, mFlags, classLoader); final int displayId = mDisplay != null @@ -2024,11 +2034,11 @@ class ContextImpl extends Context { throw new IllegalArgumentException("overrideConfiguration must not be null"); } - ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, - mUser, mFlags, mClassLoader); + ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, + mActivityToken, mUser, mFlags, mClassLoader); final int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY; - context.setResources(createResources(mActivityToken, mPackageInfo, displayId, + context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo())); return context; } @@ -2039,12 +2049,12 @@ class ContextImpl extends Context { throw new IllegalArgumentException("display must not be null"); } - ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, - mUser, mFlags, mClassLoader); + ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, + mActivityToken, mUser, mFlags, mClassLoader); final int displayId = display.getDisplayId(); - context.setResources(createResources(mActivityToken, mPackageInfo, displayId, null, - getDisplayAdjustments(displayId).getCompatibilityInfo())); + context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, + null, getDisplayAdjustments(displayId).getCompatibilityInfo())); context.mDisplay = display; return context; } @@ -2053,16 +2063,16 @@ class ContextImpl extends Context { public Context createDeviceProtectedStorageContext() { final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE) | Context.CONTEXT_DEVICE_PROTECTED_STORAGE; - return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, mUser, flags, - mClassLoader); + return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, + flags, mClassLoader); } @Override public Context createCredentialProtectedStorageContext() { final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE) | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE; - return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, mUser, flags, - mClassLoader); + return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, + flags, mClassLoader); } @Override @@ -2149,7 +2159,7 @@ class ContextImpl extends Context { static ContextImpl createSystemContext(ActivityThread mainThread) { LoadedApk packageInfo = new LoadedApk(mainThread); - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0, + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null); context.setResources(packageInfo.getResources()); context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), @@ -2159,7 +2169,7 @@ class ContextImpl extends Context { static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, 0, + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, null); context.setResources(packageInfo.getResources()); return context; @@ -2186,8 +2196,8 @@ class ContextImpl extends Context { } } - ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityToken, null, - 0, classLoader); + ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName, + activityToken, null, 0, classLoader); // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY. displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY; @@ -2214,9 +2224,10 @@ class ContextImpl extends Context { return context; } - private ContextImpl(ContextImpl container, ActivityThread mainThread, - LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags, - ClassLoader classLoader) { + private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, + @NonNull LoadedApk packageInfo, @Nullable String splitName, + @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, + @Nullable ClassLoader classLoader) { mOuterContext = this; // If creator didn't specify which storage to use, use the default @@ -2241,6 +2252,7 @@ class ContextImpl extends Context { mUser = user; mPackageInfo = packageInfo; + mSplitName = splitName; mClassLoader = classLoader; mResourcesManager = ResourcesManager.getInstance(); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index cf41e4e5dc9c..dbed1beb4cf7 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -27,7 +27,8 @@ import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; -import android.content.pm.split.SplitDependencyLoaderHelper; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.split.SplitDependencyLoader; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Resources; @@ -49,7 +50,6 @@ import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.util.SparseArray; -import android.util.SparseIntArray; import android.view.Display; import android.view.DisplayAdjustments; @@ -304,7 +304,7 @@ public final class LoadedApk { final String[] splitPaths; try { splitPaths = getSplitPaths(null); - } catch (PackageManager.NameNotFoundException e) { + } catch (NameNotFoundException e) { // This should NEVER fail. throw new AssertionError("null split not found"); } @@ -336,7 +336,7 @@ public final class LoadedApk { mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs; if (aInfo.requestsIsolatedSplitLoading() && !ArrayUtils.isEmpty(mSplitNames)) { - mSplitLoader = new SplitDependencyLoader(aInfo.splitDependencies); + mSplitLoader = new SplitDependencyLoaderImpl(aInfo.splitDependencies); } } @@ -465,110 +465,88 @@ public final class LoadedApk { } } - private class SplitDependencyLoader - extends SplitDependencyLoaderHelper<PackageManager.NameNotFoundException> { - private String[] mCachedBaseResourcePath; + /* + * All indices received by the super class should be shifted by 1 when accessing mSplitNames, + * etc. The super class assumes the base APK is index 0, while the PackageManager APIs don't + * include the base APK in the list of splits. + */ + private class SplitDependencyLoaderImpl extends SplitDependencyLoader<NameNotFoundException> { private final String[][] mCachedResourcePaths; - private final ClassLoader[] mCachedSplitClassLoaders; + private final ClassLoader[] mCachedClassLoaders; - SplitDependencyLoader(SparseIntArray dependencies) { + SplitDependencyLoaderImpl(@NonNull SparseArray<int[]> dependencies) { super(dependencies); - mCachedResourcePaths = new String[mSplitNames.length][]; - mCachedSplitClassLoaders = new ClassLoader[mSplitNames.length]; + mCachedResourcePaths = new String[mSplitNames.length + 1][]; + mCachedClassLoaders = new ClassLoader[mSplitNames.length + 1]; } @Override protected boolean isSplitCached(int splitIdx) { - if (splitIdx != -1) { - return mCachedSplitClassLoaders[splitIdx] != null; - } - return mClassLoader != null && mCachedBaseResourcePath != null; - } - - private void addAllConfigSplits(String splitName, ArrayList<String> outAssetPaths) { - for (int i = 0; i < mSplitNames.length; i++) { - if (isConfigurationSplitOf(mSplitNames[i], splitName)) { - outAssetPaths.add(mSplitResDirs[i]); - } - } + return mCachedClassLoaders[splitIdx] != null; } @Override - protected void constructSplit(int splitIdx, int parentSplitIdx) throws - PackageManager.NameNotFoundException { + protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices, + int parentSplitIdx) throws NameNotFoundException { final ArrayList<String> splitPaths = new ArrayList<>(); - if (splitIdx == -1) { + if (splitIdx == 0) { createOrUpdateClassLoaderLocked(null); - addAllConfigSplits(null, splitPaths); - mCachedBaseResourcePath = splitPaths.toArray(new String[splitPaths.size()]); - return; - } + mCachedClassLoaders[0] = mClassLoader; - final ClassLoader parent; - if (parentSplitIdx == -1) { - // The parent is the base APK, so use its ClassLoader as parent - // and its configuration splits as part of our own too. - parent = mClassLoader; - Collections.addAll(splitPaths, mCachedBaseResourcePath); - } else { - parent = mCachedSplitClassLoaders[parentSplitIdx]; - Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]); + // Never add the base resources here, they always get added no matter what. + for (int configSplitIdx : configSplitIndices) { + splitPaths.add(mSplitResDirs[configSplitIdx - 1]); + } + mCachedResourcePaths[0] = splitPaths.toArray(new String[splitPaths.size()]); + return; } - mCachedSplitClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader( - mSplitAppDirs[splitIdx], getTargetSdkVersion(), false, null, null, parent); + // Since we handled the special base case above, parentSplitIdx is always valid. + final ClassLoader parent = mCachedClassLoaders[parentSplitIdx]; + mCachedClassLoaders[splitIdx] = ApplicationLoaders.getDefault().getClassLoader( + mSplitAppDirs[splitIdx - 1], getTargetSdkVersion(), false, null, null, parent); - splitPaths.add(mSplitResDirs[splitIdx]); - addAllConfigSplits(mSplitNames[splitIdx], splitPaths); + Collections.addAll(splitPaths, mCachedResourcePaths[parentSplitIdx]); + splitPaths.add(mSplitResDirs[splitIdx - 1]); + for (int configSplitIdx : configSplitIndices) { + splitPaths.add(mSplitResDirs[configSplitIdx - 1]); + } mCachedResourcePaths[splitIdx] = splitPaths.toArray(new String[splitPaths.size()]); } - private int ensureSplitLoaded(String splitName) - throws PackageManager.NameNotFoundException { - final int idx; - if (splitName == null) { - idx = -1; - } else { + private int ensureSplitLoaded(String splitName) throws NameNotFoundException { + int idx = 0; + if (splitName != null) { idx = Arrays.binarySearch(mSplitNames, splitName); if (idx < 0) { throw new PackageManager.NameNotFoundException( "Split name '" + splitName + "' is not installed"); } + idx += 1; } - loadDependenciesForSplit(idx); return idx; } - ClassLoader getClassLoaderForSplit(String splitName) - throws PackageManager.NameNotFoundException { - final int idx = ensureSplitLoaded(splitName); - if (idx < 0) { - return mClassLoader; - } - return mCachedSplitClassLoaders[idx]; + ClassLoader getClassLoaderForSplit(String splitName) throws NameNotFoundException { + return mCachedClassLoaders[ensureSplitLoaded(splitName)]; } - String[] getSplitPathsForSplit(String splitName) - throws PackageManager.NameNotFoundException { - final int idx = ensureSplitLoaded(splitName); - if (idx < 0) { - return mCachedBaseResourcePath; - } - return mCachedResourcePaths[idx]; + String[] getSplitPathsForSplit(String splitName) throws NameNotFoundException { + return mCachedResourcePaths[ensureSplitLoaded(splitName)]; } } - private SplitDependencyLoader mSplitLoader; + private SplitDependencyLoaderImpl mSplitLoader; - ClassLoader getSplitClassLoader(String splitName) throws PackageManager.NameNotFoundException { + ClassLoader getSplitClassLoader(String splitName) throws NameNotFoundException { if (mSplitLoader == null) { return mClassLoader; } return mSplitLoader.getClassLoaderForSplit(splitName); } - String[] getSplitPaths(String splitName) throws PackageManager.NameNotFoundException { + String[] getSplitPaths(String splitName) throws NameNotFoundException { if (mSplitLoader == null) { return mSplitResDirs; } @@ -925,7 +903,7 @@ public final class LoadedApk { final String[] splitPaths; try { splitPaths = getSplitPaths(null); - } catch (PackageManager.NameNotFoundException e) { + } catch (NameNotFoundException e) { // This should never fail. throw new AssertionError("null split not found"); } diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index 29f29e7dba4e..c281c7f7b0f8 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -52,10 +52,10 @@ interface IBluetoothGatt { void startAdvertisingSet(in AdvertisingSetParameters parameters, in AdvertiseData advertiseData, in AdvertiseData scanResponse, in PeriodicAdvertisingParameters periodicParameters, - in AdvertiseData periodicData, in IAdvertisingSetCallback callback); + in AdvertiseData periodicData, in int timeout, in IAdvertisingSetCallback callback); void stopAdvertisingSet(in IAdvertisingSetCallback callback); - void enableAdverisingSet(in int advertiserId, in boolean enable); + void enableAdverisingSet(in int advertiserId, in boolean enable, in int timeout); void setAdvertisingData(in int advertiserId, in AdvertiseData data); void setScanResponseData(in int advertiserId, in AdvertiseData data); void setAdvertisingParameters(in int advertiserId, in AdvertisingSetParameters parameters); diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java index 1524022b1f0f..5524a2bdae18 100644 --- a/core/java/android/bluetooth/le/AdvertisingSet.java +++ b/core/java/android/bluetooth/le/AdvertisingSet.java @@ -63,9 +63,9 @@ public final class AdvertisingSet { * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * */ - public void enableAdvertising(boolean enable) { + public void enableAdvertising(boolean enable, int timeout) { try { - gatt.enableAdverisingSet(this.advertiserId, enable); + gatt.enableAdverisingSet(this.advertiserId, enable, timeout); } catch (RemoteException e) { Log.e(TAG, "remote exception - ", e); } diff --git a/core/java/android/bluetooth/le/AdvertisingSetParameters.java b/core/java/android/bluetooth/le/AdvertisingSetParameters.java index 453dd70a589c..59fef8d1d1ea 100644 --- a/core/java/android/bluetooth/le/AdvertisingSetParameters.java +++ b/core/java/android/bluetooth/le/AdvertisingSetParameters.java @@ -118,13 +118,11 @@ public final class AdvertisingSetParameters implements Parcelable { private final boolean connectable; private final int interval; private final int txPowerLevel; - private final int timeoutMillis; private AdvertisingSetParameters(boolean connectable, boolean isLegacy, boolean isAnonymous, boolean includeTxPower, int primaryPhy, int secondaryPhy, - int interval, int txPowerLevel, - int timeoutMillis) { + int interval, int txPowerLevel) { this.connectable = connectable; this.isLegacy = isLegacy; this.isAnonymous = isAnonymous; @@ -133,7 +131,6 @@ public final class AdvertisingSetParameters implements Parcelable { this.secondaryPhy = secondaryPhy; this.interval = interval; this.txPowerLevel = txPowerLevel; - this.timeoutMillis = timeoutMillis; } private AdvertisingSetParameters(Parcel in) { @@ -145,7 +142,6 @@ public final class AdvertisingSetParameters implements Parcelable { secondaryPhy = in.readInt(); interval = in.readInt(); txPowerLevel = in.readInt(); - timeoutMillis = in.readInt(); } /** @@ -188,11 +184,6 @@ public final class AdvertisingSetParameters implements Parcelable { */ public int getTxPowerLevel() { return txPowerLevel; } - /** - * Returns the advertising time limit in milliseconds. - */ - public int getTimeout() { return timeoutMillis; } - @Override public String toString() { return "AdvertisingSetParameters [connectable=" + connectable @@ -202,8 +193,7 @@ public final class AdvertisingSetParameters implements Parcelable { + ", primaryPhy=" + primaryPhy + ", secondaryPhy=" + secondaryPhy + ", interval=" + interval - + ", txPowerLevel=" + txPowerLevel - + ", timeoutMillis=" + timeoutMillis + "]"; + + ", txPowerLevel=" + txPowerLevel + "]"; } @Override @@ -221,7 +211,6 @@ public final class AdvertisingSetParameters implements Parcelable { dest.writeInt(secondaryPhy); dest.writeInt(interval); dest.writeInt(txPowerLevel); - dest.writeInt(timeoutMillis); } public static final Parcelable.Creator<AdvertisingSetParameters> CREATOR = @@ -250,7 +239,6 @@ public final class AdvertisingSetParameters implements Parcelable { private int secondaryPhy = PHY_LE_1M; private int interval = INTERVAL_LOW; private int txPowerLevel = TX_POWER_MEDIUM; - private int timeoutMillis = 0; /** * Set whether the advertisement type should be connectable or @@ -380,30 +368,12 @@ public final class AdvertisingSetParameters implements Parcelable { } /** - * Limit advertising to a given amount of time. - * @param timeoutMillis Advertising time limit. May not exceed 180000 - * milliseconds. A value of 0 will disable the time limit. - * @throws IllegalArgumentException If the provided timeout is over 180000 - * ms. - */ - public Builder setTimeout(int timeoutMillis) { - if (timeoutMillis < 0 || timeoutMillis > LIMITED_ADVERTISING_MAX_MILLIS) { - throw new IllegalArgumentException("timeoutMillis invalid (must be 0-" + - LIMITED_ADVERTISING_MAX_MILLIS + - " milliseconds)"); - } - this.timeoutMillis = timeoutMillis; - return this; - } - - /** * Build the {@link AdvertisingSetParameters} object. */ public AdvertisingSetParameters build() { return new AdvertisingSetParameters(connectable, isLegacy, isAnonymous, includeTxPower, primaryPhy, - secondaryPhy, interval, txPowerLevel, - timeoutMillis); + secondaryPhy, interval, txPowerLevel); } } }
\ No newline at end of file diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index c9f1d7a32efb..67fd1c86aa3b 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -130,7 +130,6 @@ public final class BluetoothLeAdvertiser { AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder(); parameters.setLegacyMode(true); parameters.setConnectable(isConnectable); - parameters.setTimeout(settings.getTimeout()); if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) { parameters.setInterval(1600); // 1s } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_BALANCED) { @@ -152,7 +151,7 @@ public final class BluetoothLeAdvertiser { AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings); mLegacyAdvertisers.put(callback, wrapped); startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null, - wrapped); + settings.getTimeout(), wrapped); } } @@ -216,8 +215,8 @@ public final class BluetoothLeAdvertiser { AdvertiseData advertiseData, AdvertiseData scanResponse, PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, AdvertisingSetCallback callback) { - startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, callback, new Handler(Looper.getMainLooper())); + startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, + periodicData, 0, callback, new Handler(Looper.getMainLooper())); } /** @@ -237,6 +236,49 @@ public final class BluetoothLeAdvertiser { PeriodicAdvertisingParameters periodicParameters, AdvertiseData periodicData, AdvertisingSetCallback callback, Handler handler) { + startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, + periodicData, 0, callback, handler); + } + + /** + * Creates a new advertising set. If operation succeed, device will start advertising. This + * method returns immediately, the operation status is delivered through + * {@code callback.onAdvertisingSetStarted()}. + * <p> + * @param parameters advertising set parameters. + * @param advertiseData Advertisement data to be broadcasted. + * @param scanResponse Scan response associated with the advertisement data. + * @param periodicData Periodic advertising data. + * @param timeoutMillis Advertising time limit. May not exceed 180000 + * @param callback Callback for advertising set. + */ + public void startAdvertisingSet(AdvertisingSetParameters parameters, + AdvertiseData advertiseData, AdvertiseData scanResponse, + PeriodicAdvertisingParameters periodicParameters, + AdvertiseData periodicData, int timeoutMillis, + AdvertisingSetCallback callback) { + startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, + periodicData, timeoutMillis, callback, new Handler(Looper.getMainLooper())); + } + + /** + * Creates a new advertising set. If operation succeed, device will start advertising. This + * method returns immediately, the operation status is delivered through + * {@code callback.onAdvertisingSetStarted()}. + * <p> + * @param parameters advertising set parameters. + * @param advertiseData Advertisement data to be broadcasted. + * @param scanResponse Scan response associated with the advertisement data. + * @param periodicData Periodic advertising data. + * @param timeoutMillis Advertising time limit. May not exceed 180000 + * @param callback Callback for advertising set. + * @param handler thread upon which the callbacks will be invoked. + */ + public void startAdvertisingSet(AdvertisingSetParameters parameters, + AdvertiseData advertiseData, AdvertiseData scanResponse, + PeriodicAdvertisingParameters periodicParameters, + AdvertiseData periodicData, int timeoutMillis, + AdvertisingSetCallback callback, Handler handler) { BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter); if (callback == null) { @@ -259,7 +301,7 @@ public final class BluetoothLeAdvertiser { try { gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters, - periodicData, wrapped); + periodicData, timeoutMillis, wrapped); } catch (RemoteException e) { Log.e(TAG, "Failed to start advertising set - ", e); throw new IllegalStateException("Failed to start advertising set"); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 4dc6fd227243..bd31b03d7cff 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1104,18 +1104,7 @@ public class Intent implements Parcelable, Cloneable { * @hide */ public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED"; - /** - * Activity action: Activate the current SIM card. If SIM cards do not require activation, - * sending this intent is a no-op. - * <p>Input: No data should be specified. get*Extra may have an optional - * {@link #EXTRA_SIM_ACTIVATION_RESPONSE} field containing a PendingIntent through which to - * send the activation result. - * <p>Output: nothing. - * @hide - */ - @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_SIM_ACTIVATION_REQUEST = - "android.intent.action.SIM_ACTIVATION_REQUEST"; + /** * Activity Action: Main entry point for carrier setup apps. * <p>Carrier apps that provide an implementation for this action may be invoked to configure diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index b4d77a0fe54a..0b3742f27ddf 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -31,7 +31,7 @@ import android.os.Parcelable; import android.os.UserHandle; import android.text.TextUtils; import android.util.Printer; -import android.util.SparseIntArray; +import android.util.SparseArray; import com.android.internal.util.ArrayUtils; @@ -656,13 +656,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * * The keys and values are all indices into the {@link #splitNames}, {@link #splitSourceDirs}, * and {@link #splitPublicSourceDirs} arrays. - * Each key represents a split and its value is its parent split. + * Each key represents a split and its value is an array of splits. The first element of this + * array is the parent split, and the rest are configuration splits. These configuration splits + * have no dependencies themselves. * Cycles do not exist because they are illegal and screened for during installation. * * May be null if no splits are installed, or if no dependencies exist between them. * @hide */ - public SparseIntArray splitDependencies; + public SparseArray<int[]> splitDependencies; /** * Full paths to the locations of extra resource packages (runtime overlays) @@ -1182,7 +1184,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeStringArray(splitNames); dest.writeStringArray(splitSourceDirs); dest.writeStringArray(splitPublicSourceDirs); - dest.writeSparseIntArray(splitDependencies); + dest.writeSparseArray((SparseArray) splitDependencies); dest.writeString(nativeLibraryDir); dest.writeString(secondaryNativeLibraryDir); dest.writeString(nativeLibraryRootDir); @@ -1244,7 +1246,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { splitNames = source.readStringArray(); splitSourceDirs = source.readStringArray(); splitPublicSourceDirs = source.readStringArray(); - splitDependencies = source.readSparseIntArray(); + splitDependencies = source.readSparseArray(null); nativeLibraryDir = source.readString(); secondaryNativeLibraryDir = source.readString(); nativeLibraryRootDir = source.readString(); diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java index 59c530730170..f6f1be63baee 100644 --- a/core/java/android/content/pm/InstrumentationInfo.java +++ b/core/java/android/content/pm/InstrumentationInfo.java @@ -82,13 +82,15 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { * * The keys and values are all indices into the {@link #splitNames}, {@link #splitSourceDirs}, * and {@link #splitPublicSourceDirs} arrays. - * Each key represents a split and its value is its parent split. + * Each key represents a split and its value is an array of splits. The first element of this + * array is the parent split, and the rest are configuration splits. These configuration splits + * have no dependencies themselves. * Cycles do not exist because they are illegal and screened for during installation. * * May be null if no splits are installed, or if no dependencies exist between them. * @hide */ - public SparseIntArray splitDependencies; + public SparseArray<int[]> splitDependencies; /** * Full path to a directory assigned to the package for its persistent data. @@ -155,7 +157,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { dest.writeStringArray(splitNames); dest.writeStringArray(splitSourceDirs); dest.writeStringArray(splitPublicSourceDirs); - dest.writeSparseIntArray(splitDependencies); + dest.writeSparseArray((SparseArray) splitDependencies); dest.writeString(dataDir); dest.writeString(deviceProtectedDataDir); dest.writeString(credentialProtectedDataDir); @@ -185,7 +187,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { splitNames = source.readStringArray(); splitSourceDirs = source.readStringArray(); splitPublicSourceDirs = source.readStringArray(); - splitDependencies = source.readSparseIntArray(); + splitDependencies = source.readSparseArray(null); dataDir = source.readString(); deviceProtectedDataDir = source.readString(); credentialProtectedDataDir = source.readString(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index be6dc05ace5f..99aa1bcaaebf 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -76,7 +76,7 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import android.util.Slog; -import android.util.SparseIntArray; +import android.util.SparseArray; import android.util.TypedValue; import android.util.apk.ApkSignatureSchemeV2Verifier; import android.util.jar.StrictJarFile; @@ -109,7 +109,6 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; -import java.util.BitSet; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -368,8 +367,12 @@ public class PackageParser { /** Names of any split APKs, ordered by parsed splitName */ public final String[] splitNames; + /** Names of any split APKs that are features. Ordered by splitName */ + public final boolean[] isFeatureSplits; + /** Dependencies of any split APKs, ordered by parsed splitName */ public final String[] usesSplitNames; + public final String[] configForSplit; /** * Path where this package was found on disk. For monolithic packages @@ -396,14 +399,16 @@ public class PackageParser { public final boolean isolatedSplits; public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, - String[] usesSplitNames, String[] splitCodePaths, - int[] splitRevisionCodes) { + boolean[] isFeatureSplits, String[] usesSplitNames, String[] configForSplit, + String[] splitCodePaths, int[] splitRevisionCodes) { this.packageName = baseApk.packageName; this.versionCode = baseApk.versionCode; this.installLocation = baseApk.installLocation; this.verifiers = baseApk.verifiers; this.splitNames = splitNames; + this.isFeatureSplits = isFeatureSplits; this.usesSplitNames = usesSplitNames; + this.configForSplit = configForSplit; this.codePath = codePath; this.baseCodePath = baseApk.codePath; this.splitCodePaths = splitCodePaths; @@ -434,6 +439,8 @@ public class PackageParser { public final String codePath; public final String packageName; public final String splitName; + public boolean isFeatureSplit; + public final String configForSplit; public final String usesSplitName; public final int versionCode; public final int revisionCode; @@ -448,14 +455,17 @@ public class PackageParser { public final boolean extractNativeLibs; public final boolean isolatedSplits; - public ApkLite(String codePath, String packageName, String splitName, String usesSplitName, - int versionCode, int revisionCode, int installLocation, List<VerifierInfo> verifiers, - Signature[] signatures, Certificate[][] certificates, boolean coreApp, - boolean debuggable, boolean multiArch, boolean use32bitAbi, - boolean extractNativeLibs, boolean isolatedSplits) { + public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit, + String configForSplit, String usesSplitName, int versionCode, int revisionCode, + int installLocation, List<VerifierInfo> verifiers, Signature[] signatures, + Certificate[][] certificates, boolean coreApp, boolean debuggable, + boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs, + boolean isolatedSplits) { this.codePath = codePath; this.packageName = packageName; this.splitName = splitName; + this.isFeatureSplit = isFeatureSplit; + this.configForSplit = configForSplit; this.usesSplitName = usesSplitName; this.versionCode = versionCode; this.revisionCode = revisionCode; @@ -811,10 +821,10 @@ public class PackageParser { final ApkLite baseApk = parseApkLite(packageFile, flags); final String packagePath = packageFile.getAbsolutePath(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - return new PackageLite(packagePath, baseApk, null, null, null, null); + return new PackageLite(packagePath, baseApk, null, null, null, null, null, null); } - private static PackageLite parseClusterPackageLite(File packageDir, int flags) + static PackageLite parseClusterPackageLite(File packageDir, int flags) throws PackageParserException { final File[] files = packageDir.listFiles(); if (ArrayUtils.isEmpty(files)) { @@ -869,12 +879,16 @@ public class PackageParser { 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]; @@ -884,14 +898,16 @@ public class PackageParser { for (int i = 0; i < size; i++) { final 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 PackageLite(codePath, baseApk, splitNames, usesSplitNames, splitCodePaths, - splitRevisionCodes); + return new PackageLite(codePath, baseApk, splitNames, isFeatureSplits, usesSplitNames, + configForSplits, splitCodePaths, splitRevisionCodes); } /** @@ -1069,42 +1085,6 @@ public class PackageParser { } } - private static SparseIntArray buildSplitDependencyTree(PackageLite pkg) - throws PackageParserException { - SparseIntArray splitDependencies = new SparseIntArray(); - for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) { - final String splitDependency = pkg.usesSplitNames[splitIdx]; - if (splitDependency != null) { - final int depIdx = Arrays.binarySearch(pkg.splitNames, splitDependency); - if (depIdx < 0) { - throw new PackageParserException( - PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Split '" + pkg.splitNames[splitIdx] + "' requires split '" - + splitDependency + "', which is missing."); - } - splitDependencies.put(splitIdx, depIdx); - } - } - - // Verify that there are no cycles. - final BitSet bitset = new BitSet(); - for (int i = 0; i < splitDependencies.size(); i++) { - int splitIdx = splitDependencies.keyAt(i); - - bitset.clear(); - while (splitIdx != -1) { - if (bitset.get(splitIdx)) { - throw new PackageParserException( - PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST, - "Cycle detected in split dependencies."); - } - bitset.set(splitIdx); - splitIdx = splitDependencies.get(splitIdx, -1); - } - } - return splitDependencies.size() != 0 ? splitDependencies : null; - } - /** * Parse all APKs contained in the given directory, treating them as a * single package. This also performs sanity checking, such as requiring @@ -1122,11 +1102,15 @@ public class PackageParser { } // Build the split dependency tree. - SparseIntArray splitDependencies = null; + SparseArray<int[]> splitDependencies = null; final SplitAssetLoader assetLoader; if (lite.isolatedSplits && !ArrayUtils.isEmpty(lite.splitNames)) { - splitDependencies = buildSplitDependencyTree(lite); - assetLoader = new SplitAssetDependencyLoader(lite, splitDependencies, flags); + 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); } @@ -1762,6 +1746,8 @@ public class PackageParser { boolean use32bitAbi = false; boolean extractNativeLibs = true; boolean isolatedSplits = false; + boolean isFeatureSplit = false; + String configForSplit = null; String usesSplitName = null; for (int i = 0; i < attrs.getAttributeCount(); i++) { @@ -1777,6 +1763,10 @@ public class PackageParser { coreApp = attrs.getAttributeBooleanValue(i, false); } else if (attr.equals("isolatedSplits")) { isolatedSplits = attrs.getAttributeBooleanValue(i, false); + } else if (attr.equals("configForSplit")) { + configForSplit = attrs.getAttributeValue(i); + } else if (attr.equals("isFeatureSplit")) { + isFeatureSplit = attrs.getAttributeBooleanValue(i, false); } } @@ -1831,10 +1821,10 @@ public class PackageParser { } } - return new ApkLite(codePath, packageSplit.first, packageSplit.second, usesSplitName, - versionCode, revisionCode, installLocation, verifiers, signatures, - certificates, coreApp, debuggable, multiArch, use32bitAbi, extractNativeLibs, - isolatedSplits); + return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit, + configForSplit, usesSplitName, versionCode, revisionCode, installLocation, + verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi, + extractNativeLibs, isolatedSplits); } /** diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java index 4df90eb9f53e..16023f0d9d97 100644 --- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java +++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java @@ -18,10 +18,11 @@ package android.content.pm.split; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; +import android.annotation.NonNull; import android.content.pm.PackageParser; import android.content.res.AssetManager; import android.os.Build; -import android.util.SparseIntArray; +import android.util.SparseArray; import libcore.io.IoUtils; @@ -34,49 +35,31 @@ import java.util.Collections; * @hide */ public class SplitAssetDependencyLoader - extends SplitDependencyLoaderHelper<PackageParser.PackageParserException> + extends SplitDependencyLoader<PackageParser.PackageParserException> implements SplitAssetLoader { - private static final int BASE_ASSET_PATH_IDX = -1; - private final String mBasePath; - private final String[] mSplitNames; private final String[] mSplitPaths; private final int mFlags; - private String[] mCachedBasePaths; - private AssetManager mCachedBaseAssetManager; - - private String[][] mCachedSplitPaths; + private String[][] mCachedPaths; private AssetManager[] mCachedAssetManagers; - public SplitAssetDependencyLoader(PackageParser.PackageLite pkg, SparseIntArray dependencies, - int flags) { + public SplitAssetDependencyLoader(PackageParser.PackageLite pkg, + SparseArray<int[]> dependencies, int flags) { super(dependencies); - mBasePath = pkg.baseCodePath; - mSplitNames = pkg.splitNames; - mSplitPaths = pkg.splitCodePaths; + + // The base is inserted into index 0, so we need to shift all the splits by 1. + mSplitPaths = new String[pkg.splitCodePaths.length + 1]; + mSplitPaths[0] = pkg.baseCodePath; + System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length); + mFlags = flags; - mCachedBasePaths = null; - mCachedBaseAssetManager = null; - mCachedSplitPaths = new String[mSplitNames.length][]; - mCachedAssetManagers = new AssetManager[mSplitNames.length]; + mCachedPaths = new String[mSplitPaths.length][]; + mCachedAssetManagers = new AssetManager[mSplitPaths.length]; } @Override protected boolean isSplitCached(int splitIdx) { - if (splitIdx != -1) { - return mCachedAssetManagers[splitIdx] != null; - } - return mCachedBaseAssetManager != null; - } - - // Adds all non-code configuration splits for this split name. The split name is expected - // to represent a feature split. - private void addAllConfigSplits(String splitName, ArrayList<String> outAssetPaths) { - for (int i = 0; i < mSplitNames.length; i++) { - if (isConfigurationSplitOf(mSplitNames[i], splitName)) { - outAssetPaths.add(mSplitPaths[i]); - } - } + return mCachedAssetManagers[splitIdx] != null; } private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags) @@ -107,45 +90,38 @@ public class SplitAssetDependencyLoader } @Override - protected void constructSplit(int splitIdx, int parentSplitIdx) throws - PackageParser.PackageParserException { + protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices, + int parentSplitIdx) throws PackageParser.PackageParserException { final ArrayList<String> assetPaths = new ArrayList<>(); - if (splitIdx == BASE_ASSET_PATH_IDX) { - assetPaths.add(mBasePath); - addAllConfigSplits(null, assetPaths); - mCachedBasePaths = assetPaths.toArray(new String[assetPaths.size()]); - mCachedBaseAssetManager = createAssetManagerWithPaths(mCachedBasePaths, mFlags); - return; - } - - if (parentSplitIdx == BASE_ASSET_PATH_IDX) { - Collections.addAll(assetPaths, mCachedBasePaths); - } else { - Collections.addAll(assetPaths, mCachedSplitPaths[parentSplitIdx]); + if (parentSplitIdx >= 0) { + Collections.addAll(assetPaths, mCachedPaths[parentSplitIdx]); } assetPaths.add(mSplitPaths[splitIdx]); - addAllConfigSplits(mSplitNames[splitIdx], assetPaths); - mCachedSplitPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]); - mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedSplitPaths[splitIdx], + for (int configSplitIdx : configSplitIndices) { + assetPaths.add(mSplitPaths[configSplitIdx]); + } + mCachedPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]); + mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedPaths[splitIdx], mFlags); } @Override public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException { - loadDependenciesForSplit(BASE_ASSET_PATH_IDX); - return mCachedBaseAssetManager; + loadDependenciesForSplit(0); + return mCachedAssetManagers[0]; } @Override public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException { - loadDependenciesForSplit(idx); - return mCachedAssetManagers[idx]; + // Since we insert the base at position 0, and PackageParser keeps splits separate from + // the base, we need to adjust the index. + loadDependenciesForSplit(idx + 1); + return mCachedAssetManagers[idx + 1]; } @Override public void close() throws Exception { - IoUtils.closeQuietly(mCachedBaseAssetManager); for (AssetManager assets : mCachedAssetManagers) { IoUtils.closeQuietly(assets); } diff --git a/core/java/android/content/pm/split/SplitDependencyLoader.java b/core/java/android/content/pm/split/SplitDependencyLoader.java new file mode 100644 index 000000000000..358654692c9e --- /dev/null +++ b/core/java/android/content/pm/split/SplitDependencyLoader.java @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2016 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.split; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.content.pm.PackageParser; +import android.util.IntArray; +import android.util.SparseArray; + +import libcore.util.EmptyArray; + +import java.util.Arrays; +import java.util.BitSet; + +/** + * A helper class that implements the dependency tree traversal for splits. Callbacks + * are implemented by subclasses to notify whether a split has already been constructed + * and is cached, and to actually create the split requested. + * + * This helper is meant to be subclassed so as to reduce the number of allocations + * needed to make use of it. + * + * All inputs and outputs are assumed to be indices into an array of splits. + * + * @hide + */ +public abstract class SplitDependencyLoader<E extends Exception> { + private final @NonNull SparseArray<int[]> mDependencies; + + /** + * Construct a new SplitDependencyLoader. Meant to be called from the + * subclass constructor. + * @param dependencies The dependency tree of splits. + */ + protected SplitDependencyLoader(@NonNull SparseArray<int[]> dependencies) { + mDependencies = dependencies; + } + + /** + * Traverses the dependency tree and constructs any splits that are not already + * cached. This routine short-circuits and skips the creation of splits closer to the + * root if they are cached, as reported by the subclass implementation of + * {@link #isSplitCached(int)}. The construction of splits is delegated to the subclass + * implementation of {@link #constructSplit(int, int[], int)}. + * @param splitIdx The index of the split to load. 0 represents the base Application. + */ + protected void loadDependenciesForSplit(@IntRange(from = 0) int splitIdx) throws E { + // Quick check before any allocations are done. + if (isSplitCached(splitIdx)) { + return; + } + + // Special case the base, since it has no dependencies. + if (splitIdx == 0) { + final int[] configSplitIndices = collectConfigSplitIndices(0); + constructSplit(0, configSplitIndices, -1); + return; + } + + // Build up the dependency hierarchy. + final IntArray linearDependencies = new IntArray(); + linearDependencies.add(splitIdx); + + // Collect all the dependencies that need to be constructed. + // They will be listed from leaf to root. + while (true) { + // Only follow the first index into the array. The others are config splits and + // get loaded with the split. + final int[] deps = mDependencies.get(splitIdx); + if (deps != null && deps.length > 0) { + splitIdx = deps[0]; + } else { + splitIdx = -1; + } + + if (splitIdx < 0 || isSplitCached(splitIdx)) { + break; + } + + linearDependencies.add(splitIdx); + } + + // Visit each index, from right to left (root to leaf). + int parentIdx = splitIdx; + for (int i = linearDependencies.size() - 1; i >= 0; i--) { + final int idx = linearDependencies.get(i); + final int[] configSplitIndices = collectConfigSplitIndices(idx); + constructSplit(idx, configSplitIndices, parentIdx); + parentIdx = idx; + } + } + + private @NonNull int[] collectConfigSplitIndices(int splitIdx) { + // The config splits appear after the first element. + final int[] deps = mDependencies.get(splitIdx); + if (deps == null || deps.length <= 1) { + return EmptyArray.INT; + } + return Arrays.copyOfRange(deps, 1, deps.length); + } + + /** + * Subclass to report whether the split at `splitIdx` is cached and need not be constructed. + * It is assumed that if `splitIdx` is cached, any parent of `splitIdx` is also cached. + * @param splitIdx The index of the split to check for in the cache. + * @return true if the split is cached and does not need to be constructed. + */ + protected abstract boolean isSplitCached(@IntRange(from = 0) int splitIdx); + + /** + * Subclass to construct a split at index `splitIdx` with parent split `parentSplitIdx`. + * The result is expected to be cached by the subclass in its own structures. + * @param splitIdx The index of the split to construct. 0 represents the base Application. + * @param configSplitIndices The array of configuration splits to load along with this split. + * May be empty (length == 0) but never null. + * @param parentSplitIdx The index of the parent split. -1 if there is no parent. + * @throws E Subclass defined exception representing failure to construct a split. + */ + protected abstract void constructSplit(@IntRange(from = 0) int splitIdx, + @NonNull @IntRange(from = 1) int[] configSplitIndices, + @IntRange(from = -1) int parentSplitIdx) throws E; + + public static class IllegalDependencyException extends Exception { + private IllegalDependencyException(String message) { + super(message); + } + } + + private static int[] append(int[] src, int elem) { + if (src == null) { + return new int[] { elem }; + } + int[] dst = Arrays.copyOf(src, src.length + 1); + dst[src.length] = elem; + return dst; + } + + public static @NonNull SparseArray<int[]> createDependenciesFromPackage( + PackageParser.PackageLite pkg) throws IllegalDependencyException { + // The data structure that holds the dependencies. In PackageParser, splits are stored + // in their own array, separate from the base. We treat all paths as equals, so + // we need to insert the base as index 0, and shift all other splits. + final SparseArray<int[]> splitDependencies = new SparseArray<>(); + + // The base depends on nothing. + splitDependencies.put(0, new int[] {-1}); + + // First write out the <uses-split> dependencies. These must appear first in the + // array of ints, as is convention in this class. + for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) { + if (!pkg.isFeatureSplits[splitIdx]) { + // Non-feature splits don't have dependencies. + continue; + } + + // Implicit dependency on the base. + final int targetIdx; + final String splitDependency = pkg.usesSplitNames[splitIdx]; + if (splitDependency != null) { + final int depIdx = Arrays.binarySearch(pkg.splitNames, splitDependency); + if (depIdx < 0) { + throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx] + + "' requires split '" + splitDependency + "', which is missing."); + } + targetIdx = depIdx + 1; + } else { + // Implicitly depend on the base. + targetIdx = 0; + } + splitDependencies.put(splitIdx + 1, new int[] {targetIdx}); + } + + // Write out the configForSplit reverse-dependencies. These appear after the <uses-split> + // dependencies and are considered leaves. + // + // At this point, all splits in splitDependencies have the first element in their array set. + for (int splitIdx = 0; splitIdx < pkg.splitNames.length; splitIdx++) { + if (pkg.isFeatureSplits[splitIdx]) { + // Feature splits are not configForSplits. + continue; + } + + // Implicit feature for the base. + final int targetSplitIdx; + final String configForSplit = pkg.configForSplit[splitIdx]; + if (configForSplit != null) { + final int depIdx = Arrays.binarySearch(pkg.splitNames, configForSplit); + if (depIdx < 0) { + throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx] + + "' targets split '" + configForSplit + "', which is missing."); + } + + if (!pkg.isFeatureSplits[depIdx]) { + throw new IllegalDependencyException("Split '" + pkg.splitNames[splitIdx] + + "' declares itself as configuration split for a non-feature split '" + + pkg.splitNames[depIdx] + "'"); + } + targetSplitIdx = depIdx + 1; + } else { + targetSplitIdx = 0; + } + splitDependencies.put(targetSplitIdx, + append(splitDependencies.get(targetSplitIdx), splitIdx + 1)); + } + + // Verify that there are no cycles. + final BitSet bitset = new BitSet(); + for (int i = 0, size = splitDependencies.size(); i < size; i++) { + int splitIdx = splitDependencies.keyAt(i); + + bitset.clear(); + while (splitIdx != -1) { + // Check if this split has been visited yet. + if (bitset.get(splitIdx)) { + throw new IllegalDependencyException("Cycle detected in split dependencies."); + } + + // Mark the split so that if we visit it again, we no there is a cycle. + bitset.set(splitIdx); + + // Follow the first dependency only, the others are leaves by definition. + final int[] deps = splitDependencies.get(splitIdx); + splitIdx = deps != null ? deps[0] : -1; + } + } + return splitDependencies; + } +} diff --git a/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java b/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java deleted file mode 100644 index b49348000449..000000000000 --- a/core/java/android/content/pm/split/SplitDependencyLoaderHelper.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2016 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.split; - -import android.annotation.Nullable; -import android.util.IntArray; -import android.util.SparseIntArray; - -/** - * A helper class that implements the dependency tree traversal for splits. Callbacks - * are implemented by subclasses to notify whether a split has already been constructed - * and is cached, and to actually create the split requested. - * - * This helper is meant to be subclassed so as to reduce the number of allocations - * needed to make use of it. - * - * All inputs and outputs are assumed to be indices into an array of splits. - * - * @hide - */ -public abstract class SplitDependencyLoaderHelper<E extends Exception> { - @Nullable private final SparseIntArray mDependencies; - - /** - * Construct a new SplitDependencyLoaderHelper. Meant to be called from the - * subclass constructor. - * @param dependencies The dependency tree of splits. Can be null, which leads to - * just the implicit dependency of all splits on the base. - */ - protected SplitDependencyLoaderHelper(@Nullable SparseIntArray dependencies) { - mDependencies = dependencies; - } - - /** - * Traverses the dependency tree and constructs any splits that are not already - * cached. This routine short-circuits and skips the creation of splits closer to the - * root if they are cached, as reported by the subclass implementation of - * {@link #isSplitCached(int)}. The construction of splits is delegated to the subclass - * implementation of {@link #constructSplit(int, int)}. - * @param splitIdx The index of the split to load. Can be -1, which represents the - * base Application. - */ - protected void loadDependenciesForSplit(int splitIdx) throws E { - // Quick check before any allocations are done. - if (isSplitCached(splitIdx)) { - return; - } - - final IntArray linearDependencies = new IntArray(); - linearDependencies.add(splitIdx); - - // Collect all the dependencies that need to be constructed. - // They will be listed from leaf to root. - while (splitIdx >= 0) { - splitIdx = mDependencies != null ? mDependencies.get(splitIdx, -1) : -1; - if (isSplitCached(splitIdx)) { - break; - } - linearDependencies.add(splitIdx); - } - - // Visit each index, from right to left (root to leaf). - int parentIdx = splitIdx; - for (int i = linearDependencies.size() - 1; i >= 0; i--) { - final int idx = linearDependencies.get(i); - constructSplit(idx, parentIdx); - parentIdx = idx; - } - } - - /** - * Subclass to report whether the split at `splitIdx` is cached and need not be constructed. - * It is assumed that if `splitIdx` is cached, any parent of `splitIdx` is also cached. - * @param splitIdx The index of the split to check for in the cache. - * @return true if the split is cached and does not need to be constructed. - */ - protected abstract boolean isSplitCached(int splitIdx); - - /** - * Subclass to construct a split at index `splitIdx` with parent split `parentSplitIdx`. - * The result is expected to be cached by the subclass in its own structures. - * @param splitIdx The index of the split to construct. Can be -1, which represents the - * base Application. - * @param parentSplitIdx The index of the parent split. Can be -1, which represents the - * base Application. - * @throws E - */ - protected abstract void constructSplit(int splitIdx, int parentSplitIdx) throws E; - - /** - * Returns true if `splitName` represents a Configuration split of `featureSplitName`. - * - * A Configuration split's name is prefixed with the associated Feature split's name - * or the empty string if the split is for the base Application APK. It is then followed by the - * dollar sign character "$" and some unique string that should represent the configurations - * the split contains. - * - * Example: - * <table> - * <tr> - * <th>Feature split name</th> - * <th>Configuration split name: xhdpi</th> - * <th>Configuration split name: fr-rFR</th> - * </tr> - * <tr> - * <td>(base APK)</td> - * <td><code>$xhdpi</code></td> - * <td><code>$fr-rFR</code></td> - * </tr> - * <tr> - * <td><code>Extras</code></td> - * <td><code>Extras$xhdpi</code></td> - * <td><code>Extras$fr-rFR</code></td> - * </tr> - * </table> - * - * @param splitName The name of the split to check. - * @param featureSplitName The name of the Feature split. May be null or "" if checking - * the base Application APK. - * @return true if the splitName represents a Configuration split of featureSplitName. - */ - protected static boolean isConfigurationSplitOf(String splitName, String featureSplitName) { - if (featureSplitName == null || featureSplitName.length() == 0) { - // We are looking for configuration splits of the base, which have some legacy support. - if (splitName.startsWith("config_")) { - return true; - } else if (splitName.startsWith("$")) { - return true; - } else { - return false; - } - } else { - return splitName.startsWith(featureSplitName + "$"); - } - } -} diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index a638cd43aba9..f6712f840585 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -22,6 +22,7 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; @@ -763,6 +764,16 @@ public class UserManager { public static final int PIN_VERIFICATION_SUCCESS = -1; /** + * Sent when user restrictions have changed. + * + * @hide + */ + @SystemApi + @TestApi // To allow seeing it from CTS. + public static final String ACTION_USER_RESTRICTIONS_CHANGED = + "android.os.action.USER_RESTRICTIONS_CHANGED"; + + /** * Error result indicating that this user is not allowed to add other users on this device. * This is a result code returned from the activity created by the intent * {@link #createUserCreationIntent(String, String, String, PersistableBundle)}. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 391ee835e92a..7b84f6893982 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6630,6 +6630,8 @@ public final class Settings { * This value is only used for managed profiles. * @hide */ + @TestApi + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; /** @hide */ diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java index 83810b03b463..a07caf4384ea 100644 --- a/core/java/android/text/Emoji.java +++ b/core/java/android/text/Emoji.java @@ -132,12 +132,11 @@ public class Emoji { 0x1F910, 0x1F911, 0x1F912, 0x1F913, 0x1F914, 0x1F915, 0x1F916, 0x1F917, 0x1F918, 0x1F919, 0x1F91A, 0x1F91B, 0x1F91C, 0x1F91D, 0x1F91E, 0x1F920, 0x1F921, 0x1F922, 0x1F923, 0x1F924, 0x1F925, 0x1F926, 0x1F927, 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938, - 0x1F939, 0x1F93A, 0x1F93B, 0x1F93C, 0x1F93D, 0x1F93E, 0x1F940, 0x1F941, 0x1F942, 0x1F943, - 0x1F944, 0x1F945, 0x1F946, 0x1F947, 0x1F948, 0x1F949, 0x1F94A, 0x1F94B, 0x1F950, 0x1F951, - 0x1F952, 0x1F953, 0x1F954, 0x1F955, 0x1F956, 0x1F957, 0x1F958, 0x1F959, 0x1F95A, 0x1F95B, - 0x1F95C, 0x1F95D, 0x1F95E, 0x1F980, 0x1F981, 0x1F982, 0x1F983, 0x1F984, 0x1F985, 0x1F986, - 0x1F987, 0x1F988, 0x1F989, 0x1F98A, 0x1F98B, 0x1F98C, 0x1F98D, 0x1F98E, 0x1F98F, 0x1F990, - 0x1F991, 0x1F9C0 + 0x1F939, 0x1F93A, 0x1F93C, 0x1F93D, 0x1F93E, 0x1F940, 0x1F941, 0x1F942, 0x1F943, 0x1F944, + 0x1F945, 0x1F947, 0x1F948, 0x1F949, 0x1F94A, 0x1F94B, 0x1F950, 0x1F951, 0x1F952, 0x1F953, + 0x1F954, 0x1F955, 0x1F956, 0x1F957, 0x1F958, 0x1F959, 0x1F95A, 0x1F95B, 0x1F95C, 0x1F95D, + 0x1F95E, 0x1F980, 0x1F981, 0x1F982, 0x1F983, 0x1F984, 0x1F985, 0x1F986, 0x1F987, 0x1F988, + 0x1F989, 0x1F98A, 0x1F98B, 0x1F98C, 0x1F98D, 0x1F98E, 0x1F98F, 0x1F990, 0x1F991, 0x1F9C0 }; // See http://www.unicode.org/Public/emoji/3.0/emoji-data.txt @@ -150,7 +149,7 @@ public class Emoji { 0x1F596, 0x1F645, 0x1F646, 0x1F647, 0x1F64B, 0x1F64C, 0x1F64D, 0x1F64E, 0x1F64F, 0x1F6A3, 0x1F6B4, 0x1F6B5, 0x1F6B6, 0x1F6C0, 0x1F918, 0x1F919, 0x1F91A, 0x1F91B, 0x1F91C, 0x1F91D, 0x1F91E, 0x1F926, 0x1F930, 0x1F933, 0x1F934, 0x1F935, 0x1F936, 0x1F937, 0x1F938, 0x1F939, - 0x1F93B, 0x1F93C, 0x1F93D, 0x1F93E + 0x1F93C, 0x1F93D, 0x1F93E }; // See http://www.unicode.org/emoji/charts/emoji-zwj-sequences.html diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 048b7c22237c..168178702ebf 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -507,7 +507,7 @@ public final class ViewRootImpl implements ViewParent, mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); if (!sCompatibilityDone) { - sAlwaysAssignFocus = mTargetSdkVersion < Build.VERSION_CODES.O; + sAlwaysAssignFocus = true; sCompatibilityDone = true; } diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java index 38221383df3f..519a7dd8be43 100644 --- a/core/java/android/widget/SearchView.java +++ b/core/java/android/widget/SearchView.java @@ -58,6 +58,7 @@ import android.view.TouchDelegate; import android.view.View; import android.view.ViewConfiguration; import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; @@ -159,20 +160,6 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { private SearchableInfo mSearchable; private Bundle mAppSearchData; - /* - * SearchView can be set expanded before the IME is ready to be shown during - * initial UI setup. The show operation is asynchronous to account for this. - */ - private Runnable mShowImeRunnable = new Runnable() { - public void run() { - InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); - - if (imm != null) { - imm.showSoftInputUnchecked(0, null); - } - } - }; - private Runnable mUpdateDrawableStateRunnable = new Runnable() { public void run() { updateFocusedState(); @@ -497,9 +484,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { @Override public void clearFocus() { mClearingFocus = true; - setImeVisibility(false); super.clearFocus(); mSearchSrcTextView.clearFocus(); + mSearchSrcTextView.setImeVisibility(false); mClearingFocus = false; } @@ -967,19 +954,6 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { super.onDetachedFromWindow(); } - private void setImeVisibility(final boolean visible) { - if (visible) { - post(mShowImeRunnable); - } else { - removeCallbacks(mShowImeRunnable); - InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); - - if (imm != null) { - imm.hideSoftInputFromWindow(getWindowToken(), 0); - } - } - } - /** * Called by the SuggestionsAdapter * @hide @@ -1286,7 +1260,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { if (mSearchable != null) { launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString()); } - setImeVisibility(false); + mSearchSrcTextView.setImeVisibility(false); dismissSuggestions(); } } @@ -1311,7 +1285,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { } else { mSearchSrcTextView.setText(""); mSearchSrcTextView.requestFocus(); - setImeVisibility(true); + mSearchSrcTextView.setImeVisibility(true); } } @@ -1319,7 +1293,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { private void onSearchClicked() { updateViewsVisibility(false); mSearchSrcTextView.requestFocus(); - setImeVisibility(true); + mSearchSrcTextView.setImeVisibility(true); if (mOnSearchClickListener != null) { mOnSearchClickListener.onClick(this); } @@ -1477,7 +1451,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { if (mOnSuggestionListener == null || !mOnSuggestionListener.onSuggestionClick(position)) { launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null); - setImeVisibility(false); + mSearchSrcTextView.setImeVisibility(false); dismissSuggestions(); return true; } @@ -1910,6 +1884,9 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { private int mThreshold; private SearchView mSearchView; + private boolean mHasPendingShowSoftInputRequest; + final Runnable mRunShowSoftInputIfNecessary = () -> showSoftInputIfNecessary(); + public SearchAutoComplete(Context context) { super(context); mThreshold = getThreshold(); @@ -1983,11 +1960,13 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { super.onWindowFocusChanged(hasWindowFocus); if (hasWindowFocus && mSearchView.hasFocus() && getVisibility() == VISIBLE) { - InputMethodManager inputManager = - getContext().getSystemService(InputMethodManager.class); - inputManager.showSoftInput(this, 0); - // If in landscape mode, then make sure that - // the ime is in front of the dropdown. + // Since InputMethodManager#onPostWindowFocus() will be called after this callback, + // it is a bit too early to call InputMethodManager#showSoftInput() here. We still + // need to wait until the system calls back onCreateInputConnection() to call + // InputMethodManager#showSoftInput(). + mHasPendingShowSoftInputRequest = true; + + // If in landscape mode, then make sure that the ime is in front of the dropdown. if (isLandscapeMode(getContext())) { ensureImeVisible(true); } @@ -2027,7 +2006,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { } if (event.isTracking() && !event.isCanceled()) { mSearchView.clearFocus(); - mSearchView.setImeVisibility(false); + setImeVisibility(false); return true; } } @@ -2051,5 +2030,51 @@ public class SearchView extends LinearLayout implements CollapsibleActionView { }; return 160; } + + /** + * We override {@link View#onCreateInputConnection(EditorInfo)} as a signal to schedule a + * pending {@link InputMethodManager#showSoftInput(View, int)} request (if any). + */ + @Override + public InputConnection onCreateInputConnection(EditorInfo editorInfo) { + final InputConnection ic = super.onCreateInputConnection(editorInfo); + if (mHasPendingShowSoftInputRequest) { + removeCallbacks(mRunShowSoftInputIfNecessary); + post(mRunShowSoftInputIfNecessary); + } + return ic; + } + + private void showSoftInputIfNecessary() { + if (mHasPendingShowSoftInputRequest) { + final InputMethodManager imm = + getContext().getSystemService(InputMethodManager.class); + imm.showSoftInput(this, 0); + mHasPendingShowSoftInputRequest = false; + } + } + + private void setImeVisibility(final boolean visible) { + final InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); + if (!visible) { + mHasPendingShowSoftInputRequest = false; + removeCallbacks(mRunShowSoftInputIfNecessary); + imm.hideSoftInputFromWindow(getWindowToken(), 0); + return; + } + + if (imm.isActive(this)) { + // This means that SearchAutoComplete is already connected to the IME. + // InputMethodManager#showSoftInput() is guaranteed to pass client-side focus check. + mHasPendingShowSoftInputRequest = false; + removeCallbacks(mRunShowSoftInputIfNecessary); + imm.showSoftInput(this, 0); + return; + } + + // Otherwise, InputMethodManager#showSoftInput() should be deferred after + // onCreateInputConnection(). + mHasPendingShowSoftInputRequest = true; + } } } diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 67050f751f5e..cf6bd9e0d22f 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1014,6 +1014,15 @@ <p>The default value of this attribute is <code>false</code>. --> <attr name="isolatedSplits" format="boolean" /> + <!-- If set to <code>true</code>, indicates to the platform that this APK is + a 'feature' split and that it implicitly depends on the base APK. This distinguishes + this split APK from a 'configuration' split, which provides resource overrides + for a particular 'feature' split. Only useful when the base APK specifies + <code>android:isolatedSplits="true"</code>. + + <p>The default value of this attribute is <code>false</code>. --> + <attr name="isFeatureSplit" format="boolean" /> + <!-- Extra options for an activity's UI. Applies to either the {@code <activity>} or {@code <application>} tag. If specified on the {@code <application>} tag these will be considered defaults for all activities in the @@ -1286,6 +1295,7 @@ <attr name="sharedUserLabel" /> <attr name="installLocation" /> <attr name="isolatedSplits" /> + <attr name="isFeatureSplit" /> <attr name="targetSandboxVersion" /> </declare-styleable> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 2897c62a8aa5..f965c6954948 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2807,6 +2807,7 @@ <public name="importantForAutofill" /> <public name="recycleEnabled"/> <public name="isStatic" /> + <public name="isFeatureSplit" /> </public-group> <public-group type="style" first-id="0x010302e0"> diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd index 9a24d1540e9b..adb1af5afe2a 100644 --- a/docs/html/topic/libraries/support-library/revisions.jd +++ b/docs/html/topic/libraries/support-library/revisions.jd @@ -316,14 +316,13 @@ APK size, we recommend that you just list the specific modules your app needs. implementations, as well as any calls to this method, should be removed. </li> - <li>{@link android.support.v4.media.session.MediaSessionCompat#obtain + <li>{@code MediaSessionCompat.obtain()} has been deprecated and replaced with the more appropriately-named method <a href="/reference/android/support/v4/media/session/MediaSessionCompat.html#fromMediaSession"><code>fromMediaSession()</code></a>. </li> - <li>{@link - android.support.v4.media.session.MediaSessionCompat.QueueItem#obtain + <li>{@code MediaSessionCompat.QueueItem.obtain()} has been deprecated and replaced with the more appropriately-named method <a href="/reference/android/support/v4/media/session/MediaSessionCompat.QueueItem.html#fromQueueItem"><code>fromQueueItem()</code></a>. diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index b8d95e4acb5f..359cface8b7f 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -4765,7 +4765,6 @@ nope: && (targetTypeLen = attrPrivate.size()) ); } - break; } return 0; } diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h index 8e9741efd2a3..94a2a14ced87 100644 --- a/libs/androidfw/tests/data/basic/R.h +++ b/libs/androidfw/tests/data/basic/R.h @@ -44,8 +44,8 @@ struct R { density = 0x7f030002, // From feature - test3 = 0x7f080000, - test4 = 0x7f080001, + test3 = 0x80020000, + test4 = 0x80020001, }; }; @@ -57,7 +57,7 @@ struct R { ref2 = 0x7f040003, // From feature - number3 = 0x7f090000, + number3 = 0x80030000, }; }; diff --git a/libs/androidfw/tests/data/feature/AndroidManifest.xml b/libs/androidfw/tests/data/feature/AndroidManifest.xml index c972372508be..12ca5b6fcfd6 100644 --- a/libs/androidfw/tests/data/feature/AndroidManifest.xml +++ b/libs/androidfw/tests/data/feature/AndroidManifest.xml @@ -15,5 +15,6 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.basic"> + package="com.android.basic" + featureName="feature"> </manifest> diff --git a/libs/androidfw/tests/data/feature/build b/libs/androidfw/tests/data/feature/build index 6ed3e416fb10..aa2f7169345c 100755 --- a/libs/androidfw/tests/data/feature/build +++ b/libs/androidfw/tests/data/feature/build @@ -19,4 +19,10 @@ set -e PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/android.jar -aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --feature-of ../basic/basic.apk -F feature.apk -f +aapt2 compile --dir res -o compiled.flata +aapt2 link -o feature.apk \ + --manifest AndroidManifest.xml \ + -I $PATH_TO_FRAMEWORK_RES \ + -I ../basic/basic.apk \ + --package-id 0x80 \ + compiled.flata diff --git a/libs/androidfw/tests/data/feature/feature.apk b/libs/androidfw/tests/data/feature/feature.apk Binary files differindex 767fed697034..a0dae380018b 100644 --- a/libs/androidfw/tests/data/feature/feature.apk +++ b/libs/androidfw/tests/data/feature/feature.apk diff --git a/libs/androidfw/tests/data/feature/res/values/values.xml b/libs/androidfw/tests/data/feature/res/values/values.xml index 59f7d93ee389..43e15177f4dd 100644 --- a/libs/androidfw/tests/data/feature/res/values/values.xml +++ b/libs/androidfw/tests/data/feature/res/values/values.xml @@ -15,13 +15,12 @@ --> <resources> - <!-- Features are offset, so 7f020000 will become 7f080000 at runtime. --> - <public type="string" name="test3" id="0x7f020000" /> + <public type="string" name="test3" id="0x80020000" /> <string name="test3">test3</string> - <public type="string" name="test4" id="0x7f020001" /> + <public type="string" name="test4" id="0x80020001" /> <string name="test4">test4</string> - <public type="integer" name="number3" id="0x7f030000" /> + <public type="integer" name="number3" id="0x80030000" /> <integer name="number3">200</integer> </resources> diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index 62fd39516b85..c28aa5ec8711 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -1807,6 +1807,9 @@ public final class TvContract { * {@link #TYPE_S_DMB}, and * {@link #TYPE_T_DMB}. * + * <p>This value cannot be changed once it's set. Trying to modify it will make the update + * fail. + * * <p>This is a required field. * * <p>Type: TEXT diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java index 3fc999fb903a..f6f81682ad6f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java @@ -48,7 +48,7 @@ public class DashboardCategory implements Parcelable { /** * List of the category's children */ - public List<Tile> tiles = new ArrayList<Tile>(); + public List<Tile> tiles = new ArrayList<>(); public DashboardCategory() { diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index 457ce76d79ac..af247bdbb392 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -30,7 +30,6 @@ import android.os.Bundle; import android.provider.Settings; import android.util.ArraySet; import android.util.Log; -import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -40,10 +39,8 @@ import android.widget.FrameLayout; import android.widget.Toolbar; import com.android.settingslib.R; -import com.android.settingslib.applications.InterestingConfigChanges; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; public class SettingsDrawerActivity extends Activity { @@ -63,15 +60,6 @@ public class SettingsDrawerActivity extends Activity { private FrameLayout mContentHeaderContainer; - // Remove below after new IA - @Deprecated - private static List<DashboardCategory> sDashboardCategories; - @Deprecated - private static HashMap<Pair<String, String>, Tile> sTileCache; - @Deprecated - private static InterestingConfigChanges sConfigTracker; - // Remove above after new IA - @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -175,17 +163,6 @@ public class SettingsDrawerActivity extends Activity { getActionBar().setDisplayHomeAsUpEnabled(true); } - public List<DashboardCategory> getDashboardCategories() { - if (sDashboardCategories == null) { - sTileCache = new HashMap<>(); - sConfigTracker = new InterestingConfigChanges(); - // Apply initial current config. - sConfigTracker.applyNewConfig(getResources()); - sDashboardCategories = TileUtils.getCategories(this, sTileCache); - } - return sDashboardCategories; - } - protected void onCategoriesChanged() { final int N = mCategoryListeners.size(); for (int i = 0; i < N; i++) { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 91a4e792bbb8..1f1c18976edf 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -248,6 +248,9 @@ public class SettingsProvider extends ContentProvider { @GuardedBy("mLock") private HandlerThread mHandlerThread; + @GuardedBy("mLock") + private Handler mHandler; + // We have to call in the user manager with no lock held, private volatile UserManager mUserManager; @@ -300,10 +303,13 @@ public class SettingsProvider extends ContentProvider { mHandlerThread = new HandlerThread(LOG_TAG, Process.THREAD_PRIORITY_BACKGROUND); mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); mSettingsRegistry = new SettingsRegistry(); } - registerBroadcastReceivers(); - startWatchingUserRestrictionChanges(); + mHandler.post(() -> { + registerBroadcastReceivers(); + startWatchingUserRestrictionChanges(); + }); ServiceManager.addService("settings", new SettingsService(this)); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index 820638cb3c2d..c30bb9a2e6e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -74,7 +74,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener if (mUserListener == null) { return false; } - return mUserListener.getUserCount() > 1; + return mUserListener.getUserCount() != 0; } public void setUserSwitcherController(UserSwitcherController userSwitcherController) { diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 100d8212eacc..df250b19beba 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -105,16 +105,16 @@ final class ActivityManagerConstants extends ContentObserver { } private void updateConstants() { + final String setting = Settings.Global.getString(mResolver, + Settings.Global.ACTIVITY_MANAGER_CONSTANTS); synchronized (mService) { try { - mParser.setString(Settings.Global.getString(mResolver, - Settings.Global.ACTIVITY_MANAGER_CONSTANTS)); + mParser.setString(setting); } catch (IllegalArgumentException e) { // Failed to parse the settings string, log this and move on // with defaults. Slog.e("ActivityManagerConstants", "Bad activity manager config settings", e); } - ENFORCE_BG_CHECK = mParser.getBoolean(KEY_ENFORCE_BG_CHECK, DEFAULT_ENFORCE_BG_CHECK); MAX_CACHED_PROCESSES = mParser.getInt(KEY_MAX_CACHED_PROCESSES, DEFAULT_MAX_CACHED_PROCESSES); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 55d661cfb534..f722a8e28be9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -21493,6 +21493,15 @@ public class ActivityManagerService extends IActivityManager.Stub return success; } + private boolean isEphemeralLocked(int uid) { + String packages[] = mContext.getPackageManager().getPackagesForUid(uid); + if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid + return false; + } + return getPackageManagerInternalLocked().isPackageEphemeral(UserHandle.getUserId(uid), + packages[0]); + } + private final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) { final UidRecord.ChangeItem pendingChange; if (uidRec == null || uidRec.pendingChange == null) { @@ -21533,7 +21542,7 @@ public class ActivityManagerService extends IActivityManager.Stub pendingChange.change = change; pendingChange.processState = uidRec != null ? uidRec.setProcState : ActivityManager.PROCESS_STATE_NONEXISTENT; - pendingChange.ephemeral = uidRec.ephemeral; + pendingChange.ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid); pendingChange.procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0; // Directly update the power manager, since we sit on top of it and it is critical diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 36a913fb9c53..f927ccea1d5d 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -857,17 +857,26 @@ class AppErrors { ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true); - String[] nativeProcs = NATIVE_STACKS_OF_INTEREST; - // don't dump native PIDs for background ANRs - File tracesFile = null; + // don't dump native PIDs for background ANRs unless it is the process of interest + String[] nativeProcs = null; if (isSilentANR) { - tracesFile = mService.dumpStackTraces(true, firstPids, null, lastPids, - null); + for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) { + if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) { + nativeProcs = new String[] { app.processName }; + break; + } + } } else { - tracesFile = mService.dumpStackTraces(true, firstPids, processCpuTracker, lastPids, - nativeProcs); + nativeProcs = NATIVE_STACKS_OF_INTEREST; } + // For background ANRs, don't pass the ProcessCpuTracker to + // avoid spending 1/2 second collecting stats to rank lastPids. + File tracesFile = mService.dumpStackTraces(true, firstPids, + (isSilentANR) ? null : processCpuTracker, + (isSilentANR) ? null : lastPids, + nativeProcs); + String cpuInfo = null; if (ActivityManagerService.MONITOR_CPU_USAGE) { mService.updateCpuStatsNow(); diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 6af1c3b20df2..db133f876d17 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -130,7 +130,7 @@ final class OverlayManagerServiceImpl { // installed and should be removed final int storedOverlayInfosSize = storedOverlayInfos.size(); for (int i = 0; i < storedOverlayInfosSize; i++) { - final OverlayInfo oi = storedOverlayInfos.get(i); + final OverlayInfo oi = storedOverlayInfos.valueAt(i); mSettings.remove(oi.packageName, oi.userId); removeIdmapIfPossible(oi); packagesToUpdateAssets.add(oi.targetPackageName); diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index d8900c0546fd..d364d17fa764 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -290,8 +290,8 @@ public class BackgroundDexOptService extends JobService { PackageManagerService.REASON_BACKGROUND_DEXOPT, /* force */ false) : pm.performDexOptSecondary(pkg, - PackageManagerServiceCompilerMapping.getFullCompilerFilter(), - /* force */ true); + PackageManagerService.REASON_BACKGROUND_DEXOPT, + /* force */ false); if (success) { // Dexopt succeeded, remove package from the list of failing ones. synchronized (failedPackageNames) { diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index aac04da0c780..126f8c408e22 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -214,6 +214,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { if (getAvailableSpace() > 0) { dexoptCommandCountExecuted++; + Log.d(TAG, "Next command: " + next); return next; } else { if (DEBUG_DEXOPT) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 0ec85aa993cb..2e4a3a3f7968 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -915,7 +915,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // This is kind of hacky; we're creating a half-parsed package that is // straddled between the inherited and staged APKs. - final PackageLite pkg = new PackageLite(null, baseApk, null, null, + final PackageLite pkg = new PackageLite(null, baseApk, null, null, null, null, splitPaths.toArray(new String[splitPaths.size()]), null); final boolean isForwardLocked = (params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1d1bf0d195d9..2882d2058e80 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8458,6 +8458,11 @@ public class PackageManagerService extends IPackageManager.Stub { return mDexManager.dexoptSecondaryDex(packageName, compilerFilter, force); } + public boolean performDexOptSecondary(String packageName, int compileReason, + boolean force) { + return mDexManager.dexoptSecondaryDex(packageName, compileReason, force); + } + /** * Reconcile the information we have about the secondary dex files belonging to * {@code packagName} and the actual dex files. For all dex files that were diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 751d9af33463..25a596aaad90 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -171,7 +171,8 @@ class PackageManagerShellCommand extends ShellCommand { if (file.isFile()) { try { ApkLite baseApk = PackageParser.parseApkLite(file, 0); - PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null); + PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null, + null, null); params.sessionParams.setSize(PackageHelper.calculateInstalledSize( pkgLite, false, params.sessionParams.abiOverride)); } catch (PackageParserException | IOException e) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 1f97d7d9cf47..a31258c39341 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1493,6 +1493,10 @@ public class UserManagerService extends IUserManager.Stub { listeners[i].onUserRestrictionsChanged(userId, newRestrictionsFinal, prevRestrictionsFinal); } + + final Intent broadcast = new Intent(UserManager.ACTION_USER_RESTRICTIONS_CHANGED) + .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mContext.sendBroadcastAsUser(broadcast, UserHandle.of(userId)); } }); } 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 83dd392988bf..a904d178b03d 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -279,6 +279,17 @@ public class DexManager { * @return true if all secondary dex files were processed successfully (compiled or skipped * because they don't need to be compiled).. */ + public boolean dexoptSecondaryDex(String packageName, int compilerReason, boolean force) { + return dexoptSecondaryDex(packageName, + PackageManagerServiceCompilerMapping.getCompilerFilterForReason(compilerReason), + force); + } + + /** + * Perform dexopt on the package {@code packageName} secondary dex files. + * @return true if all secondary dex files were processed successfully (compiled or skipped + * because they don't need to be compiled).. + */ public boolean dexoptSecondaryDex(String packageName, String compilerFilter, boolean force) { // Select the dex optimizer based on the force parameter. // Forced compilation is done through ForcedUpdatePackageDexOptimizer which will adjust diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 8987ac192026..721d337f0866 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -157,7 +157,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { super.setUp(); mContext = getContext(); - when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) .thenReturn(true); @@ -174,6 +173,12 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUpUserManager(); } + @Override + protected void tearDown() throws Exception { + flushTasks(); + super.tearDown(); + } + private void initializeDpms() { // Need clearCallingIdentity() to pass permission checks. final long ident = mContext.binder.clearCallingIdentity(); @@ -1246,7 +1251,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.applicationInfo = new ApplicationInfo(); mContext.callerPermissions.add(permission.MANAGE_USERS); mContext.packageName = "com.android.frameworks.servicestests"; - mContext.userContexts.put(user, mContext); + mContext.addPackageContext(user, mContext); when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); StringParceledListSlice oneCert = asSlice(new String[] {"1"}); @@ -3966,121 +3971,168 @@ public class DevicePolicyManagerTest extends DpmTestBase { } public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception { + mContext.packageName = mRealTestContext.getPackageName(); setDeviceOwner(); - mContext.packageName = admin1.getPackageName(); - mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; - verifyCanGetOwnerInstalledCaCerts(admin1); + final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller"); + caller.packageName = admin1.getPackageName(); + caller.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + + verifyCanGetOwnerInstalledCaCerts(admin1, caller); } public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception { + mContext.packageName = mRealTestContext.getPackageName(); setAsProfileOwner(admin1); - mContext.packageName = admin1.getPackageName(); - verifyCanGetOwnerInstalledCaCerts(admin1); - verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1); + final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller"); + caller.packageName = admin1.getPackageName(); + caller.binder.callingUid = DpmMockContext.CALLER_UID; + + verifyCanGetOwnerInstalledCaCerts(admin1, caller); + verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(admin1, caller); } public void testGetOwnerInstalledCaCertsForDelegate() throws Exception { + mContext.packageName = mRealTestContext.getPackageName(); setAsProfileOwner(admin1); final String delegate = "com.example.delegate"; final int delegateUid = setupPackageInPackageManager(delegate, 20988); dpm.setCertInstallerPackage(admin1, delegate); - mContext.packageName = delegate; - mContext.binder.callingUid = delegateUid; - verifyCanGetOwnerInstalledCaCerts(null); - verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null); + final DpmMockContext caller = new DpmMockContext(mRealTestContext, "test-caller"); + caller.packageName = delegate; + caller.binder.callingUid = delegateUid; + + verifyCanGetOwnerInstalledCaCerts(null, caller); + verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(null, caller); } - private void verifyCanGetOwnerInstalledCaCerts(ComponentName caller) throws Exception { - final UserHandle user = UserHandle.getUserHandleForUid(mContext.binder.callingUid); - final int ownerUid = user.equals(UserHandle.SYSTEM) ? - DpmMockContext.CALLER_SYSTEM_USER_UID : DpmMockContext.CALLER_UID; + private void verifyCanGetOwnerInstalledCaCerts( + final ComponentName caller, final DpmMockContext callerContext) throws Exception { + final String alias = "cert"; + final byte[] caCert = TEST_CA.getBytes(); - mContext.applicationInfo = new ApplicationInfo(); - mContext.userContexts.put(user, mContext); - when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); + // device admin (used for posting the tls notification) + final DpmMockContext admin1Context; + if (admin1.getPackageName().equals(callerContext.getPackageName())) { + admin1Context = callerContext; + } else { + admin1Context = new DpmMockContext(mRealTestContext, "test-admin"); + admin1Context.packageName = admin1.getPackageName(); + admin1Context.applicationInfo = new ApplicationInfo(); + } + when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); + + // caller: device admin or delegated certificate installer + callerContext.applicationInfo = new ApplicationInfo(); + final UserHandle callerUser = callerContext.binder.getCallingUserHandle(); + + // system_server + final DpmMockContext serviceContext = mContext; + serviceContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + serviceContext.addPackageContext(callerUser, admin1Context); + serviceContext.addPackageContext(callerUser, callerContext); // Install a CA cert. - final String alias = "cert"; - final byte[] caCert = TEST_CA.getBytes(); - when(mContext.keyChainConnection.getService().installCaCertificate(caCert)) - .thenReturn(alias); - assertTrue(dpm.installCaCert(caller, caCert)); - when(mContext.keyChainConnection.getService().getUserCaAliases()) - .thenReturn(asSlice(new String[] {alias})); - mContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)); + runAsCaller(callerContext, dpms, (dpm) -> { + when(mContext.keyChainConnection.getService().installCaCertificate(caCert)) + .thenReturn(alias); + assertTrue(dpm.installCaCert(caller, caCert)); + when(mContext.keyChainConnection.getService().getUserCaAliases()) + .thenReturn(asSlice(new String[] {alias})); + + }); + + serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) + .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier())); flushTasks(); + final List<String> ownerInstalledCaCerts = new ArrayList<>(); + // Device Owner / Profile Owner can find out which CA certs were installed by itself. - final String packageName = mContext.packageName; - mContext.packageName = admin1.getPackageName(); - final long callerIdentity = mContext.binder.clearCallingIdentity(); - mContext.binder.callingUid = ownerUid; - List<String> ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(user); - assertNotNull(ownerInstalledCaCerts); - assertEquals(1, ownerInstalledCaCerts.size()); - assertTrue(ownerInstalledCaCerts.contains(alias)); + runAsCaller(admin1Context, dpms, (dpm) -> { + final List<String> installedCaCerts = dpm.getOwnerInstalledCaCerts(callerUser); + assertEquals(Arrays.asList(alias), installedCaCerts); + ownerInstalledCaCerts.addAll(installedCaCerts); + }); // Restarting the DPMS should not lose information. initializeDpms(); - assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(user)); + runAsCaller(admin1Context, dpms, (dpm) -> { + assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser)); + }); // System can find out which CA certs were installed by the Device Owner / Profile Owner. - mContext.packageName = "com.android.frameworks.servicestests"; - mContext.binder.clearCallingIdentity(); - assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(user)); + runAsCaller(serviceContext, dpms, (dpm) -> { + assertEquals(ownerInstalledCaCerts, dpm.getOwnerInstalledCaCerts(callerUser)); - // Remove the CA cert. - mContext.packageName = packageName; - mContext.binder.restoreCallingIdentity(callerIdentity); - reset(mContext.keyChainConnection.getService()); - mContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)); + // Remove the CA cert. + reset(mContext.keyChainConnection.getService()); + }); + + serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) + .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier())); flushTasks(); // Verify that the CA cert is no longer reported as installed by the Device Owner / Profile // Owner. - mContext.packageName = admin1.getPackageName(); - mContext.binder.callingUid = ownerUid; - ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(user); - assertNotNull(ownerInstalledCaCerts); - assertTrue(ownerInstalledCaCerts.isEmpty()); - - mContext.packageName = packageName; - mContext.binder.restoreCallingIdentity(callerIdentity); + runAsCaller(admin1Context, dpms, (dpm) -> { + MoreAsserts.assertEmpty(dpm.getOwnerInstalledCaCerts(callerUser)); + }); } - private void verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval(ComponentName caller) - throws Exception { - final UserHandle user = UserHandle.of(DpmMockContext.CALLER_USER_HANDLE); - - mContext.applicationInfo = new ApplicationInfo(); - mContext.userContexts.put(user, mContext); - when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); - - // Install a CA cert. + private void verifyCantGetOwnerInstalledCaCertsProfileOwnerRemoval( + final ComponentName callerName, final DpmMockContext callerContext) throws Exception { final String alias = "cert"; final byte[] caCert = TEST_CA.getBytes(); - when(mContext.keyChainConnection.getService().installCaCertificate(caCert)) - .thenReturn(alias); - assertTrue(dpm.installCaCert(caller, caCert)); - when(mContext.keyChainConnection.getService().getUserCaAliases()) + + // device admin (used for posting the tls notification) + final DpmMockContext admin1Context; + if (admin1.getPackageName().equals(callerContext.getPackageName())) { + admin1Context = callerContext; + } else { + admin1Context = new DpmMockContext(mRealTestContext, "test-admin"); + admin1Context.packageName = admin1.getPackageName(); + admin1Context.applicationInfo = new ApplicationInfo(); + } + when(admin1Context.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); + + // caller: device admin or delegated certificate installer + callerContext.applicationInfo = new ApplicationInfo(); + final UserHandle callerUser = callerContext.binder.getCallingUserHandle(); + + // system_server + final DpmMockContext serviceContext = mContext; + serviceContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + serviceContext.addPackageContext(callerUser, admin1Context); + serviceContext.addPackageContext(callerUser, callerContext); + + // Install a CA cert as caller + runAsCaller(callerContext, dpms, (dpm) -> { + when(mContext.keyChainConnection.getService().installCaCertificate(caCert)) + .thenReturn(alias); + assertTrue(dpm.installCaCert(callerName, caCert)); + }); + + // Fake the CA cert as having been installed + when(serviceContext.keyChainConnection.getService().getUserCaAliases()) .thenReturn(asSlice(new String[] {alias})); - mContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)); + serviceContext.injectBroadcast(new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED) + .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier())); flushTasks(); - // Removing the Profile Owner should clear the information which CA certs were installed - // by it. - mContext.packageName = admin1.getPackageName(); - mContext.binder.callingUid = DpmMockContext.CALLER_UID; - dpm.clearProfileOwner(admin1); - mContext.packageName = "com.android.frameworks.servicestests"; - mContext.binder.clearCallingIdentity(); - final List<String> ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(user); - assertNotNull(ownerInstalledCaCerts); - assertTrue(ownerInstalledCaCerts.isEmpty()); + // Removing the Profile Owner should clear the information on which CA certs were installed + runAsCaller(admin1Context, dpms, (dpm) -> { + dpm.clearProfileOwner(admin1); + }); + + runAsCaller(serviceContext, dpms, (dpm) -> { + final List<String> ownerInstalledCaCerts = dpm.getOwnerInstalledCaCerts(callerUser); + assertNotNull(ownerInstalledCaCerts); + assertTrue(ownerInstalledCaCerts.isEmpty()); + }); } private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) { @@ -4147,29 +4199,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { } private void flushTasks() throws Exception { - Boolean tasksFlushed[] = new Boolean[] {false}; - final Runnable tasksFlushedNotifier = () -> { - synchronized (tasksFlushed) { - tasksFlushed[0] = true; - tasksFlushed.notify(); - } - }; - - // Flush main thread handler. - dpms.mHandler.post(tasksFlushedNotifier); - synchronized (tasksFlushed) { - if (!tasksFlushed[0]) { - tasksFlushed.wait(); - } - } + dpms.mHandler.runWithScissors(() -> {}, 0 /*now*/); + dpms.mBackgroundHandler.runWithScissors(() -> {}, 0 /*now*/); - // Flush background thread handler. - tasksFlushed[0] = false; - dpms.mBackgroundHandler.post(tasksFlushedNotifier); - synchronized (tasksFlushed) { - if (!tasksFlushed[0]) { - tasksFlushed.wait(); - } - } + // We can't let exceptions happen on the background thread. Throw them here if they happen + // so they still cause the test to fail despite being suppressed. + mContext.rethrowBackgroundBroadcastExceptions(); } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 7d017c54002c..1ea12d853556 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -48,6 +48,7 @@ import android.telephony.TelephonyManager; import android.test.mock.MockContentResolver; import android.test.mock.MockContext; import android.util.ArrayMap; +import android.util.Pair; import android.view.IWindowManager; import com.android.internal.widget.LockPatternUtils; @@ -61,6 +62,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; @@ -111,6 +113,7 @@ public class DpmMockContext extends MockContext { public static class MockBinder { public int callingUid = CALLER_UID; public int callingPid = CALLER_PID; + public final Map<Integer, List<String>> callingPermissions = new ArrayMap<>(); public long clearCallingIdentity() { final long token = (((long) callingUid) << 32) | (callingPid); @@ -303,14 +306,19 @@ public class DpmMockContext extends MockContext { /** Note this is a partial mock, not a real mock. */ public final PackageManager packageManager; + /** TODO: Migrate everything to use {@link #permissions} to avoid confusion. */ + @Deprecated public final List<String> callerPermissions = new ArrayList<>(); + /** Less confusing alias for {@link #callerPermissions}. */ + public final List<String> permissions = callerPermissions; + private final ArrayList<UserInfo> mUserInfos = new ArrayList<>(); public final BuildMock buildMock = new BuildMock(); /** Optional mapping of other user contexts for {@link #createPackageContextAsUser} to return */ - public final Map<UserHandle, Context> userContexts = new ArrayMap<>(); + public final Map<Pair<UserHandle, String>, Context> userPackageContexts = new ArrayMap<>(); public String packageName = null; @@ -324,6 +332,9 @@ public class DpmMockContext extends MockContext { public final IntentFilter filter; public final Handler scheduler; + // Exceptions thrown in a background thread kill the whole test. Save them instead. + public final AtomicReference<Exception> backgroundException = new AtomicReference<>(); + public BroadcastReceiverRegistration(BroadcastReceiver receiver, IntentFilter filter, Handler scheduler) { this.receiver = receiver; @@ -337,20 +348,30 @@ public class DpmMockContext extends MockContext { 0 /* type */, false /* ordered */, false /* sticky */, null /* token */, userId, 0 /* flags */); if (filter.match(null, intent, false, "DpmMockContext") > 0) { + final Runnable send = () -> { + receiver.setPendingResult(result); + receiver.onReceive(DpmMockContext.this, intent); + }; if (scheduler != null) { scheduler.post(() -> { - receiver.setPendingResult(result); - receiver.onReceive(DpmMockContext.this, intent); + try { + send.run(); + } catch (Exception e) { + backgroundException.compareAndSet(null, e); + } }); } else { - receiver.setPendingResult(result); - receiver.onReceive(DpmMockContext.this, intent); + send.run(); } } } } private List<BroadcastReceiverRegistration> mBroadcastReceivers = new ArrayList<>(); + public DpmMockContext(Context realTestContext, String name) { + this(realTestContext, new File(realTestContext.getCacheDir(), name)); + } + public DpmMockContext(Context context, File dataDir) { realTestContext = context; @@ -511,13 +532,29 @@ public class DpmMockContext extends MockContext { .thenReturn(isRunning); } - public void injectBroadcast(Intent intent) { + public void injectBroadcast(final Intent intent) { final int userId = UserHandle.getUserId(binder.getCallingUid()); for (final BroadcastReceiverRegistration receiver : mBroadcastReceivers) { receiver.sendBroadcastIfApplicable(userId, intent); } } + public void rethrowBackgroundBroadcastExceptions() throws Exception { + for (final BroadcastReceiverRegistration receiver : mBroadcastReceivers) { + final Exception e = receiver.backgroundException.getAndSet(null); + if (e != null) { + throw e; + } + } + } + + public void addPackageContext(UserHandle user, Context context) { + if (context.getPackageName() == null) { + throw new NullPointerException("getPackageName() == null"); + } + userPackageContexts.put(new Pair<>(user, context.getPackageName()), context); + } + @Override public Resources getResources() { return resources; @@ -576,7 +613,16 @@ public class DpmMockContext extends MockContext { if (binder.getCallingUid() == SYSTEM_UID) { return; // Assume system has all permissions. } - if (!callerPermissions.contains(permission)) { + + List<String> permissions = binder.callingPermissions.get(binder.getCallingUid()); + if (permissions == null) { + // TODO: delete the following line. to do this without breaking any tests, first it's + // necessary to remove all tests that set it directly. + permissions = callerPermissions; +// throw new UnsupportedOperationException( +// "Caller UID " + binder.getCallingUid() + " doesn't exist"); + } + if (!permissions.contains(permission)) { throw new SecurityException("Caller doesn't have " + permission + " : " + message); } } @@ -751,14 +797,11 @@ public class DpmMockContext extends MockContext { @Override public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) throws PackageManager.NameNotFoundException { - if (!userContexts.containsKey(user)) { - return super.createPackageContextAsUser(packageName, flags, user); - } - if (!getPackageName().equals(packageName)) { - throw new UnsupportedOperationException( - "Creating a context as another package is not implemented"); + final Pair<UserHandle, String> key = new Pair<>(user, packageName); + if (userPackageContexts.containsKey(key)) { + return userPackageContexts.get(key); } - return userContexts.get(user); + throw new UnsupportedOperationException("No package " + packageName + " for user " + user); } @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 43e2610e187a..5d68edd6f66b 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -16,6 +16,7 @@ package com.android.server.devicepolicy; +import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -70,6 +71,34 @@ public abstract class DpmTestBase extends AndroidTestCase { return mMockContext; } + protected interface DpmRunnable { + public void run(DevicePolicyManager dpm) throws Exception; + } + + /** + * Simulate an RPC from {@param caller} to the service context ({@link #mContext}). + * + * The caller sees its own context. The server also sees its own separate context, with the + * appropriate calling UID and calling permissions fields already set up. + */ + protected void runAsCaller(DpmMockContext caller, DevicePolicyManagerServiceTestable dpms, + DpmRunnable action) { + final DpmMockContext serviceContext = mMockContext; + + final long origId = serviceContext.binder.clearCallingIdentity(); + try { + serviceContext.binder.callingUid = caller.binder.callingUid; + serviceContext.binder.callingPid = caller.binder.callingPid; + serviceContext.binder.callingPermissions.put(caller.binder.callingUid, + caller.permissions); + action.run(new DevicePolicyManagerTestable(caller, dpms)); + } catch (Exception e) { + throw new AssertionError(e); + } finally { + serviceContext.binder.restoreCallingIdentity(origId); + } + } + protected void markPackageAsInstalled(String packageName, ApplicationInfo ai, int userId) throws Exception { final PackageInfo pi = DpmTestUtils.cloneParcelable( diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 4178f4da7603..4da2853aba41 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -169,6 +169,7 @@ public class UsbDeviceManager { public AdbSettingsObserver() { super(null); } + @Override public void onChange(boolean selfChange) { boolean enable = (Settings.Global.getInt(mContentResolver, @@ -208,9 +209,9 @@ public class UsbDeviceManager { private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); - boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB; - mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging); + int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB; + mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging); } }; @@ -261,9 +262,10 @@ public class UsbDeviceManager { // TV-specific notification channel mNotificationManager.createNotificationChannel( new NotificationChannel(ADB_NOTIFICATION_CHANNEL_ID_TV, - mContext.getString( - com.android.internal.R.string.adb_debugging_notification_channel_tv), - NotificationManager.IMPORTANCE_HIGH)); + mContext.getString( + com.android.internal.R.string + .adb_debugging_notification_channel_tv), + NotificationManager.IMPORTANCE_HIGH)); } // We do not show the USB notification if the primary volume supports mass storage. @@ -309,8 +311,8 @@ public class UsbDeviceManager { boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE); // don't start accessory mode if our mandatory strings have not been set boolean enableAccessory = (mAccessoryStrings != null && - mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null && - mAccessoryStrings[UsbAccessory.MODEL_STRING] != null); + mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null && + mAccessoryStrings[UsbAccessory.MODEL_STRING] != null); String functions = null; if (enableAccessory && enableAudio) { @@ -341,14 +343,14 @@ public class UsbDeviceManager { int serialLength = serial.length(); // XOR the USB serial across the remaining 5 bytes for (int i = 0; i < serialLength; i++) { - address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i); + address[i % (ETH_ALEN - 1) + 1] ^= (int) serial.charAt(i); } String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", - address[0], address[1], address[2], address[3], address[4], address[5]); + address[0], address[1], address[2], address[3], address[4], address[5]); try { FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString); } catch (IOException e) { - Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH); + Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH); } } @@ -400,7 +402,7 @@ public class UsbDeviceManager { // register observer to listen for settings changes mContentResolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), - false, new AdbSettingsObserver()); + false, new AdbSettingsObserver()); // Watch for USB configuration changes mUEventObserver.startObserving(USB_STATE_MATCH); @@ -466,9 +468,9 @@ public class UsbDeviceManager { } SomeArgs args = SomeArgs.obtain(); - args.argi1 = hostConnected ? 1 :0; - args.argi2 = sourcePower ? 1 :0; - args.argi3 = sinkPower ? 1 :0; + args.argi1 = hostConnected ? 1 : 0; + args.argi2 = sourcePower ? 1 : 0; + args.argi3 = sinkPower ? 1 : 0; removeMessages(MSG_UPDATE_HOST_STATE); Message msg = obtainMessage(MSG_UPDATE_HOST_STATE, args); @@ -506,7 +508,7 @@ public class UsbDeviceManager { // Persist the adb setting String newFunction = applyAdbFunction(SystemProperties.get( - USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE)); + USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE)); SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunction); // Remove mtp from the config if file transfer is not enabled @@ -529,8 +531,10 @@ public class UsbDeviceManager { */ private void setEnabledFunctions(String functions, boolean forceRestart, boolean usbDataUnlocked) { - if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " - + "forceRestart=" + forceRestart); + if (DEBUG) { + Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " + + "forceRestart=" + forceRestart); + } if (usbDataUnlocked != mUsbDataUnlocked) { mUsbDataUnlocked = usbDataUnlocked; @@ -680,7 +684,7 @@ public class UsbDeviceManager { } for (String key : keySet) { if (intent.getBooleanExtra(key, false) != - mBroadcastedIntent.getBooleanExtra(key, false)) { + mBroadcastedIntent.getBooleanExtra(key, false)) { return true; } } @@ -697,7 +701,8 @@ public class UsbDeviceManager { intent.putExtra(UsbManager.USB_CONNECTED, mConnected); intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected); intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured); - intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked); + intent.putExtra(UsbManager.USB_DATA_UNLOCKED, + isUsbTransferAllowed() && mUsbDataUnlocked); intent.putExtra(UsbManager.USB_CONFIG_CHANGED, configChanged); if (mCurrentFunctions != null) { @@ -825,7 +830,7 @@ public class UsbDeviceManager { setAdbEnabled(msg.arg1 == 1); break; case MSG_SET_CURRENT_FUNCTIONS: - String functions = (String)msg.obj; + String functions = (String) msg.obj; setEnabledFunctions(functions, false, msg.arg1 == 1); break; case MSG_UPDATE_USER_RESTRICTIONS: @@ -854,9 +859,9 @@ public class UsbDeviceManager { if (mCurrentUser != msg.arg1) { // Restart the USB stack and re-apply user restrictions for MTP or PTP. final boolean active = UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_MTP) + UsbManager.USB_FUNCTION_MTP) || UsbManager.containsFunction(mCurrentFunctions, - UsbManager.USB_FUNCTION_PTP); + UsbManager.USB_FUNCTION_PTP); if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) { Slog.v(TAG, "Current user switched to " + mCurrentUser + "; resetting USB host stack for MTP or PTP"); @@ -885,7 +890,9 @@ public class UsbDeviceManager { private void updateUsbNotification() { if (mNotificationManager == null || !mUseUsbNotification - || ("0".equals(SystemProperties.get("persist.charging.notify")))) return; + || ("0".equals(SystemProperties.get("persist.charging.notify")))) { + return; + } int id = 0; Resources r = mContext.getResources(); if (mConnected) { @@ -937,18 +944,19 @@ public class UsbDeviceManager { Notification notification = new Notification.Builder(mContext, SystemNotificationChannels.USB) - .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) - .setWhen(0) - .setOngoing(true) - .setTicker(title) - .setDefaults(0) // please be quiet - .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setContentTitle(title) - .setContentText(message) - .setContentIntent(pi) - .setVisibility(Notification.VISIBILITY_PUBLIC) - .build(); + .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) + .setWhen(0) + .setOngoing(true) + .setTicker(title) + .setDefaults(0) // please be quiet + .setColor(mContext.getColor( + com.android.internal.R.color + .system_notification_accent_color)) + .setContentTitle(title) + .setContentText(message) + .setContentIntent(pi) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .build(); mNotificationManager.notifyAsUser(null, id, notification, UserHandle.ALL); mUsbNotificationId = id; @@ -976,20 +984,21 @@ public class UsbDeviceManager { Notification notification = new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER) - .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) - .setWhen(0) - .setOngoing(true) - .setTicker(title) - .setDefaults(0) // please be quiet - .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setContentTitle(title) - .setContentText(message) - .setContentIntent(pi) - .setVisibility(Notification.VISIBILITY_PUBLIC) - .extend(new Notification.TvExtender() - .setChannel(ADB_NOTIFICATION_CHANNEL_ID_TV)) - .build(); + .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) + .setWhen(0) + .setOngoing(true) + .setTicker(title) + .setDefaults(0) // please be quiet + .setColor(mContext.getColor( + com.android.internal.R.color + .system_notification_accent_color)) + .setContentTitle(title) + .setContentText(message) + .setContentIntent(pi) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .extend(new Notification.TvExtender() + .setChannel(ADB_NOTIFICATION_CHANNEL_ID_TV)) + .build(); mAdbNotificationShown = true; mNotificationManager.notifyAsUser(null, id, notification, UserHandle.ALL); @@ -1038,7 +1047,8 @@ public class UsbDeviceManager { } /* opens the currently attached USB accessory */ - public ParcelFileDescriptor openAccessory(UsbAccessory accessory, UsbUserSettingsManager settings) { + public ParcelFileDescriptor openAccessory(UsbAccessory accessory, + UsbUserSettingsManager settings) { UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); if (currentAccessory == null) { throw new IllegalArgumentException("no accessory attached"); @@ -1058,17 +1068,19 @@ public class UsbDeviceManager { } public void setCurrentFunctions(String functions, boolean usbDataUnlocked) { - if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ", " + - usbDataUnlocked + ")"); + if (DEBUG) { + Slog.d(TAG, "setCurrentFunctions(" + functions + ", " + + usbDataUnlocked + ")"); + } mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked); } private void readOemUsbOverrideConfig() { String[] configList = mContext.getResources().getStringArray( - com.android.internal.R.array.config_oemUsbModeOverride); + com.android.internal.R.array.config_oemUsbModeOverride); if (configList != null) { - for (String config: configList) { + for (String config : configList) { String[] items = config.split(":"); if (items.length == 3) { if (mOemModeMap == null) { @@ -1092,7 +1104,7 @@ public class UsbDeviceManager { List<Pair<String, String>> overrides = mOemModeMap.get(bootMode); if (overrides != null) { - for (Pair<String, String> pair: overrides) { + for (Pair<String, String> pair : overrides) { if (pair.first.equals(usbFunctions)) { Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second); return pair.second; @@ -1120,7 +1132,7 @@ public class UsbDeviceManager { mDebuggingManager.clearUsbDebuggingKeys(); } else { throw new RuntimeException("Cannot clear Usb Debugging keys, " - + "UsbDebuggingManager not enabled"); + + "UsbDebuggingManager not enabled"); } } @@ -1134,7 +1146,10 @@ public class UsbDeviceManager { } private native String[] nativeGetAccessoryStrings(); + private native ParcelFileDescriptor nativeOpenAccessory(); + private native boolean nativeIsStartRequested(); + private native int nativeGetAudioMode(); } diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java index 54ab19d0898f..2516d5129dc8 100644 --- a/telephony/java/android/telephony/PreciseDisconnectCause.java +++ b/telephony/java/android/telephony/PreciseDisconnectCause.java @@ -25,75 +25,480 @@ package android.telephony; public class PreciseDisconnectCause { /** The disconnect cause is not valid (Not received a disconnect cause)*/ - public static final int NOT_VALID = -1; + public static final int NOT_VALID = -1; /** No disconnect cause provided. Generally a local disconnect or an incoming missed call */ - public static final int NO_DISCONNECT_CAUSE_AVAILABLE = 0; + public static final int NO_DISCONNECT_CAUSE_AVAILABLE = 0; /** * The destination cannot be reached because the number, although valid, * is not currently assigned */ - public static final int UNOBTAINABLE_NUMBER = 1; + public static final int UNOBTAINABLE_NUMBER = 1; + /** The user cannot be reached because the network through which the call has been + * routed does not serve the destination desired + */ + public static final int NO_ROUTE_TO_DESTINATION = 3; + /** The channel most recently identified is not acceptable to the sending entity for + * use in this call + */ + public static final int CHANNEL_UNACCEPTABLE = 6; + /** The MS has tried to access a service that the MS's network operator or service + * provider is not prepared to allow + */ + public static final int OPERATOR_DETERMINED_BARRING = 8; /** One of the users involved in the call has requested that the call is cleared */ - public static final int NORMAL = 16; + public static final int NORMAL = 16; /** The called user is unable to accept another call */ - public static final int BUSY = 17; + public static final int BUSY = 17; + /** The user does not respond to a call establishment message with either an alerting + * or connect indication within the prescribed period of time allocated + */ + public static final int NO_USER_RESPONDING = 18; + /** The user has provided an alerting indication but has not provided a connect + * indication within a prescribed period of time + */ + public static final int NO_ANSWER_FROM_USER = 19; + /** The equipment sending this cause does not wish to accept this call */ + public static final int CALL_REJECTED = 21; /** The called number is no longer assigned */ - public static final int NUMBER_CHANGED = 22; + public static final int NUMBER_CHANGED = 22; + /** This cause is returned to the network when a mobile station clears an active + * call which is being pre-empted by another call with higher precedence + */ + public static final int PREEMPTION = 25; + /** The destination indicated by the mobile station cannot be reached because + * the interface to the destination is not functioning correctly + */ + public static final int DESTINATION_OUT_OF_ORDER = 27; + /** The called party number is not a valid format or is not complete */ + public static final int INVALID_NUMBER_FORMAT = 28; + /** The facility requested by user can not be provided by the network */ + public static final int FACILITY_REJECTED = 29; /** Provided in response to a STATUS ENQUIRY message */ - public static final int STATUS_ENQUIRY = 30; + public static final int STATUS_ENQUIRY = 30; /** Reports a normal disconnect only when no other normal cause applies */ - public static final int NORMAL_UNSPECIFIED = 31; + public static final int NORMAL_UNSPECIFIED = 31; /** There is no channel presently available to handle the call */ - public static final int NO_CIRCUIT_AVAIL = 34; + public static final int NO_CIRCUIT_AVAIL = 34; + /** The network is not functioning correctly and that the condition is likely + * to last a relatively long period of time + */ + public static final int NETWORK_OUT_OF_ORDER = 38; /** * The network is not functioning correctly and the condition is not likely to last * a long period of time */ - public static final int TEMPORARY_FAILURE = 41; + public static final int TEMPORARY_FAILURE = 41; /** The switching equipment is experiencing a period of high traffic */ - public static final int SWITCHING_CONGESTION = 42; + public static final int SWITCHING_CONGESTION = 42; + /** The network could not deliver access information to the remote user as requested */ + public static final int ACCESS_INFORMATION_DISCARDED = 43; /** The channel cannot be provided */ - public static final int CHANNEL_NOT_AVAIL = 44; + public static final int CHANNEL_NOT_AVAIL = 44; + /** This cause is used to report a resource unavailable event only when no other + * cause in the resource unavailable class applies + */ + public static final int RESOURCES_UNAVAILABLE_OR_UNSPECIFIED = 44; /** The requested quality of service (ITU-T X.213) cannot be provided */ - public static final int QOS_NOT_AVAIL = 49; + public static final int QOS_NOT_AVAIL = 49; + /** The facility could not be provided by the network because the user has no + * complete subscription + */ + public static final int REQUESTED_FACILITY_NOT_SUBSCRIBED = 50; + /** Incoming calls are not allowed within this CUG */ + public static final int INCOMING_CALLS_BARRED_WITHIN_CUG = 55; + /** The mobile station is not authorized to use bearer capability requested */ + public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 57; /** The requested bearer capability is not available at this time */ - public static final int BEARER_NOT_AVAIL = 58; + public static final int BEARER_NOT_AVAIL = 58; + /** The service option is not availble at this time */ + public static final int SERVICE_OPTION_NOT_AVAILABLE = 63; + /** The equipment sending this cause does not support the bearer capability requested */ + public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 65; /** The call clearing is due to ACM being greater than or equal to ACMmax */ - public static final int ACM_LIMIT_EXCEEDED = 68; + public static final int ACM_LIMIT_EXCEEDED = 68; + /** The equipment sending this cause does not support the requested facility */ + public static final int REQUESTED_FACILITY_NOT_IMPLEMENTED = 69; + /** The equipment sending this cause only supports the restricted version of + * the requested bearer capability + */ + public static final int ONLY_DIGITAL_INFORMATION_BEARER_AVAILABLE = 70; + /** The service requested is not implemented at network */ + public static final int SERVICE_OR_OPTION_NOT_IMPLEMENTED = 79; + /** The equipment sending this cause has received a message with a transaction identifier + * which is not currently in use on the MS-network interface + */ + public static final int INVALID_TRANSACTION_IDENTIFIER = 81; + /** The called user for the incoming CUG call is not a member of the specified CUG */ + public static final int USER_NOT_MEMBER_OF_CUG = 87; + /** The equipment sending this cause has received a request which can't be accomodated */ + public static final int INCOMPATIBLE_DESTINATION = 88; + /** This cause is used to report receipt of a message with semantically incorrect contents */ + public static final int SEMANTICALLY_INCORRECT_MESSAGE = 95; + /** The equipment sending this cause has received a message with a non-semantical + * mandatory IE error + */ + public static final int INVALID_MANDATORY_INFORMATION = 96; + /** This is sent in response to a message which is not defined, or defined but not + * implemented by the equipment sending this cause + */ + public static final int MESSAGE_TYPE_NON_IMPLEMENTED = 97; + /** The equipment sending this cause has received a message not compatible with the + * protocol state + */ + public static final int MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 98; + /** The equipment sending this cause has received a message which includes information + * elements not recognized because its identifier is not defined or it is defined but not + * implemented by the equipment sending the cause + */ + public static final int INFORMATION_ELEMENT_NON_EXISTENT = 99; + /** The equipment sending this cause has received a message with conditional IE errors */ + public static final int CONDITIONAL_IE_ERROR = 100; + /** The message has been received which is incompatible with the protocol state */ + public static final int MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE = 101; + /** The procedure has been initiated by the expiry of a timer in association with + * 3GPP TS 24.008 error handling procedures + */ + public static final int RECOVERY_ON_TIMER_EXPIRED = 102; + /** This protocol error event is reported only when no other cause in the protocol + * error class applies + */ + public static final int PROTOCOL_ERROR_UNSPECIFIED = 111; + /** interworking with a network which does not provide causes for actions it takes + * thus, the precise cause for a message which is being sent cannot be ascertained + */ + public static final int INTERWORKING_UNSPECIFIED = 127; /** The call is restricted */ - public static final int CALL_BARRED = 240; + public static final int CALL_BARRED = 240; /** The call is blocked by the Fixed Dialing Number list */ - public static final int FDN_BLOCKED = 241; + public static final int FDN_BLOCKED = 241; /** The given IMSI is not known at the VLR */ /** TS 24.008 cause 4 */ - public static final int IMSI_UNKNOWN_IN_VLR = 242; + public static final int IMSI_UNKNOWN_IN_VLR = 242; /** * The network does not accept emergency call establishment using an IMEI or not accept attach * procedure for emergency services using an IMEI */ - public static final int IMEI_NOT_ACCEPTED = 243; + public static final int IMEI_NOT_ACCEPTED = 243; + /** The call cannot be established because RADIO is OFF */ + public static final int RADIO_OFF = 247; + /** The call cannot be established because of no cell coverage */ + public static final int OUT_OF_SRV = 248; + /** The call cannot be established because of no valid SIM */ + public static final int NO_VALID_SIM = 249; + /** The call is dropped or failed internally by modem */ + public static final int RADIO_INTERNAL_ERROR = 250; + /** Call failed because of UE timer expired while waiting for a response from network */ + public static final int NETWORK_RESP_TIMEOUT = 251; + /** Call failed because of a network reject */ + public static final int NETWORK_REJECT = 252; + /** Call failed because of radio access failure. ex. RACH failure */ + public static final int RADIO_ACCESS_FAILURE = 253; + /** Call failed/dropped because of a RLF */ + public static final int RADIO_LINK_FAILURE = 254; + /** Call failed/dropped because of radio link lost */ + public static final int RADIO_LINK_LOST = 255; + /** Call failed because of a radio uplink issue */ + public static final int RADIO_UPLINK_FAILURE = 256; + /** Call failed because of a RRC connection setup failure */ + public static final int RADIO_SETUP_FAILURE = 257; + /** Call failed/dropped because of RRC connection release from NW */ + public static final int RADIO_RELEASE_NORMAL = 258; + /** Call failed/dropped because of RRC abnormally released by modem/network */ + public static final int RADIO_RELEASE_ABNORMAL = 259; + /** Call setup failed because of access class barring */ + public static final int ACCESS_CLASS_BLOCKED = 260; + /** Call failed/dropped because of a network detach */ + public static final int NETWORK_DETACH = 261; + /** MS is locked until next power cycle */ - public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; + public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; /** Drop call*/ - public static final int CDMA_DROP = 1001; + public static final int CDMA_DROP = 1001; /** INTERCEPT order received, MS state idle entered */ - public static final int CDMA_INTERCEPT = 1002; + public static final int CDMA_INTERCEPT = 1002; /** MS has been redirected, call is cancelled */ - public static final int CDMA_REORDER = 1003; + public static final int CDMA_REORDER = 1003; /** Service option rejection */ - public static final int CDMA_SO_REJECT = 1004; + public static final int CDMA_SO_REJECT = 1004; /** Requested service is rejected, retry delay is set */ - public static final int CDMA_RETRY_ORDER = 1005; + public static final int CDMA_RETRY_ORDER = 1005; /** Unable to obtain access to the CDMA system */ - public static final int CDMA_ACCESS_FAILURE = 1006; + public static final int CDMA_ACCESS_FAILURE = 1006; /** Not a preempted call */ - public static final int CDMA_PREEMPTED = 1007; + public static final int CDMA_PREEMPTED = 1007; /** Not an emergency call */ - public static final int CDMA_NOT_EMERGENCY = 1008; + public static final int CDMA_NOT_EMERGENCY = 1008; /** Access Blocked by CDMA network */ - public static final int CDMA_ACCESS_BLOCKED = 1009; + public static final int CDMA_ACCESS_BLOCKED = 1009; + + /** Mapped from ImsReasonInfo */ + /* The passed argument is an invalid */ + public static final int LOCAL_ILLEGAL_ARGUMENT = 1200; + // The operation is invoked in invalid call state + public static final int LOCAL_ILLEGAL_STATE = 1201; + // IMS service internal error + public static final int LOCAL_INTERNAL_ERROR = 1202; + // IMS service goes down (service connection is lost) + public static final int LOCAL_IMS_SERVICE_DOWN = 1203; + // No pending incoming call exists + public static final int LOCAL_NO_PENDING_CALL = 1204; + // Service unavailable; by power off + public static final int LOCAL_POWER_OFF = 1205; + // Service unavailable; by low battery + public static final int LOCAL_LOW_BATTERY = 1206; + // Service unavailable; by out of service (data service state) + public static final int LOCAL_NETWORK_NO_SERVICE = 1207; + /* Service unavailable; by no LTE coverage + * (VoLTE is not supported even though IMS is registered) + */ + public static final int LOCAL_NETWORK_NO_LTE_COVERAGE = 1208; + /** Service unavailable; by located in roaming area */ + public static final int LOCAL_NETWORK_ROAMING = 1209; + /** Service unavailable; by IP changed */ + public static final int LOCAL_NETWORK_IP_CHANGED = 1210; + /** Service unavailable; other */ + public static final int LOCAL_SERVICE_UNAVAILABLE = 1211; + /* Service unavailable; IMS connection is lost (IMS is not registered) */ + public static final int LOCAL_NOT_REGISTERED = 1212; + /** Max call exceeded */ + public static final int LOCAL_MAX_CALL_EXCEEDED = 1213; + /** Call decline */ + public static final int LOCAL_CALL_DECLINE = 1214; + /** SRVCC is in progress */ + public static final int LOCAL_CALL_VCC_ON_PROGRESSING = 1215; + /** Resource reservation is failed (QoS precondition) */ + public static final int LOCAL_CALL_RESOURCE_RESERVATION_FAILED = 1216; + /** Retry CS call; VoLTE service can't be provided by the network or remote end + * Resolve the extra code(EXTRA_CODE_CALL_RETRY_*) if the below code is set + */ + public static final int LOCAL_CALL_CS_RETRY_REQUIRED = 1217; + /** Retry VoLTE call; VoLTE service can't be provided by the network temporarily */ + public static final int LOCAL_CALL_VOLTE_RETRY_REQUIRED = 1218; + /** IMS call is already terminated (in TERMINATED state) */ + public static final int LOCAL_CALL_TERMINATED = 1219; + /** Handover not feasible */ + public static final int LOCAL_HO_NOT_FEASIBLE = 1220; + + /** 1xx waiting timer is expired after sending INVITE request (MO only) */ + public static final int TIMEOUT_1XX_WAITING = 1221; + /** User no answer during call setup operation (MO/MT) + * MO : 200 OK to INVITE request is not received, + * MT : No action from user after alerting the call + */ + public static final int TIMEOUT_NO_ANSWER = 1222; + /** User no answer during call update operation (MO/MT) + * MO : 200 OK to re-INVITE request is not received, + * MT : No action from user after alerting the call + */ + public static final int TIMEOUT_NO_ANSWER_CALL_UPDATE = 1223; + + /** + * STATUSCODE (SIP response code) (IMS -> Telephony) + */ + /** SIP request is redirected */ + public static final int SIP_REDIRECTED = 1300; + /** 4xx responses */ + /** 400 : Bad Request */ + public static final int SIP_BAD_REQUEST = 1310; + /** 403 : Forbidden */ + public static final int SIP_FORBIDDEN = 1311; + /** 404 : Not Found */ + public static final int SIP_NOT_FOUND = 1312; + /** 415 : Unsupported Media Type + * 416 : Unsupported URI Scheme + * 420 : Bad Extension + */ + public static final int SIP_NOT_SUPPORTED = 1313; + /** 408 : Request Timeout */ + public static final int SIP_REQUEST_TIMEOUT = 1314; + /** 480 : Temporarily Unavailable */ + public static final int SIP_TEMPRARILY_UNAVAILABLE = 1315; + /** 484 : Address Incomplete */ + public static final int SIP_BAD_ADDRESS = 1316; + /** 486 : Busy Here + * 600 : Busy Everywhere + */ + public static final int SIP_BUSY = 1317; + /** 487 : Request Terminated */ + public static final int SIP_REQUEST_CANCELLED = 1318; + /** 406 : Not Acceptable + * 488 : Not Acceptable Here + * 606 : Not Acceptable + */ + public static final int SIP_NOT_ACCEPTABLE = 1319; + /** 410 : Gone + * 604 : Does Not Exist Anywhere + */ + public static final int SIP_NOT_REACHABLE = 1320; + /** Others */ + public static final int SIP_CLIENT_ERROR = 1321; + /** 5xx responses + * 501 : Server Internal Error + */ + public static final int SIP_SERVER_INTERNAL_ERROR = 1330; + /** 503 : Service Unavailable */ + public static final int SIP_SERVICE_UNAVAILABLE = 1331; + /** 504 : Server Time-out */ + public static final int SIP_SERVER_TIMEOUT = 1332; + /** Others */ + public static final int SIP_SERVER_ERROR = 1333; + /** 6xx responses + * 603 : Decline + */ + public static final int SIP_USER_REJECTED = 1340; + /** Others */ + public static final int SIP_GLOBAL_ERROR = 1341; + /** Emergency failure */ + public static final int EMERGENCY_TEMP_FAILURE = 1342; + public static final int EMERGENCY_PERM_FAILURE = 1343; + /** Media resource initialization failed */ + public static final int MEDIA_INIT_FAILED = 1400; + /** RTP timeout (no audio / video traffic in the session) */ + public static final int MEDIA_NO_DATA = 1401; + /** Media is not supported; so dropped the call */ + public static final int MEDIA_NOT_ACCEPTABLE = 1402; + /** Unknown media related errors */ + public static final int MEDIA_UNSPECIFIED = 1403; + /** User triggers the call end */ + public static final int USER_TERMINATED = 1500; + /** No action while an incoming call is ringing */ + public static final int USER_NOANSWER = 1501; + /** User ignores an incoming call */ + public static final int USER_IGNORE = 1502; + /** User declines an incoming call */ + public static final int USER_DECLINE = 1503; + /** Device declines/ends a call due to low battery */ + public static final int LOW_BATTERY = 1504; + /** Device declines call due to blacklisted call ID */ + public static final int BLACKLISTED_CALL_ID = 1505; + /** The call is terminated by the network or remote user */ + public static final int USER_TERMINATED_BY_REMOTE = 1510; + + /** + * UT + */ + public static final int UT_NOT_SUPPORTED = 1800; + public static final int UT_SERVICE_UNAVAILABLE = 1801; + public static final int UT_OPERATION_NOT_ALLOWED = 1802; + public static final int UT_NETWORK_ERROR = 1803; + public static final int UT_CB_PASSWORD_MISMATCH = 1804; + + /** + * ECBM + */ + public static final int ECBM_NOT_SUPPORTED = 1900; + + /** + * Fail code used to indicate that Multi-endpoint is not supported by the Ims framework. + */ + public static final int MULTIENDPOINT_NOT_SUPPORTED = 1901; + + /** + * CALL DROP error codes (Call could drop because of many reasons like Network not available, + * handover, failed, etc) + */ + + /** + * CALL DROP error code for the case when a device is ePDG capable and when the user is on an + * active wifi call and at the edge of coverage and there is no qualified LTE network available + * to handover the call to. We get a handover NOT_TRIGERRED message from the modem. This error + * code is received as part of the handover message. + */ + public static final int CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE = 2000; + + /** + * MT call has ended due to a release from the network + * because the call was answered elsewhere + */ + public static final int ANSWERED_ELSEWHERE = 2100; + + /** + * For MultiEndpoint - Call Pull request has failed + */ + public static final int CALL_PULL_OUT_OF_SYNC = 2101; + + /** + * For MultiEndpoint - Call has been pulled from primary to secondary + */ + public static final int CALL_PULLED = 2102; + + /** + * Supplementary services (HOLD/RESUME) failure error codes. + * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision. + */ + public static final int SUPP_SVC_FAILED = 2300; + public static final int SUPP_SVC_CANCELLED = 2301; + public static final int SUPP_SVC_REINVITE_COLLISION = 2302; + + /** + * DPD Procedure received no response or send failed + */ + public static final int IWLAN_DPD_FAILURE = 2400; + + /** + * Establishment of the ePDG Tunnel Failed + */ + public static final int EPDG_TUNNEL_ESTABLISH_FAILURE = 2500; + + /** + * Re-keying of the ePDG Tunnel Failed; may not always result in teardown + */ + public static final int EPDG_TUNNEL_REKEY_FAILURE = 2501; + + /** + * Connection to the packet gateway is lost + */ + public static final int EPDG_TUNNEL_LOST_CONNECTION = 2502; + + /** + * The maximum number of calls allowed has been reached. Used in a multi-endpoint scenario + * where the number of calls across all connected devices has reached the maximum. + */ + public static final int MAXIMUM_NUMBER_OF_CALLS_REACHED = 2503; + + /** + * Similar to {@link #CODE_LOCAL_CALL_DECLINE}, except indicates that a remote device has + * declined the call. Used in a multi-endpoint scenario where a remote device declined an + * incoming call. + */ + public static final int REMOTE_CALL_DECLINE = 2504; + + /** + * Indicates the call was disconnected due to the user reaching their data limit. + */ + public static final int DATA_LIMIT_REACHED = 2505; + + /** + * Indicates the call was disconnected due to the user disabling cellular data. + */ + public static final int DATA_DISABLED = 2506; + + /** + * Indicates a call was disconnected due to loss of wifi signal. + */ + public static final int WIFI_LOST = 2507; + + + /* OEM specific error codes. To be used by OEMs when they don't want to + reveal error code which would be replaced by ERROR_UNSPECIFIED */ + public static final int OEM_CAUSE_1 = 0xf001; + public static final int OEM_CAUSE_2 = 0xf002; + public static final int OEM_CAUSE_3 = 0xf003; + public static final int OEM_CAUSE_4 = 0xf004; + public static final int OEM_CAUSE_5 = 0xf005; + public static final int OEM_CAUSE_6 = 0xf006; + public static final int OEM_CAUSE_7 = 0xf007; + public static final int OEM_CAUSE_8 = 0xf008; + public static final int OEM_CAUSE_9 = 0xf009; + public static final int OEM_CAUSE_10 = 0xf00a; + public static final int OEM_CAUSE_11 = 0xf00b; + public static final int OEM_CAUSE_12 = 0xf00c; + public static final int OEM_CAUSE_13 = 0xf00d; + public static final int OEM_CAUSE_14 = 0xf00e; + public static final int OEM_CAUSE_15 = 0xf00f; + /** Disconnected due to unspecified reasons */ - public static final int ERROR_UNSPECIFIED = 0xffff; + public static final int ERROR_UNSPECIFIED = 0xffff; /** Private constructor to avoid class instantiation. */ private PreciseDisconnectCause() { diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java index e4f380f7a749..bd8492b3e9d2 100644 --- a/telephony/java/com/android/ims/ImsReasonInfo.java +++ b/telephony/java/com/android/ims/ImsReasonInfo.java @@ -318,6 +318,66 @@ public class ImsReasonInfo implements Parcelable { */ public static final int CODE_IKEV2_AUTH_FAILURE = 1408; + /** The call cannot be established because RADIO is OFF */ + public static final int CODE_RADIO_OFF = 1500; + + /** The call cannot be established because of no valid SIM */ + public static final int CODE_NO_VALID_SIM = 1501; + + /** The failure is due internal error at modem */ + public static final int CODE_RADIO_INTERNAL_ERROR = 1502; + + /** The failure is due to UE timer expired while waiting for a response from network */ + public static final int CODE_NETWORK_RESP_TIMEOUT = 1503; + + /** The failure is due to explicit reject from network */ + public static final int CODE_NETWORK_REJECT = 1504; + + /** The failure is due to radio access failure. ex. RACH failure */ + public static final int CODE_RADIO_ACCESS_FAILURE = 1505; + + /** Call/IMS registration failed/dropped because of a RLF */ + public static final int CODE_RADIO_LINK_FAILURE = 1506; + + /** Call/IMS registration failed/dropped because of radio link lost */ + public static final int CODE_RADIO_LINK_LOST = 1507; + + /** The call Call/IMS registration failed because of a radio uplink issue */ + public static final int CODE_RADIO_UPLINK_FAILURE = 1508; + + /** Call failed because of a RRC connection setup failure */ + public static final int CODE_RADIO_SETUP_FAILURE = 1509; + + /** Call failed/dropped because of RRC connection release from NW */ + public static final int CODE_RADIO_RELEASE_NORMAL = 1510; + + /** Call failed/dropped because of RRC abnormally released by modem/network */ + public static final int CODE_RADIO_RELEASE_ABNORMAL = 1511; + + /** Call failed because of access class barring */ + public static final int CODE_ACCESS_CLASS_BLOCKED = 1512; + + /** Call/IMS registration is failed/dropped because of a network detach */ + public static final int CODE_NETWORK_DETACH = 1513; + + /* OEM specific error codes. To be used by OEMs when they don't want to + reveal error code which would be replaced by ERROR_UNSPECIFIED */ + public static final int CODE_OEM_CAUSE_1 = 0xf001; + public static final int CODE_OEM_CAUSE_2 = 0xf002; + public static final int CODE_OEM_CAUSE_3 = 0xf003; + public static final int CODE_OEM_CAUSE_4 = 0xf004; + public static final int CODE_OEM_CAUSE_5 = 0xf005; + public static final int CODE_OEM_CAUSE_6 = 0xf006; + public static final int CODE_OEM_CAUSE_7 = 0xf007; + public static final int CODE_OEM_CAUSE_8 = 0xf008; + public static final int CODE_OEM_CAUSE_9 = 0xf009; + public static final int CODE_OEM_CAUSE_10 = 0xf00a; + public static final int CODE_OEM_CAUSE_11 = 0xf00b; + public static final int CODE_OEM_CAUSE_12 = 0xf00c; + public static final int CODE_OEM_CAUSE_13 = 0xf00d; + public static final int CODE_OEM_CAUSE_14 = 0xf00e; + public static final int CODE_OEM_CAUSE_15 = 0xf00f; + /** * Network string error messages. * mExtraMessage may have these values. diff --git a/tools/aapt2/AppInfo.h b/tools/aapt2/AppInfo.h index 1e488f70bd4d..9db21aadb242 100644 --- a/tools/aapt2/AppInfo.h +++ b/tools/aapt2/AppInfo.h @@ -23,30 +23,22 @@ namespace aapt { -/** - * Holds basic information about the app being built. Most of this information - * will come from the app's AndroidManifest. - */ +// Information relevant to building an app, parsed from the app's AndroidManifest.xml. struct AppInfo { - /** - * App's package name. - */ + // The app's package name. std::string package; - /** - * The App's minimum SDK version. - */ + // The app's minimum SDK version, if it is defined. Maybe<std::string> min_sdk_version; - /** - * The Version code of the app. - */ + // The app's version code, if it is defined. Maybe<uint32_t> version_code; - /** - * The revision code of the app. - */ + // The app's revision code, if it is defined. Maybe<uint32_t> revision_code; + + // The app's split name, if it is a split. + Maybe<std::string> split_name; }; } // namespace aapt diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp index 10421115b629..1b4d5bb4f6e1 100644 --- a/tools/aapt2/link/Link.cpp +++ b/tools/aapt2/link/Link.cpp @@ -751,70 +751,67 @@ class LinkCommand { return true; } - Maybe<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, - IDiagnostics* diag) { + Maybe<AppInfo> ExtractAppInfoFromManifest(xml::XmlResource* xml_res, IDiagnostics* diag) { // Make sure the first element is <manifest> with package attribute. - if (xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get())) { - AppInfo app_info; + xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get()); + if (manifest_el == nullptr) { + return {}; + } + + AppInfo app_info; + + if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") { + diag->Error(DiagMessage(xml_res->file.source) << "root tag must be <manifest>"); + return {}; + } - if (!manifest_el->namespace_uri.empty() || - manifest_el->name != "manifest") { - diag->Error(DiagMessage(xml_res->file.source) - << "root tag must be <manifest>"); + xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package"); + if (!package_attr) { + diag->Error(DiagMessage(xml_res->file.source) + << "<manifest> must have a 'package' attribute"); + return {}; + } + app_info.package = package_attr->value; + + if (xml::Attribute* version_code_attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) { + Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(version_code_attr->value); + if (!maybe_code) { + diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number)) + << "invalid android:versionCode '" << version_code_attr->value << "'"); return {}; } + app_info.version_code = maybe_code.value(); + } - xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package"); - if (!package_attr) { - diag->Error(DiagMessage(xml_res->file.source) - << "<manifest> must have a 'package' attribute"); + if (xml::Attribute* revision_code_attr = + manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) { + Maybe<uint32_t> maybe_code = ResourceUtils::ParseInt(revision_code_attr->value); + if (!maybe_code) { + diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number)) + << "invalid android:revisionCode '" << revision_code_attr->value << "'"); return {}; } + app_info.revision_code = maybe_code.value(); + } - app_info.package = package_attr->value; - - if (xml::Attribute* version_code_attr = - manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) { - Maybe<uint32_t> maybe_code = - ResourceUtils::ParseInt(version_code_attr->value); - if (!maybe_code) { - diag->Error(DiagMessage(xml_res->file.source.WithLine( - manifest_el->line_number)) - << "invalid android:versionCode '" - << version_code_attr->value << "'"); - return {}; - } - app_info.version_code = maybe_code.value(); - } - - if (xml::Attribute* revision_code_attr = - manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) { - Maybe<uint32_t> maybe_code = - ResourceUtils::ParseInt(revision_code_attr->value); - if (!maybe_code) { - diag->Error(DiagMessage(xml_res->file.source.WithLine( - manifest_el->line_number)) - << "invalid android:revisionCode '" - << revision_code_attr->value << "'"); - return {}; - } - app_info.revision_code = maybe_code.value(); + if (xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) { + if (!split_name_attr->value.empty()) { + app_info.split_name = split_name_attr->value; } + } - if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) { - if (xml::Attribute* min_sdk = uses_sdk_el->FindAttribute( - xml::kSchemaAndroid, "minSdkVersion")) { - app_info.min_sdk_version = min_sdk->value; - } + if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) { + if (xml::Attribute* min_sdk = + uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) { + app_info.min_sdk_version = min_sdk->value; } - return app_info; } - return {}; + return app_info; } /** - * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it - * linked. + * Precondition: ResourceTable doesn't have any IDs assigned yet, nor is it linked. * Postcondition: ResourceTable has only one package left. All others are * stripped, or there is an error and false is returned. */ @@ -1367,45 +1364,44 @@ class LinkCommand { return true; } - std::unique_ptr<xml::XmlResource> GenerateSplitManifest( - const AppInfo& app_info, const SplitConstraints& constraints) { - std::unique_ptr<xml::XmlResource> doc = - util::make_unique<xml::XmlResource>(); + std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, + const SplitConstraints& constraints) { + std::unique_ptr<xml::XmlResource> doc = util::make_unique<xml::XmlResource>(); - std::unique_ptr<xml::Namespace> namespace_android = - util::make_unique<xml::Namespace>(); + std::unique_ptr<xml::Namespace> namespace_android = util::make_unique<xml::Namespace>(); namespace_android->namespace_uri = xml::kSchemaAndroid; namespace_android->namespace_prefix = "android"; - std::unique_ptr<xml::Element> manifest_el = - util::make_unique<xml::Element>(); + std::unique_ptr<xml::Element> manifest_el = util::make_unique<xml::Element>(); manifest_el->name = "manifest"; - manifest_el->attributes.push_back( - xml::Attribute{"", "package", app_info.package}); + manifest_el->attributes.push_back(xml::Attribute{"", "package", app_info.package}); if (app_info.version_code) { - manifest_el->attributes.push_back( - xml::Attribute{xml::kSchemaAndroid, "versionCode", - std::to_string(app_info.version_code.value())}); + manifest_el->attributes.push_back(xml::Attribute{ + xml::kSchemaAndroid, "versionCode", std::to_string(app_info.version_code.value())}); } if (app_info.revision_code) { - manifest_el->attributes.push_back( - xml::Attribute{xml::kSchemaAndroid, "revisionCode", - std::to_string(app_info.revision_code.value())}); + manifest_el->attributes.push_back(xml::Attribute{ + xml::kSchemaAndroid, "revisionCode", std::to_string(app_info.revision_code.value())}); } std::stringstream split_name; + if (app_info.split_name) { + split_name << app_info.split_name.value() << "."; + } split_name << "config." << util::Joiner(constraints.configs, "_"); - manifest_el->attributes.push_back( - xml::Attribute{"", "split", split_name.str()}); + manifest_el->attributes.push_back(xml::Attribute{"", "split", split_name.str()}); + + if (app_info.split_name) { + manifest_el->attributes.push_back( + xml::Attribute{"", "configForSplit", app_info.split_name.value()}); + } - std::unique_ptr<xml::Element> application_el = - util::make_unique<xml::Element>(); + std::unique_ptr<xml::Element> application_el = util::make_unique<xml::Element>(); application_el->name = "application"; - application_el->attributes.push_back( - xml::Attribute{xml::kSchemaAndroid, "hasCode", "false"}); + application_el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, "hasCode", "false"}); manifest_el->AppendChild(std::move(application_el)); namespace_android->AppendChild(std::move(manifest_el)); diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp index 313fe453dff5..0c19c7ad7f32 100644 --- a/tools/aapt2/link/ManifestFixer.cpp +++ b/tools/aapt2/link/ManifestFixer.cpp @@ -29,10 +29,7 @@ using android::StringPiece; namespace aapt { -/** - * This is how PackageManager builds class names from AndroidManifest.xml - * entries. - */ +// This is how PackageManager builds class names from AndroidManifest.xml entries. static bool NameIsJavaClassName(xml::Element* el, xml::Attribute* attr, SourcePathDiagnostics* diag) { // We allow unqualified class names (ie: .HelloActivity) @@ -90,6 +87,36 @@ static xml::XmlNodeAction::ActionFuncWithDiag RequiredAndroidAttribute(const std }; } +static bool AutoGenerateIsFeatureSplit(xml::Element* el, SourcePathDiagnostics* diag) { + constexpr const char* kFeatureSplit = "featureSplit"; + constexpr const char* kIsFeatureSplit = "isFeatureSplit"; + + xml::Attribute* attr = el->FindAttribute({}, kFeatureSplit); + if (attr != nullptr) { + // Rewrite the featureSplit attribute to be "split". This is what the + // platform recognizes. + attr->name = "split"; + + // Now inject the android:isFeatureSplit="true" attribute. + xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsFeatureSplit); + if (attr != nullptr) { + if (!ResourceUtils::ParseBool(attr->value).value_or_default(false)) { + // The isFeatureSplit attribute is false, which conflicts with the use + // of "featureSplit". + diag->Error(DiagMessage(el->line_number) + << "attribute 'featureSplit' used in <manifest> but 'android:isFeatureSplit' " + "is not 'true'"); + return false; + } + + // The attribute is already there and set to true, nothing to do. + } else { + el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsFeatureSplit, "true"}); + } + } + return true; +} + static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) { xml::Attribute* attr = el->FindAttribute({}, "package"); if (!attr) { @@ -97,31 +124,34 @@ static bool VerifyManifest(xml::Element* el, SourcePathDiagnostics* diag) { << "<manifest> tag is missing 'package' attribute"); return false; } else if (ResourceUtils::IsReference(attr->value)) { - diag->Error( - DiagMessage(el->line_number) - << "attribute 'package' in <manifest> tag must not be a reference"); + diag->Error(DiagMessage(el->line_number) + << "attribute 'package' in <manifest> tag must not be a reference"); return false; } else if (!util::IsJavaPackageName(attr->value)) { diag->Error(DiagMessage(el->line_number) - << "attribute 'package' in <manifest> tag is not a valid Java " - "package name: '" + << "attribute 'package' in <manifest> tag is not a valid Java package name: '" << attr->value << "'"); return false; } + + attr = el->FindAttribute({}, "split"); + if (attr) { + if (!util::IsJavaPackageName(attr->value)) { + diag->Error(DiagMessage(el->line_number) << "attribute 'split' in <manifest> tag is not a " + "valid split name"); + return false; + } + } return true; } -/** - * The coreApp attribute in <manifest> is not a regular AAPT attribute, so type - * checking on it is manual. - */ +// The coreApp attribute in <manifest> is not a regular AAPT attribute, so type +// checking on it is manual. static bool FixCoreAppAttribute(xml::Element* el, SourcePathDiagnostics* diag) { if (xml::Attribute* attr = el->FindAttribute("", "coreApp")) { - std::unique_ptr<BinaryPrimitive> result = - ResourceUtils::TryParseBool(attr->value); + std::unique_ptr<BinaryPrimitive> result = ResourceUtils::TryParseBool(attr->value); if (!result) { - diag->Error(DiagMessage(el->line_number) - << "attribute coreApp must be a boolean"); + diag->Error(DiagMessage(el->line_number) << "attribute coreApp must be a boolean"); return false; } attr->compiled_value = std::move(result); @@ -172,8 +202,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, } if (options_.rename_instrumentation_target_package) { - if (!util::IsJavaPackageName( - options_.rename_instrumentation_target_package.value())) { + if (!util::IsJavaPackageName(options_.rename_instrumentation_target_package.value())) { diag->Error(DiagMessage() << "invalid instrumentation target package override '" << options_.rename_instrumentation_target_package.value() @@ -203,6 +232,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, // Manifest actions. xml::XmlNodeAction& manifest_action = (*executor)["manifest"]; + manifest_action.Action(AutoGenerateIsFeatureSplit); manifest_action.Action(VerifyManifest); manifest_action.Action(FixCoreAppAttribute); manifest_action.Action([&](xml::Element* el) -> bool { @@ -276,6 +306,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor, manifest_action["compatible-screens"]["screen"]; manifest_action["supports-gl-texture"]; manifest_action["meta-data"] = meta_data_action; + manifest_action["uses-split"].Action(RequiredNameIsJavaPackage); // Application actions. xml::XmlNodeAction& application_action = manifest_action["application"]; @@ -311,15 +342,13 @@ class FullyQualifiedClassNameVisitor : public xml::Visitor { public: using xml::Visitor::Visit; - explicit FullyQualifiedClassNameVisitor(const StringPiece& package) - : package_(package) {} + explicit FullyQualifiedClassNameVisitor(const StringPiece& package) : package_(package) {} void Visit(xml::Element* el) override { for (xml::Attribute& attr : el->attributes) { if (attr.namespace_uri == xml::kSchemaAndroid && class_attributes_.find(attr.name) != class_attributes_.end()) { - if (Maybe<std::string> new_value = - util::GetFullyQualifiedClassName(package_, attr.value)) { + if (Maybe<std::string> new_value = util::GetFullyQualifiedClassName(package_, attr.value)) { attr.value = std::move(new_value.value()); } } @@ -334,8 +363,7 @@ class FullyQualifiedClassNameVisitor : public xml::Visitor { std::unordered_set<StringPiece> class_attributes_ = {"name"}; }; -static bool RenameManifestPackage(const StringPiece& package_override, - xml::Element* manifest_el) { +static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) { xml::Attribute* attr = manifest_el->FindAttribute({}, "package"); // We've already verified that the manifest element is present, with a package @@ -358,8 +386,7 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) { return false; } - if ((options_.min_sdk_version_default || - options_.target_sdk_version_default) && + if ((options_.min_sdk_version_default || options_.target_sdk_version_default) && root->FindChild({}, "uses-sdk") == nullptr) { // Auto insert a <uses-sdk> element. This must be inserted before the // <application> tag. The device runtime PackageParser will make SDK version @@ -374,8 +401,7 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) { return false; } - if (!executor.Execute(xml::XmlActionExecutorPolicy::kWhitelist, - context->GetDiagnostics(), doc)) { + if (!executor.Execute(xml::XmlActionExecutorPolicy::kWhitelist, context->GetDiagnostics(), doc)) { return false; } @@ -383,8 +409,7 @@ bool ManifestFixer::Consume(IAaptContext* context, xml::XmlResource* doc) { // Rename manifest package outside of the XmlActionExecutor. // We need to extract the old package name and FullyQualify all class // names. - if (!RenameManifestPackage(options_.rename_manifest_package.value(), - root)) { + if (!RenameManifestPackage(options_.rename_manifest_package.value(), root)) { return false; } } diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py index eb8a1ccd0d9e..008344cc9480 100755 --- a/tools/fonts/fontchain_lint.py +++ b/tools/fonts/fontchain_lint.py @@ -521,36 +521,21 @@ def compute_expected_emoji(): # add zwj sequences not in the current emoji-zwj-sequences.txt adjusted_emoji_zwj_sequences = dict(_emoji_zwj_sequences) adjusted_emoji_zwj_sequences.update(_emoji_zwj_sequences) - # single parent families + # Wrestlers with modifiers additional_emoji_zwj = ( - (0x1F468, 0x200D, 0x1F466), - (0x1F468, 0x200D, 0x1F467), - (0x1F468, 0x200D, 0x1F466, 0x200D, 0x1F466), - (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F466), - (0x1F468, 0x200D, 0x1F467, 0x200D, 0x1F467), - (0x1F469, 0x200D, 0x1F466), - (0x1F469, 0x200D, 0x1F467), - (0x1F469, 0x200D, 0x1F466, 0x200D, 0x1F466), - (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466), - (0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F467), - ) - # sequences formed from man and woman and optional fitzpatrick modifier - modified_extensions = ( - 0x2696, - 0x2708, - 0x1F3A8, - 0x1F680, - 0x1F692, + (0x1F93C, 0x1F3FB, 0x200D, 0x2640), + (0x1F93C, 0x1F3FB, 0x200D, 0x2642), + (0x1F93C, 0x1F3FC, 0x200D, 0x2640), + (0x1F93C, 0x1F3FC, 0x200D, 0x2642), + (0x1F93C, 0x1F3FD, 0x200D, 0x2640), + (0x1F93C, 0x1F3FD, 0x200D, 0x2642), + (0x1F93C, 0x1F3FE, 0x200D, 0x2640), + (0x1F93C, 0x1F3FE, 0x200D, 0x2642), + (0x1F93C, 0x1F3FF, 0x200D, 0x2640), + (0x1F93C, 0x1F3FF, 0x200D, 0x2642), ) for seq in additional_emoji_zwj: adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence' - for ext in modified_extensions: - for base in (0x1F468, 0x1F469): - seq = (base, 0x200D, ext) - adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence' - for modifier in range(0x1F3FB, 0x1F400): - seq = (base, modifier, 0x200D, ext) - adjusted_emoji_zwj_sequences[seq] = 'Emoji_ZWJ_Sequence' for sequence in _emoji_sequences.keys(): sequence = tuple(ch for ch in sequence if ch != EMOJI_VS) diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java index 7de55aa5ffb2..333a4f7dc3ce 100644 --- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java @@ -28,6 +28,7 @@ import android.os.Parcel; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -329,6 +330,50 @@ public final class PasspointConfiguration implements Parcelable { mUsageLimitStartTimeInMs, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("UpdateIdentifier: ").append(mUpdateIdentifier).append("\n"); + builder.append("CredentialPriority: ").append(mCredentialPriority).append("\n"); + builder.append("SubscriptionCreationTime: ").append( + mSubscriptionCreationTimeInMs != Long.MIN_VALUE + ? new Date(mSubscriptionCreationTimeInMs) : "Not specified").append("\n"); + builder.append("SubscriptionExpirationTime: ").append( + mSubscriptionExpirationTimeInMs != Long.MIN_VALUE + ? new Date(mSubscriptionExpirationTimeInMs) : "Not specified").append("\n"); + builder.append("UsageLimitStartTime: ").append(mUsageLimitStartTimeInMs != Long.MIN_VALUE + ? new Date(mUsageLimitStartTimeInMs) : "Not specified").append("\n"); + builder.append("UsageTimePeriod: ").append(mUsageLimitUsageTimePeriodInMinutes) + .append("\n"); + builder.append("UsageLimitDataLimit: ").append(mUsageLimitDataLimit).append("\n"); + builder.append("UsageLimitTimeLimit: ").append(mUsageLimitTimeLimitInMinutes).append("\n"); + if (mHomeSp != null) { + builder.append("HomeSP Begin ---\n"); + builder.append(mHomeSp); + builder.append("HomeSP End ---\n"); + } + if (mCredential != null) { + builder.append("Credential Begin ---\n"); + builder.append(mCredential); + builder.append("Credential End ---\n"); + } + if (mPolicy != null) { + builder.append("Policy Begin ---\n"); + builder.append(mPolicy); + builder.append("Policy End ---\n"); + } + if (mSubscriptionUpdate != null) { + builder.append("SubscriptionUpdate Begin ---\n"); + builder.append(mSubscriptionUpdate); + builder.append("SubscriptionUpdate End ---\n"); + } + if (mTrustRootCertList != null) { + builder.append("TrustRootCertServers: ").append(mTrustRootCertList.keySet()) + .append("\n"); + } + return builder.toString(); + } + /** * Validate the configuration data. * diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java index d8da84f28df6..67fa1bbccd1e 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java @@ -30,6 +30,7 @@ import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.Arrays; +import java.util.Date; import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -282,6 +283,18 @@ public final class Credential implements Parcelable { mAbleToShare, mEapType, mNonEapInnerMethod); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Username: ").append(mUsername).append("\n"); + builder.append("MachineManaged: ").append(mMachineManaged).append("\n"); + builder.append("SoftTokenApp: ").append(mSoftTokenApp).append("\n"); + builder.append("AbleToShare: ").append(mAbleToShare).append("\n"); + builder.append("EAPType: ").append(mEapType).append("\n"); + builder.append("AuthMethod: ").append(mNonEapInnerMethod).append("\n"); + return builder.toString(); + } + /** * Validate the configuration data. * @@ -440,6 +453,11 @@ public final class Credential implements Parcelable { return Objects.hash(mCertType, mCertSha256Fingerprint); } + @Override + public String toString() { + return "CertificateType: " + mCertType + "\n"; + } + /** * Validate the configuration data. * @@ -562,6 +580,14 @@ public final class Credential implements Parcelable { } @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("IMSI: ").append(mImsi).append("\n"); + builder.append("EAPType: ").append(mEapType).append("\n"); + return builder.toString(); + } + + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(mImsi); dest.writeInt(mEapType); @@ -767,6 +793,33 @@ public final class Credential implements Parcelable { mCaCertificate, mClientCertificateChain, mClientPrivateKey); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Realm: ").append(mRealm).append("\n"); + builder.append("CreationTime: ").append(mCreationTimeInMs != Long.MIN_VALUE + ? new Date(mCreationTimeInMs) : "Not specified").append("\n"); + builder.append("ExpirationTime: ").append(mExpirationTimeInMs != Long.MIN_VALUE + ? new Date(mExpirationTimeInMs) : "Not specified").append("\n"); + builder.append("CheckAAAServerStatus: ").append(mCheckAaaServerCertStatus).append("\n"); + if (mUserCredential != null) { + builder.append("UserCredential Begin ---\n"); + builder.append(mUserCredential); + builder.append("UserCredential End ---\n"); + } + if (mCertCredential != null) { + builder.append("CertificateCredential Begin ---\n"); + builder.append(mCertCredential); + builder.append("CertificateCredential End ---\n"); + } + if (mSimCredential != null) { + builder.append("SIMCredential Begin ---\n"); + builder.append(mSimCredential); + builder.append("SIMCredential End ---\n"); + } + return builder.toString(); + } + /** * Validate the configuration data. * diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java index 68bdf37b1815..9192ab015e20 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java @@ -241,6 +241,20 @@ public final class HomeSp implements Parcelable { mMatchAnyOis, mOtherHomePartners, mRoamingConsortiumOis); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("FQDN: ").append(mFqdn).append("\n"); + builder.append("FriendlyName: ").append(mFriendlyName).append("\n"); + builder.append("IconURL: ").append(mIconUrl).append("\n"); + builder.append("HomeNetworkIDs: ").append(mHomeNetworkIds).append("\n"); + builder.append("MatchAllOIs: ").append(mMatchAllOis).append("\n"); + builder.append("MatchAnyOIs: ").append(mMatchAnyOis).append("\n"); + builder.append("OtherHomePartners: ").append(mOtherHomePartners).append("\n"); + builder.append("RoamingConsortiumOIs: ").append(mRoamingConsortiumOis).append("\n"); + return builder.toString(); + } + /** * Validate HomeSp data. * diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java index da36a116fbbe..1df70f8d45d0 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java @@ -249,6 +249,16 @@ public final class Policy implements Parcelable { return Objects.hash(mFqdn, mFqdnExactMatch, mPriority, mCountries); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("FQDN: ").append(mFqdn).append("\n"); + builder.append("ExactMatch: ").append("mFqdnExactMatch").append("\n"); + builder.append("Priority: ").append(mPriority).append("\n"); + builder.append("Countries: ").append(mCountries).append("\n"); + return builder.toString(); + } + /** * Validate RoamingParnter data. * @@ -390,6 +400,29 @@ public final class Policy implements Parcelable { mPolicyUpdate); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("MinHomeDownlinkBandwidth: ").append(mMinHomeDownlinkBandwidth) + .append("\n"); + builder.append("MinHomeUplinkBandwidth: ").append(mMinHomeUplinkBandwidth).append("\n"); + builder.append("MinRoamingDownlinkBandwidth: ").append(mMinRoamingDownlinkBandwidth) + .append("\n"); + builder.append("MinRoamingUplinkBandwidth: ").append(mMinRoamingUplinkBandwidth) + .append("\n"); + builder.append("ExcludedSSIDList: ").append(mExcludedSsidList).append("\n"); + builder.append("RequiredProtoPortMap: ").append(mRequiredProtoPortMap).append("\n"); + builder.append("MaximumBSSLoadValue: ").append(mMaximumBssLoadValue).append("\n"); + builder.append("PreferredRoamingPartnerList: ").append(mPreferredRoamingPartnerList) + .append("\n"); + if (mPolicyUpdate != null) { + builder.append("PolicyUpdate Begin ---\n"); + builder.append(mPolicyUpdate); + builder.append("PolicyUpdate End ---\n"); + } + return builder.toString(); + } + /** * Validate Policy data. * diff --git a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java index ae051b0a6e3f..a7adfeb9ec0f 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java @@ -247,6 +247,18 @@ public final class UpdateParameter implements Parcelable { mTrustRootCertSha256Fingerprint); } + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("UpdateInterval: ").append(mUpdateIntervalInMinutes).append("\n"); + builder.append("UpdateMethod: ").append(mUpdateMethod).append("\n"); + builder.append("Restriction: ").append(mRestriction).append("\n"); + builder.append("ServerURI: ").append(mServerUri).append("\n"); + builder.append("Username: ").append(mUsername).append("\n"); + builder.append("TrustRootCertURL: ").append(mTrustRootCertUrl).append("\n"); + return builder.toString(); + } + /** * Validate UpdateParameter data. * |