diff options
22 files changed, 348 insertions, 228 deletions
diff --git a/config/Android.bp b/config/Android.bp new file mode 100644 index 000000000000..0fb56cb3410a --- /dev/null +++ b/config/Android.bp @@ -0,0 +1,18 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +filegroup { + name: "preloaded-classes-blacklist", + srcs: ["preloaded-classes-blacklist"], +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2906710b0655..0e10de8c4e3f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -510,7 +510,7 @@ public class ConnectivityManager { * The absence of a connection type. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_NONE = -1; /** @@ -627,7 +627,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_MOBILE_FOTA = 10; /** @@ -645,7 +645,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_MOBILE_CBS = 12; /** @@ -655,7 +655,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_WIFI_P2P = 13; /** @@ -674,7 +674,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static final int TYPE_MOBILE_EMERGENCY = 15; /** @@ -775,7 +775,7 @@ public class ConnectivityManager { */ public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private final IConnectivityManager mService; /** * A kludge to facilitate static access where a Context pointer isn't available, like in the @@ -867,7 +867,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public static boolean isNetworkTypeMobile(int networkType) { switch (networkType) { case TYPE_MOBILE: @@ -1304,7 +1304,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public LinkProperties getLinkProperties(int networkType) { try { return mService.getLinkPropertiesForType(networkType); @@ -3042,7 +3042,7 @@ public class ConnectivityManager { */ @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) public boolean isNetworkSupported(int networkType) { try { return mService.isNetworkSupported(networkType); diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index b6c4fe2de4f4..68826cbeb845 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -197,7 +197,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkSend((network != null - ? network.netId : NETID_UNSET), query, query.length, flags); + ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -238,7 +238,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags); + ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -346,7 +346,8 @@ public final class DnsResolver { if (queryIpv6) { try { v6fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags); + ? network.getNetIdForResolv() : NETID_UNSET), + domain, CLASS_IN, TYPE_AAAA, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; @@ -365,7 +366,8 @@ public final class DnsResolver { if (queryIpv4) { try { v4fd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags); + ? network.getNetIdForResolv() : NETID_UNSET), + domain, CLASS_IN, TYPE_A, flags); } catch (ErrnoException e) { if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid. executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); @@ -423,7 +425,7 @@ public final class DnsResolver { final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null - ? network.netId : NETID_UNSET), domain, CLASS_IN, nsType, flags); + ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags); } catch (ErrnoException e) { executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e))); return; diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 49c6f74b1a34..5a22747cb499 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -25,6 +25,7 @@ import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; import android.content.Context; import android.media.MediaPlayer; +import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.util.DataUnit; @@ -150,7 +151,7 @@ public class TrafficStats { private static INetworkStatsService sStatsService; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private synchronized static INetworkStatsService getStatsService() { if (sStatsService == null) { sStatsService = INetworkStatsService.Stub.asInterface( @@ -960,7 +961,7 @@ public class TrafficStats { * Interfaces are never removed from this list, so counters should always be * monotonic. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private static String[] getMobileIfaces() { try { return getStatsService().getMobileIfaces(); diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index 0feed68163e2..e366fe05723e 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -175,6 +175,7 @@ public final class BugreportManager { // Need to delete the file if it was created but failed while trying to get fd deleteFile(tmpScreenshotFile); Log.e(TAG, "Not able to create/open temporary screenshot file ", e); + callback.onError(BugreportCallback.BUGREPORT_ERROR_RUNTIME); } finally { // We can close the file descriptors here because binder would have duped them. IoUtils.closeQuietly(bugreportFd); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 5a1089bbc2b4..d17646216a64 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1365,6 +1365,7 @@ public final class ViewRootImpl implements ViewParent, renderer.setStopped(mStopped); } if (!mStopped) { + mNewSurfaceNeeded = true; scheduleTraversals(); } else { if (renderer != null) { diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp index 42e3942eb350..9c60e6bd8565 100644 --- a/core/jni/android_os_HwBinder.cpp +++ b/core/jni/android_os_HwBinder.cpp @@ -224,6 +224,21 @@ status_t JHwBinder::onTransact( return err; } +bool validateCanUseHwBinder(const sp<hardware::IBinder>& binder) { + if (binder != nullptr && binder->localBinder() != nullptr) { + // untested/unsupported/inefficient + // see b/129150021, doesn't work with scatter-gather + // + // explicitly disabling until it is supported + // (note, even if this is fixed to work with scatter gather, we would also need + // to convert this to the Java object rather than re-wrapping with a proxy) + LOG(ERROR) << "Local Java Binder not supported."; + return false; + } + + return true; +} + } // namespace android //////////////////////////////////////////////////////////////////////////////// @@ -324,9 +339,9 @@ static jobject JHwBinder_native_getService( sp<IBase> ret = getRawServiceInternal(ifaceName, serviceName, retry /* retry */, false /* getStub */); sp<hardware::IBinder> service = hardware::toBinder<hidl::base::V1_0::IBase>(ret); - if (service == NULL) { + if (service == nullptr || !validateCanUseHwBinder(service)) { signalExceptionForError(env, NAME_NOT_FOUND); - return NULL; + return nullptr; } LOG(INFO) << "HwBinder: Starting thread pool for getting: " << ifaceName << "/" << serviceName; diff --git a/core/jni/android_os_HwBinder.h b/core/jni/android_os_HwBinder.h index 5352f1e607c2..99195b1abc9c 100644 --- a/core/jni/android_os_HwBinder.h +++ b/core/jni/android_os_HwBinder.h @@ -54,6 +54,8 @@ private: int register_android_os_HwBinder(JNIEnv *env); +bool validateCanUseHwBinder(const sp<hardware::IBinder>& binder); + } // namespace android #endif // _ANDROID_OS_HW_BINDER_H diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp index 7221ca11cc00..f437a78e35f8 100644 --- a/core/jni/android_os_HwParcel.cpp +++ b/core/jni/android_os_HwParcel.cpp @@ -883,8 +883,12 @@ static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) { sp<hardware::IBinder> binder = parcel->readStrongBinder(); - if (binder == NULL) { - return NULL; + if (binder == nullptr) { + return nullptr; + } + + if (!validateCanUseHwBinder(binder)) { + return nullptr; } return JHwRemoteBinder::NewObject(env, binder); diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 35f7ea3ae0fe..77a18e2b3ddc 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -191,6 +191,7 @@ public class KeepaliveTracker { case NOT_STARTED : return "NOT_STARTED"; case STARTING : return "STARTING"; case STARTED : return "STARTED"; + case STOPPING : return "STOPPING"; } throw new IllegalArgumentException("Unknown state"); } @@ -314,18 +315,27 @@ public class KeepaliveTracker { Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network); } } - if (NOT_STARTED != mStartedState) { - mStartedState = STOPPING; - Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name()); - if (mType == TYPE_NATT) { - mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); - } else if (mType == TYPE_TCP) { - mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); - mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot); - mTcpController.stopSocketMonitor(mSlot); - } else { - Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); - } + Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name() + ": " + reason); + switch (mStartedState) { + case NOT_STARTED: + // Remove the reference of the keepalive that meet error before starting, + // e.g. invalid parameter. + cleanupStoppedKeepalive(mNai, mSlot); + break; + case STOPPING: + // Keepalive is already in stopping state, ignore. + return; + default: + mStartedState = STOPPING; + if (mType == TYPE_NATT) { + mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); + } else if (mType == TYPE_TCP) { + mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot); + mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot); + mTcpController.stopSocketMonitor(mSlot); + } else { + Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType); + } } // Close the duplicated fd that maintains the lifecycle of socket whenever @@ -405,9 +415,9 @@ public class KeepaliveTracker { for (KeepaliveInfo ki : networkKeepalives.values()) { ki.stop(reason); } - networkKeepalives.clear(); - mKeepalives.remove(nai); } + // Clean up keepalives will be done as a result of calling ki.stop() after the slots are + // freed. } public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) { @@ -423,8 +433,24 @@ public class KeepaliveTracker { return; } ki.stop(reason); + // Clean up keepalives will be done as a result of calling ki.stop() after the slots are + // freed. + } + + private void cleanupStoppedKeepalive(NetworkAgentInfo nai, int slot) { + String networkName = (nai == null) ? "(null)" : nai.name(); + HashMap<Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai); + if (networkKeepalives == null) { + Log.e(TAG, "Attempt to remove keepalive on nonexistent network " + networkName); + return; + } + KeepaliveInfo ki = networkKeepalives.get(slot); + if (ki == null) { + Log.e(TAG, "Attempt to remove nonexistent keepalive " + slot + " on " + networkName); + return; + } networkKeepalives.remove(slot); - Log.d(TAG, "Stopped keepalive " + slot + " on " + networkName + ", " + Log.d(TAG, "Remove keepalive " + slot + " on " + networkName + ", " + networkKeepalives.size() + " remains."); if (networkKeepalives.isEmpty()) { mKeepalives.remove(nai); @@ -495,10 +521,11 @@ public class KeepaliveTracker { handleStopKeepalive(nai, slot, reason); } } else if (KeepaliveInfo.STOPPING == ki.mStartedState) { - // The message indicated result of stopping : don't call handleStopKeepalive. + // The message indicated result of stopping : clean up keepalive slots. Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.name() + " stopped: " + reason); ki.mStartedState = KeepaliveInfo.NOT_STARTED; + cleanupStoppedKeepalive(nai, slot); } else { Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason + " for keepalive in wrong state: " + ki.toString()); diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index b140c1b25320..33c84d161a90 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -237,13 +237,17 @@ public class Tethering extends BaseNetworkObserver { mLog.log("OBSERVED UiEnitlementFailed"); stopTethering(downstream); }); + mEntitlementMgr.setTetheringConfigurationFetcher(() -> { + maybeDefaultDataSubChanged(); + return mConfig; + }); mCarrierConfigChange = new VersionedBroadcastListener( "CarrierConfigChangeListener", mContext, mHandler, filter, (Intent ignored) -> { mLog.log("OBSERVED carrier config change"); updateConfiguration(); - mEntitlementMgr.reevaluateSimCardProvisioning(); + mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); }); filter = new IntentFilter(); @@ -252,12 +256,12 @@ public class Tethering extends BaseNetworkObserver { "DefaultSubscriptionChangeListener", mContext, mHandler, filter, (Intent ignored) -> { mLog.log("OBSERVED default data subscription change"); - updateConfiguration(); + maybeDefaultDataSubChanged(); // To avoid launch unexpected provisioning checks, ignore re-provisioning when // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be // triggered again when CarrierConfig is loaded. - if (mEntitlementMgr.getCarrierConfig() != null) { - mEntitlementMgr.reevaluateSimCardProvisioning(); + if (mEntitlementMgr.getCarrierConfig(mConfig) != null) { + mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); } else { mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded"); } @@ -301,17 +305,26 @@ public class Tethering extends BaseNetworkObserver { // NOTE: This is always invoked on the mLooper thread. private void updateConfiguration() { final int subId = mDeps.getDefaultDataSubscriptionId(); + updateConfiguration(subId); + } + + private void updateConfiguration(final int subId) { mConfig = new TetheringConfiguration(mContext, mLog, subId); mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired); - mEntitlementMgr.updateConfiguration(mConfig); } - private void maybeUpdateConfiguration() { + private void maybeDunSettingChanged() { final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext); if (isDunRequired == mConfig.isDunRequired) return; updateConfiguration(); } + private void maybeDefaultDataSubChanged() { + final int subId = mDeps.getDefaultDataSubscriptionId(); + if (subId == mConfig.subId) return; + updateConfiguration(subId); + } + @Override public void interfaceStatusChanged(String iface, boolean up) { // Never called directly: only called from interfaceLinkStateChanged. @@ -1183,7 +1196,7 @@ public class Tethering extends BaseNetworkObserver { protected void chooseUpstreamType(boolean tryCell) { // We rebuild configuration on ACTION_CONFIGURATION_CHANGED, but we // do not currently know how to watch for changes in DUN settings. - maybeUpdateConfiguration(); + maybeDunSettingChanged(); final TetheringConfiguration config = mConfig; final NetworkState ns = (config.chooseUpstreamAutomatically) diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java index b0bbd72794d9..836f1e64aa9c 100644 --- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java @@ -29,7 +29,6 @@ import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; import static com.android.internal.R.string.config_wifi_tether_enable; -import android.annotation.Nullable; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -76,6 +75,7 @@ public class EntitlementManager { protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning"; private static final String ACTION_PROVISIONING_ALARM = "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"; + private static final String EXTRA_SUBID = "subId"; // {@link ComponentName} of the Service used to run tether provisioning. private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString( @@ -99,7 +99,6 @@ public class EntitlementManager { private final SharedLog mLog; private final SparseIntArray mEntitlementCacheValue; private final EntitlementHandler mHandler; - private @Nullable TetheringConfiguration mConfig; private final StateMachine mTetherMasterSM; // Key: ConnectivityManager.TETHERING_*(downstream). // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result). @@ -109,6 +108,7 @@ public class EntitlementManager { private boolean mUsingCellularAsUpstream = false; private boolean mNeedReRunProvisioningUi = false; private OnUiEntitlementFailedListener mListener; + private TetheringConfigurationFetcher mFetcher; public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log, int permissionChangeMessageCode, MockableSystemProperties systemProperties) { @@ -143,12 +143,18 @@ public class EntitlementManager { void onUiEntitlementFailed(int downstream); } - /** - * Pass a new TetheringConfiguration instance each time when - * Tethering#updateConfiguration() is called. - */ - public void updateConfiguration(TetheringConfiguration conf) { - mConfig = conf; + public void setTetheringConfigurationFetcher(final TetheringConfigurationFetcher fetcher) { + mFetcher = fetcher; + } + + /** Interface to fetch TetheringConfiguration. */ + public interface TetheringConfigurationFetcher { + /** + * Fetch current tethering configuration. This will be called to ensure whether entitlement + * check is needed. + * @return TetheringConfiguration instance. + */ + TetheringConfiguration fetchTetheringConfiguration(); } /** @@ -176,7 +182,8 @@ public class EntitlementManager { if (!mCurrentTethers.contains(type)) mCurrentTethers.add(type); - if (isTetherProvisioningRequired()) { + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + if (isTetherProvisioningRequired(config)) { // If provisioning is required and the result is not available yet, // cellular upstream should not be allowed. if (mCellularPermitted.size() == 0) { @@ -186,9 +193,9 @@ public class EntitlementManager { // till upstream change to cellular. if (mUsingCellularAsUpstream) { if (showProvisioningUi) { - runUiTetherProvisioning(type); + runUiTetherProvisioning(type, config.subId); } else { - runSilentTetherProvisioning(type); + runSilentTetherProvisioning(type, config.subId); } mNeedReRunProvisioningUi = false; } else { @@ -237,7 +244,8 @@ public class EntitlementManager { mUsingCellularAsUpstream = isCellular; if (mUsingCellularAsUpstream) { - handleMaybeRunProvisioning(); + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + handleMaybeRunProvisioning(config); } } @@ -246,8 +254,8 @@ public class EntitlementManager { mHandler.sendMessage(mHandler.obtainMessage(EVENT_MAYBE_RUN_PROVISIONING)); } - private void handleMaybeRunProvisioning() { - if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired()) { + private void handleMaybeRunProvisioning(final TetheringConfiguration config) { + if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired(config)) { return; } @@ -259,9 +267,9 @@ public class EntitlementManager { if (mCellularPermitted.indexOfKey(downstream) < 0) { if (mNeedReRunProvisioningUi) { mNeedReRunProvisioningUi = false; - runUiTetherProvisioning(downstream); + runUiTetherProvisioning(downstream, config.subId); } else { - runSilentTetherProvisioning(downstream); + runSilentTetherProvisioning(downstream, config.subId); } } } @@ -270,29 +278,31 @@ public class EntitlementManager { /** * Check if the device requires a provisioning check in order to enable tethering. * + * @param config an object that encapsulates the various tethering configuration elements. * @return a boolean - {@code true} indicating tether provisioning is required by the carrier. */ @VisibleForTesting - public boolean isTetherProvisioningRequired() { + protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) { if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false) - || mConfig.provisioningApp.length == 0) { + || config.provisioningApp.length == 0) { return false; } - if (carrierConfigAffirmsEntitlementCheckNotRequired()) { + if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) { return false; } - return (mConfig.provisioningApp.length == 2); + return (config.provisioningApp.length == 2); } /** * Re-check tethering provisioning for all enabled tether types. * Reference ConnectivityManager.TETHERING_{@code *} for each tether type. * + * @param config an object that encapsulates the various tethering configuration elements. * Note: this method is only called from TetherMaster on the handler thread. * If there are new callers from different threads, the logic should move to * masterHandler to avoid race conditions. */ - public void reevaluateSimCardProvisioning() { + public void reevaluateSimCardProvisioning(final TetheringConfiguration config) { if (DBG) mLog.i("reevaluateSimCardProvisioning"); if (!mHandler.getLooper().isCurrentThread()) { @@ -303,24 +313,27 @@ public class EntitlementManager { mCellularPermitted.clear(); // TODO: refine provisioning check to isTetherProvisioningRequired() ?? - if (!mConfig.hasMobileHotspotProvisionApp() - || carrierConfigAffirmsEntitlementCheckNotRequired()) { - evaluateCellularPermission(); + if (!config.hasMobileHotspotProvisionApp() + || carrierConfigAffirmsEntitlementCheckNotRequired(config)) { + evaluateCellularPermission(config); return; } if (mUsingCellularAsUpstream) { - handleMaybeRunProvisioning(); + handleMaybeRunProvisioning(config); } } - /** Get carrier configuration bundle. */ - public PersistableBundle getCarrierConfig() { + /** + * Get carrier configuration bundle. + * @param config an object that encapsulates the various tethering configuration elements. + * */ + public PersistableBundle getCarrierConfig(final TetheringConfiguration config) { final CarrierConfigManager configManager = (CarrierConfigManager) mContext .getSystemService(Context.CARRIER_CONFIG_SERVICE); if (configManager == null) return null; - final PersistableBundle carrierConfig = configManager.getConfig(); + final PersistableBundle carrierConfig = configManager.getConfigForSubId(config.subId); if (CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) { return carrierConfig; @@ -334,9 +347,10 @@ public class EntitlementManager { // // TODO: find a better way to express this, or alter the checking process // entirely so that this is more intuitive. - private boolean carrierConfigAffirmsEntitlementCheckNotRequired() { + private boolean carrierConfigAffirmsEntitlementCheckNotRequired( + final TetheringConfiguration config) { // Check carrier config for entitlement checks - final PersistableBundle carrierConfig = getCarrierConfig(); + final PersistableBundle carrierConfig = getCarrierConfig(config); if (carrierConfig == null) return false; // A CarrierConfigManager was found and it has a config. @@ -348,17 +362,19 @@ public class EntitlementManager { /** * Run no UI tethering provisioning check. * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param subId default data subscription ID. */ - protected void runSilentTetherProvisioning(int type) { + @VisibleForTesting + protected void runSilentTetherProvisioning(int type, int subId) { if (DBG) mLog.i("runSilentTetherProvisioning: " + type); // For silent provisioning, settings would stop tethering when entitlement fail. - ResultReceiver receiver = buildProxyReceiver(type, - false/* notifyFail */, null); + ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null); Intent intent = new Intent(); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); intent.putExtra(EXTRA_RUN_PROVISION, true); intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); + intent.putExtra(EXTRA_SUBID, subId); intent.setComponent(TETHER_SERVICE); final long ident = Binder.clearCallingIdentity(); try { @@ -368,24 +384,25 @@ public class EntitlementManager { } } + private void runUiTetherProvisioning(int type, int subId) { + ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null); + runUiTetherProvisioning(type, subId, receiver); + } + /** * Run the UI-enabled tethering provisioning check. * @param type tethering type from ConnectivityManager.TETHERING_{@code *} + * @param subId default data subscription ID. + * @param receiver to receive entitlement check result. */ @VisibleForTesting - protected void runUiTetherProvisioning(int type) { - ResultReceiver receiver = buildProxyReceiver(type, - true/* notifyFail */, null); - runUiTetherProvisioning(type, receiver); - } - - @VisibleForTesting - protected void runUiTetherProvisioning(int type, ResultReceiver receiver) { + protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) { if (DBG) mLog.i("runUiTetherProvisioning: " + type); Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING); intent.putExtra(EXTRA_ADD_TETHER_TYPE, type); intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); + intent.putExtra(EXTRA_SUBID, subId); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); final long ident = Binder.clearCallingIdentity(); try { @@ -396,9 +413,9 @@ public class EntitlementManager { } // Not needed to check if this don't run on the handler thread because it's private. - private void scheduleProvisioningRechecks() { + private void scheduleProvisioningRechecks(final TetheringConfiguration config) { if (mProvisioningRecheckAlarm == null) { - final int period = mConfig.provisioningCheckPeriod; + final int period = config.provisioningCheckPeriod; if (period <= 0) return; Intent intent = new Intent(ACTION_PROVISIONING_ALARM); @@ -421,9 +438,9 @@ public class EntitlementManager { } } - private void evaluateCellularPermission() { + private void evaluateCellularPermission(final TetheringConfiguration config) { final boolean oldPermitted = mCellularUpstreamPermitted; - mCellularUpstreamPermitted = (!isTetherProvisioningRequired() + mCellularUpstreamPermitted = (!isTetherProvisioningRequired(config) || mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1); if (DBG) { @@ -438,7 +455,7 @@ public class EntitlementManager { // Only schedule periodic re-check when tether is provisioned // and the result is ok. if (mCellularUpstreamPermitted && mCellularPermitted.size() > 0) { - scheduleProvisioningRechecks(); + scheduleProvisioningRechecks(config); } else { cancelTetherProvisioningRechecks(); } @@ -457,7 +474,8 @@ public class EntitlementManager { if (!mCurrentTethers.contains(type)) return; mCellularPermitted.put(type, resultCode); - evaluateCellularPermission(); + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + evaluateCellularPermission(config); } /** @@ -467,7 +485,8 @@ public class EntitlementManager { protected void removeDownstreamMapping(int type) { mLog.i("removeDownstreamMapping: " + type); mCellularPermitted.delete(type); - evaluateCellularPermission(); + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + evaluateCellularPermission(config); } private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @@ -475,7 +494,8 @@ public class EntitlementManager { public void onReceive(Context context, Intent intent) { if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) { mLog.log("Received provisioning alarm"); - reevaluateSimCardProvisioning(); + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + reevaluateSimCardProvisioning(config); } } }; @@ -498,7 +518,8 @@ public class EntitlementManager { handleNotifyUpstream(toBool(msg.arg1)); break; case EVENT_MAYBE_RUN_PROVISIONING: - handleMaybeRunProvisioning(); + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + handleMaybeRunProvisioning(config); break; case EVENT_GET_ENTITLEMENT_VALUE: handleGetLatestTetheringEntitlementValue(msg.arg1, (ResultReceiver) msg.obj, @@ -636,7 +657,8 @@ public class EntitlementManager { private void handleGetLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver, boolean showEntitlementUi) { - if (!isTetherProvisioningRequired()) { + final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration(); + if (!isTetherProvisioningRequired(config)) { receiver.send(TETHER_ERROR_NO_ERROR, null); return; } @@ -647,7 +669,7 @@ public class EntitlementManager { receiver.send(cacheValue, null); } else { ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver); - runUiTetherProvisioning(downstream, proxy); + runUiTetherProvisioning(downstream, config.subId, proxy); } } } diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 2ce3cafa3e1d..770f780372ad 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -39,6 +39,7 @@ import android.util.DisplayMetrics; import android.util.Log; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -123,6 +124,16 @@ public class SubscriptionInfo implements Parcelable { private String mMnc; /** + * EHPLMNs associated with the subscription + */ + private String[] mEhplmns; + + /** + * HPLMNs associated with the subscription + */ + private String[] mHplmns; + + /** * ISO Country code for the subscription's provider */ private String mCountryIso; @@ -316,6 +327,14 @@ public class SubscriptionInfo implements Parcelable { } /** + * @hide + */ + public void setAssociatedPlmns(String[] ehplmns, String[] hplmns) { + mEhplmns = ehplmns; + mHplmns = hplmns; + } + + /** * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a * user interface. * @@ -467,6 +486,20 @@ public class SubscriptionInfo implements Parcelable { } /** + * @hide + */ + public List<String> getEhplmns() { + return mEhplmns == null ? Collections.emptyList() : Arrays.asList(mEhplmns); + } + + /** + * @hide + */ + public List<String> getHplmns() { + return mHplmns == null ? Collections.emptyList() : Arrays.asList(mHplmns); + } + + /** * @return the profile class of this subscription. * @hide */ @@ -599,7 +632,7 @@ public class SubscriptionInfo implements Parcelable { String mcc = source.readString(); String mnc = source.readString(); String countryIso = source.readString(); - Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source); + Bitmap iconBitmap = source.readParcelable(Bitmap.class.getClassLoader()); boolean isEmbedded = source.readBoolean(); UiccAccessRule[] accessRules = source.createTypedArray(UiccAccessRule.CREATOR); String cardString = source.readString(); @@ -610,11 +643,15 @@ public class SubscriptionInfo implements Parcelable { int carrierid = source.readInt(); int profileClass = source.readInt(); int subType = source.readInt(); - - return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName, - nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso, - isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID, - isGroupDisabled, carrierid, profileClass, subType); + String[] ehplmns = source.readStringArray(); + String[] hplmns = source.readStringArray(); + + SubscriptionInfo info = new SubscriptionInfo(id, iccId, simSlotIndex, displayName, + carrierName, nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, + countryIso, isEmbedded, accessRules, cardString, cardId, isOpportunistic, + groupUUID, isGroupDisabled, carrierid, profileClass, subType); + info.setAssociatedPlmns(ehplmns, hplmns); + return info; } @Override @@ -637,7 +674,7 @@ public class SubscriptionInfo implements Parcelable { dest.writeString(mMcc); dest.writeString(mMnc); dest.writeString(mCountryIso); - mIconBitmap.writeToParcel(dest, flags); + dest.writeParcelable(mIconBitmap, flags); dest.writeBoolean(mIsEmbedded); dest.writeTypedArray(mAccessRules, flags); dest.writeString(mCardString); @@ -648,6 +685,8 @@ public class SubscriptionInfo implements Parcelable { dest.writeInt(mCarrierId); dest.writeInt(mProfileClass); dest.writeInt(mSubscriptionType); + dest.writeStringArray(mEhplmns); + dest.writeStringArray(mHplmns); } @Override @@ -685,6 +724,8 @@ public class SubscriptionInfo implements Parcelable { + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID + " mIsGroupDisabled=" + mIsGroupDisabled + " profileClass=" + mProfileClass + + " ehplmns = " + Arrays.toString(mEhplmns) + + " hplmns = " + Arrays.toString(mHplmns) + " subscriptionType=" + mSubscriptionType + "}"; } @@ -728,6 +769,8 @@ public class SubscriptionInfo implements Parcelable { && TextUtils.equals(mDisplayName, toCompare.mDisplayName) && TextUtils.equals(mCarrierName, toCompare.mCarrierName) && Arrays.equals(mAccessRules, toCompare.mAccessRules) - && mProfileClass == toCompare.mProfileClass; + && mProfileClass == toCompare.mProfileClass + && Arrays.equals(mEhplmns, toCompare.mEhplmns) + && Arrays.equals(mHplmns, toCompare.mHplmns); } } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index b0fa9d526b16..586c815ae7b5 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -458,6 +458,18 @@ public class SubscriptionManager { public static final String CARRIER_ID = "carrier_id"; /** + * @hide A comma-separated list of EHPLMNs associated with the subscription + * <P>Type: TEXT (String)</P> + */ + public static final String EHPLMNS = "ehplmns"; + + /** + * @hide A comma-separated list of HPLMNs associated with the subscription + * <P>Type: TEXT (String)</P> + */ + public static final String HPLMNS = "hplmns"; + + /** * TelephonyProvider column name for the MCC associated with a SIM, stored as a string. * <P>Type: TEXT (String)</P> * @hide @@ -2733,6 +2745,8 @@ public class SubscriptionManager { * * @throws SecurityException if the caller doesn't meet the requirements * outlined above. + * @throws IllegalArgumentException if any of the subscriptions in the list doesn't exist. + * @throws IllegalStateException if Telephony service is in bad state. * * @param subIdList list of subId that will be in the same group * @return groupUUID a UUID assigned to the subscription group. @@ -2781,6 +2795,7 @@ public class SubscriptionManager { * outlined above. * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist, * or the groupUuid doesn't exist. + * @throws IllegalStateException if Telephony service is in bad state. * * @param subIdList list of subId that need adding into the group * @param groupUuid the groupUuid the subscriptions are being added to. @@ -2833,6 +2848,7 @@ public class SubscriptionManager { * outlined above. * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong * the specified group. + * @throws IllegalStateException if Telephony service is in bad state. * * @param subIdList list of subId that need removing from their groups. * diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 12acf9d09830..e1425b975525 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -10321,10 +10321,10 @@ public class TelephonyManager { * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). * - * @return Map including the key as the active subscription ID (Note: if there is no active + * @return Map including the keys as the active subscription IDs (Note: if there is no active * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value - * as the list of {@link EmergencyNumber}; null if this information is not available; or throw - * a SecurityException if the caller does not have the permission. + * as the list of {@link EmergencyNumber}; empty Map if this information is not available; + * or throw a SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull @@ -10374,10 +10374,10 @@ public class TelephonyManager { * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_MIEC} </li> * <li>{@link EmergencyNumber#EMERGENCY_SERVICE_CATEGORY_AIEC} </li> * </ol> - * @return Map including the key as the active subscription ID (Note: if there is no active + * @return Map including the keys as the active subscription IDs (Note: if there is no active * subscription, the key is {@link SubscriptionManager#getDefaultSubscriptionId}) and the value - * as the list of {@link EmergencyNumber}; null if this information is not available; or throw - * a SecurityException if the caller does not have the permission. + * as the list of {@link EmergencyNumber}; empty Map if this information is not available; + * or throw a SecurityException if the caller does not have the permission. */ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index e9aede7336f0..be5872387d7b 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -781,8 +781,13 @@ public class ImsMmTelManager { } /** - * Change the user's setting for RTT capability of this device. - * @param isEnabled if true RTT will be enabled during calls. + * Sets the capability of RTT for IMS calls placed on this subscription. + * + * Note: This does not affect the value of + * {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting + * for RTT. That value is enabled/disabled separately by the user through the Accessibility + * settings. + * @param isEnabled if true RTT should be enabled during calls made on this subscription. */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean isEnabled) { diff --git a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java index e8fcac19f675..de4f17466a47 100644 --- a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java @@ -19,7 +19,6 @@ package android.telephony.ims.compat.feature; import android.annotation.IntDef; import android.annotation.UnsupportedAppUsage; import android.content.Context; -import android.content.Intent; import android.os.IInterface; import android.os.RemoteException; import android.telephony.SubscriptionManager; @@ -42,32 +41,6 @@ public abstract class ImsFeature { private static final String LOG_TAG = "ImsFeature"; - /** - * Action to broadcast when ImsService is up. - * Internal use only. - * Only defined here separately compatibility purposes with the old ImsService. - * @hide - */ - public static final String ACTION_IMS_SERVICE_UP = - "com.android.ims.IMS_SERVICE_UP"; - - /** - * Action to broadcast when ImsService is down. - * Internal use only. - * Only defined here separately for compatibility purposes with the old ImsService. - * @hide - */ - public static final String ACTION_IMS_SERVICE_DOWN = - "com.android.ims.IMS_SERVICE_DOWN"; - - /** - * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents. - * A long value; the phone ID corresponding to the IMS service coming up or down. - * Only defined here separately for compatibility purposes with the old ImsService. - * @hide - */ - public static final String EXTRA_PHONE_ID = "android:phone_id"; - // Invalid feature value public static final int INVALID = -1; // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously @@ -162,30 +135,6 @@ public abstract class ImsFeature { } } } - sendImsServiceIntent(state); - } - - /** - * Provide backwards compatibility using deprecated service UP/DOWN intents. - */ - private void sendImsServiceIntent(@ImsState int state) { - if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - return; - } - Intent intent; - switch (state) { - case ImsFeature.STATE_NOT_AVAILABLE: - case ImsFeature.STATE_INITIALIZING: - intent = new Intent(ACTION_IMS_SERVICE_DOWN); - break; - case ImsFeature.STATE_READY: - intent = new Intent(ACTION_IMS_SERVICE_UP); - break; - default: - intent = new Intent(ACTION_IMS_SERVICE_DOWN); - } - intent.putExtra(EXTRA_PHONE_ID, mSlotId); - mContext.sendBroadcast(intent); } /** diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 5e3f3983b0a1..74af6bf6fe6e 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -20,7 +20,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; -import android.content.Intent; import android.os.IInterface; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -395,30 +394,6 @@ public abstract class ImsFeature { } } } - sendImsServiceIntent(state); - } - - /** - * Provide backwards compatibility using deprecated service UP/DOWN intents. - */ - private void sendImsServiceIntent(@ImsState int state) { - if (mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { - return; - } - Intent intent; - switch (state) { - case ImsFeature.STATE_UNAVAILABLE: - case ImsFeature.STATE_INITIALIZING: - intent = new Intent(ACTION_IMS_SERVICE_DOWN); - break; - case ImsFeature.STATE_READY: - intent = new Intent(ACTION_IMS_SERVICE_UP); - break; - default: - intent = new Intent(ACTION_IMS_SERVICE_DOWN); - } - intent.putExtra(EXTRA_PHONE_ID, mSlotId); - mContext.sendBroadcast(intent); } /** diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index ed93da16989c..b47b59b28e2a 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -4292,8 +4292,9 @@ public class ConnectivityServiceTest { } // Check that there is no port leaked after all keepalives and sockets are closed. - assertFalse(isUdpPortInUse(srcPort)); - assertFalse(isUdpPortInUse(srcPort2)); + // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7. + // assertFalse(isUdpPortInUse(srcPort)); + // assertFalse(isUdpPortInUse(srcPort2)); mWiFiNetworkAgent.disconnect(); waitFor(mWiFiNetworkAgent.getDisconnectedCV()); @@ -4421,7 +4422,8 @@ public class ConnectivityServiceTest { assertEquals(anyIPv4, sa.getAddress()); testPfd.close(); - assertFalse(isUdpPortInUse(srcPort)); + // TODO: enable this check after ensuring a valid free port. See b/129512753#comment7. + // assertFalse(isUdpPortInUse(srcPort)); mWiFiNetworkAgent.disconnect(); waitFor(mWiFiNetworkAgent.getDisconnectedCV()); diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java index d28ab708f051..2b2e8a72ab04 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.times; @@ -93,6 +94,7 @@ public final class EntitlementManagerTest { private TestStateMachine mSM; private WrappedEntitlementManager mEnMgr; + private TetheringConfiguration mConfig; private class MockContext extends BroadcastInterceptingContext { MockContext(Context base) { @@ -127,13 +129,13 @@ public final class EntitlementManagerTest { } @Override - protected void runUiTetherProvisioning(int type, ResultReceiver receiver) { + protected void runUiTetherProvisioning(int type, int subId, ResultReceiver receiver) { uiProvisionCount++; receiver.send(fakeEntitlementResult, null); } @Override - protected void runSilentTetherProvisioning(int type) { + protected void runSilentTetherProvisioning(int type, int subId) { silentProvisionCount++; addDownstreamMapping(type, fakeEntitlementResult); } @@ -162,8 +164,10 @@ public final class EntitlementManagerTest { mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE, mSystemProperties); mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener); - mEnMgr.updateConfiguration( - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); + mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + mEnMgr.setTetheringConfigurationFetcher(() -> { + return mConfig; + }); } @After @@ -186,17 +190,16 @@ public final class EntitlementManagerTest { // Act like the CarrierConfigManager is present and ready unless told otherwise. when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) .thenReturn(mCarrierConfigManager); - when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig); + when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mCarrierConfig); mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true); mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true); + mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); } @Test public void canRequireProvisioning() { setupForRequiredProvisioning(); - mEnMgr.updateConfiguration( - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); - assertTrue(mEnMgr.isTetherProvisioningRequired()); + assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig)); } @Test @@ -204,31 +207,27 @@ public final class EntitlementManagerTest { setupForRequiredProvisioning(); when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)) .thenReturn(null); - mEnMgr.updateConfiguration( - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); + mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); // Couldn't get the CarrierConfigManager, but still had a declared provisioning app. // Therefore provisioning still be required. - assertTrue(mEnMgr.isTetherProvisioningRequired()); + assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig)); } @Test public void toleratesCarrierConfigMissing() { setupForRequiredProvisioning(); when(mCarrierConfigManager.getConfig()).thenReturn(null); - mEnMgr.updateConfiguration( - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); + mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); // We still have a provisioning app configured, so still require provisioning. - assertTrue(mEnMgr.isTetherProvisioningRequired()); + assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig)); } @Test public void toleratesCarrierConfigNotLoaded() { setupForRequiredProvisioning(); mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, false); - mEnMgr.updateConfiguration( - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); // We still have a provisioning app configured, so still require provisioning. - assertTrue(mEnMgr.isTetherProvisioningRequired()); + assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig)); } @Test @@ -236,14 +235,12 @@ public final class EntitlementManagerTest { setupForRequiredProvisioning(); when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) .thenReturn(null); - mEnMgr.updateConfiguration( - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); - assertFalse(mEnMgr.isTetherProvisioningRequired()); + mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(mEnMgr.isTetherProvisioningRequired(mConfig)); when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) .thenReturn(new String[] {"malformedApp"}); - mEnMgr.updateConfiguration( - new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID)); - assertFalse(mEnMgr.isTetherProvisioningRequired()); + mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); + assertFalse(mEnMgr.isTetherProvisioningRequired(mConfig)); } @Test @@ -265,8 +262,6 @@ public final class EntitlementManagerTest { mEnMgr.reset(); setupForRequiredProvisioning(); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog, - INVALID_SUBSCRIPTION_ID)); // 2. No cache value and don't need to run entitlement check. receiver = new ResultReceiver(null) { @Override @@ -361,8 +356,6 @@ public final class EntitlementManagerTest { public void verifyPermissionResult() { setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog, - INVALID_SUBSCRIPTION_ID)); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); @@ -379,8 +372,6 @@ public final class EntitlementManagerTest { public void verifyPermissionIfAllNotApproved() { setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog, - INVALID_SUBSCRIPTION_ID)); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); @@ -399,8 +390,6 @@ public final class EntitlementManagerTest { public void verifyPermissionIfAnyApproved() { setupForRequiredProvisioning(); mEnMgr.notifyUpstream(true); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog, - INVALID_SUBSCRIPTION_ID)); mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true); mLooper.dispatchAll(); @@ -419,8 +408,6 @@ public final class EntitlementManagerTest { @Test public void testRunTetherProvisioning() { setupForRequiredProvisioning(); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog, - INVALID_SUBSCRIPTION_ID)); // 1. start ui provisioning, upstream is mobile mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR; mEnMgr.notifyUpstream(true); @@ -458,7 +445,7 @@ public final class EntitlementManagerTest { // 5. tear down mobile, then switch SIM mEnMgr.notifyUpstream(false); mLooper.dispatchAll(); - mEnMgr.reevaluateSimCardProvisioning(); + mEnMgr.reevaluateSimCardProvisioning(mConfig); assertEquals(0, mEnMgr.uiProvisionCount); assertEquals(0, mEnMgr.silentProvisionCount); mEnMgr.reset(); @@ -474,8 +461,6 @@ public final class EntitlementManagerTest { @Test public void testCallStopTetheringWhenUiProvisioningFail() { setupForRequiredProvisioning(); - mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog, - INVALID_SUBSCRIPTION_ID)); verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI); mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED; mEnMgr.notifyUpstream(true); @@ -486,7 +471,6 @@ public final class EntitlementManagerTest { verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI); } - public class TestStateMachine extends StateMachine { public final ArrayList<Message> messages = new ArrayList<>(); private final State diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp index c84567b704a6..2488341bfd97 100644 --- a/tools/preload-check/Android.bp +++ b/tools/preload-check/Android.bp @@ -15,6 +15,7 @@ java_test_host { name: "PreloadCheck", srcs: ["src/**/*.java"], + java_resources: [":preloaded-classes-blacklist"], libs: ["tradefed"], test_suites: ["general-tests"], required: ["preload-check-device"], diff --git a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java index dbdecdbecd12..1fde40252939 100644 --- a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java +++ b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java @@ -25,6 +25,9 @@ import com.android.tradefed.testtype.IDeviceTest; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.BufferedReader; +import java.io.InputStreamReader; + @RunWith(DeviceJUnit4ClassRunner.class) public class PreloadCheck implements IDeviceTest { private ITestDevice mTestDevice; @@ -65,6 +68,35 @@ public class PreloadCheck implements IDeviceTest { run("com.android.preload.check.Initialized", "android.animation.Animator"); } + /** + * Test the classes mentioned in the embedded preloaded-classes blacklist. + */ + @Test + public void testBlackList() throws Exception { + StringBuilder sb = new StringBuilder(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass() + .getResourceAsStream("/preloaded-classes-blacklist")))) { + String s; + while ((s = br.readLine()) != null) { + s = s.trim(); + if (s.startsWith("#") || s.isEmpty()) { + continue; + } + try { + run("com.android.preload.check.NotInitialized", s); + } catch (Throwable t) { + if (sb.length() > 0) { + sb.append('\n'); + } + sb.append(t.getMessage()); + } + } + } + if (sb.length() > 0) { + throw new RuntimeException(sb.toString()); + } + } + private void run(String cmd, String... args) throws Exception { StringBuilder sb = new StringBuilder(); sb.append("app_process ") @@ -72,9 +104,16 @@ public class PreloadCheck implements IDeviceTest { .append(" /system/bin ") .append(cmd); for (String arg : args) { - sb.append(' ').append(arg); + sb.append(' ').append(escape(arg)); } String res = mTestDevice.executeShellCommand(sb.toString()); assertEquals(sb.toString(), "OK", res.trim()); } + + private static String escape(String input) { + if (input.indexOf('$') == -1) { + return input; + } + return input.replace("$", "\\$"); + } } |