Merge "Rename Binder.destroy() to Binder.destroyBinder()."
diff --git a/cmds/svc/src/com/android/commands/svc/BluetoothCommand.java b/cmds/svc/src/com/android/commands/svc/BluetoothCommand.java
new file mode 100644
index 0000000..b572ce2
--- /dev/null
+++ b/cmds/svc/src/com/android/commands/svc/BluetoothCommand.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.svc;
+
+import android.bluetooth.BluetoothAdapter;
+import android.os.RemoteException;
+
+public class BluetoothCommand extends Svc.Command {
+
+ public BluetoothCommand() {
+ super("bluetooth");
+ }
+
+ @Override
+ public String shortHelp() {
+ return "Control Bluetooth service";
+ }
+
+ @Override
+ public String longHelp() {
+ return shortHelp() + "\n"
+ + "\n"
+ + "usage: svc bluetooth [enable|disable]\n"
+ + " Turn Bluetooth on or off.\n\n";
+ }
+
+ @Override
+ public void run(String[] args) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ if (adapter == null) {
+ System.err.println("Got a null BluetoothAdapter, is the system running?");
+ return;
+ }
+
+ if (args.length == 2 && "enable".equals(args[1])) {
+ adapter.enable();
+ } else if (args.length == 2 && "disable".equals(args[1])) {
+ adapter.disable();
+ } else {
+ System.err.println(longHelp());
+ }
+ }
+}
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
index 02a92b9..020ca33 100644
--- a/cmds/svc/src/com/android/commands/svc/NfcCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
@@ -17,8 +17,6 @@
package com.android.commands.svc;
import android.content.Context;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
import android.nfc.INfcAdapter;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -44,42 +42,27 @@
@Override
public void run(String[] args) {
- boolean validCommand = false;
- if (args.length >= 2) {
- boolean flag = false;
- if ("enable".equals(args[1])) {
- flag = true;
- validCommand = true;
- } else if ("disable".equals(args[1])) {
- flag = false;
- validCommand = true;
- }
- if (validCommand) {
- IPackageManager pm = IPackageManager.Stub.asInterface(
- ServiceManager.getService("package"));
- try {
- if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0) ||
- pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) {
- INfcAdapter nfc = INfcAdapter.Stub
- .asInterface(ServiceManager.getService(Context.NFC_SERVICE));
- try {
- if (flag) {
- nfc.enable();
- } else
- nfc.disable(true);
- } catch (RemoteException e) {
- System.err.println("NFC operation failed: " + e);
- }
- } else {
- System.err.println("NFC feature not supported.");
- }
- } catch (RemoteException e) {
- System.err.println("RemoteException while calling PackageManager, is the "
- + "system running?");
- }
+ INfcAdapter adapter = INfcAdapter.Stub.asInterface(
+ ServiceManager.getService(Context.NFC_SERVICE));
+
+ if (adapter == null) {
+ System.err.println("Got a null NfcAdapter, is the system running?");
+ return;
+ }
+
+ try {
+ if (args.length == 2 && "enable".equals(args[1])) {
+ adapter.enable();
+ return;
+ } else if (args.length == 2 && "disable".equals(args[1])) {
+ adapter.disable(true);
return;
}
+ } catch (RemoteException e) {
+ System.err.println("NFC operation failed: " + e);
+ return;
}
+
System.err.println(longHelp());
}
diff --git a/cmds/svc/src/com/android/commands/svc/Svc.java b/cmds/svc/src/com/android/commands/svc/Svc.java
index 2cccd1a..62225df 100644
--- a/cmds/svc/src/com/android/commands/svc/Svc.java
+++ b/cmds/svc/src/com/android/commands/svc/Svc.java
@@ -97,5 +97,6 @@
new WifiCommand(),
new UsbCommand(),
new NfcCommand(),
+ new BluetoothCommand(),
};
}
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
index 33f4e80..7d6ad21 100644
--- a/core/java/android/app/timezone/RulesState.java
+++ b/core/java/android/app/timezone/RulesState.java
@@ -174,29 +174,14 @@
}
/**
- * Returns true if the distro IANA rules version supplied is newer or the same as the version in
- * the system image data files.
+ * Returns true if the system image data files contain IANA rules data that are newer than the
+ * distro IANA rules version supplied, i.e. true when the version specified would be "worse"
+ * than the one that is in the system image. Returns false if the system image version is the
+ * same or older, i.e. false when the version specified would be "better" than the one that is
+ * in the system image.
*/
- public boolean isSystemVersionOlderThan(DistroRulesVersion distroRulesVersion) {
- return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) < 0;
- }
-
- public boolean isDistroInstalled() {
- return mDistroStatus == DISTRO_STATUS_INSTALLED;
- }
-
- /**
- * Returns true if the rules version supplied is newer than the one currently installed. If
- * there is no installed distro this method throws IllegalStateException.
- */
- public boolean isInstalledDistroOlderThan(DistroRulesVersion distroRulesVersion) {
- if (mOperationInProgress) {
- throw new IllegalStateException("Distro state not known: operation in progress.");
- }
- if (!isDistroInstalled()) {
- throw new IllegalStateException("No distro installed.");
- }
- return mInstalledDistroRulesVersion.isOlderThan(distroRulesVersion);
+ public boolean isSystemVersionNewerThan(DistroRulesVersion distroRulesVersion) {
+ return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) > 0;
}
public static final Parcelable.Creator<RulesState> CREATOR =
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ff52f27..838fb72 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -70,9 +70,10 @@
* devices, and start a scan for Bluetooth LE devices.
*
* <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
- * adapter, when running on JELLY_BEAN_MR1 and below, call the
- * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and
- * higher, call {@link BluetoothManager#getAdapter}.
+ * adapter, call the {@link BluetoothManager#getAdapter} function on {@link BluetoothManager}.
+ * On JELLY_BEAN_MR1 and below you will need to use the static {@link #getDefaultAdapter}
+ * method instead.
+ * </p><p>
* Fundamentally, this is your starting point for all
* Bluetooth actions. Once you have the local adapter, you can get a set of
* {@link BluetoothDevice} objects representing all paired devices with
@@ -81,14 +82,13 @@
* listen for incoming connection requests with
* {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for
* Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
- *
- * <p>This class is thread safe.
- *
+ * </p>
+ * <p>This class is thread safe.</p>
* <p class="note"><strong>Note:</strong>
* Most methods require the {@link android.Manifest.permission#BLUETOOTH}
* permission and some also require the
* {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
- *
+ * </p>
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>
@@ -565,6 +565,7 @@
* <p>Currently Android only supports one Bluetooth adapter, but the API
* could be extended to support more. This will always return the default
* adapter.
+ * </p>
* @return the default local adapter, or null if Bluetooth is not supported
* on this hardware platform
*/
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 29283e7..4c21aae 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -32,10 +32,7 @@
* Use {@link android.content.Context#getSystemService(java.lang.String)}
* with {@link Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager},
* then call {@link #getAdapter} to obtain the {@link BluetoothAdapter}.
- * <p>
- * Alternately, you can just call the static helper
- * {@link BluetoothAdapter#getDefaultAdapter()}.
- *
+ * </p>
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 67d56d5..dfd5996 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -208,6 +208,8 @@
if (wrapper == null) return;
stopAdvertisingSet(wrapper);
+
+ mLegacyAdvertisers.remove(callback);
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9e8acd0..02f0f18 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -596,7 +596,16 @@
/**
* @hide
*/
- public final static int REQUEST_ID_UNSET = 0;
+ public static final int REQUEST_ID_UNSET = 0;
+
+ /**
+ * Static unique request used as a tombstone for NetworkCallbacks that have been unregistered.
+ * This allows to distinguish when unregistering NetworkCallbacks those that were never
+ * registered and those that were already unregistered.
+ * @hide
+ */
+ private static final NetworkRequest ALREADY_UNREGISTERED =
+ new NetworkRequest.Builder().clearCapabilities().build();
/**
* A NetID indicating no Network is selected.
@@ -2691,10 +2700,6 @@
public void onNetworkResumed(Network network) {}
private NetworkRequest networkRequest;
-
- private boolean isRegistered() {
- return (networkRequest != null) && (networkRequest.requestId != REQUEST_ID_UNSET);
- }
}
/**
@@ -2861,7 +2866,8 @@
final NetworkRequest request;
try {
synchronized(sCallbacks) {
- if (callback.isRegistered()) {
+ if (callback.networkRequest != null
+ && callback.networkRequest != ALREADY_UNREGISTERED) {
// TODO: throw exception instead and enforce 1:1 mapping of callbacks
// and requests (http://b/20701525).
Log.e(TAG, "NetworkCallback was already registered");
@@ -3312,8 +3318,10 @@
// Find all requests associated to this callback and stop callback triggers immediately.
// Callback is reusable immediately. http://b/20701525, http://b/35921499.
synchronized (sCallbacks) {
- Preconditions.checkArgument(
- networkCallback.isRegistered(), "NetworkCallback was not registered");
+ Preconditions.checkArgument(networkCallback.networkRequest != null,
+ "NetworkCallback was not registered");
+ Preconditions.checkArgument(networkCallback.networkRequest != ALREADY_UNREGISTERED,
+ "NetworkCallback was already unregistered");
for (Map.Entry<NetworkRequest, NetworkCallback> e : sCallbacks.entrySet()) {
if (e.getValue() == networkCallback) {
reqs.add(e.getKey());
@@ -3329,7 +3337,7 @@
// Only remove mapping if rpc was successful.
sCallbacks.remove(r);
}
- networkCallback.networkRequest = null;
+ networkCallback.networkRequest = ALREADY_UNREGISTERED;
}
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index c34de15..92e78bc 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -97,6 +97,12 @@
void enableIpv6(String iface);
/**
+ * Set IPv6 autoconf address generation mode.
+ * This is a no-op if an unsupported mode is requested.
+ */
+ void setIPv6AddrGenMode(String iface, int mode);
+
+ /**
* Enables or enables IPv6 ND offload.
*/
void setInterfaceIpv6NdOffload(String iface, boolean enable);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index d6688e3..d5e240a 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -740,7 +740,8 @@
/**
* Return the current priority of a thread, based on Linux priorities.
*
- * @param tid The identifier of the thread/process to change.
+ * @param tid The identifier of the thread/process. If tid equals zero, the priority of the
+ * calling process/thread will be returned.
*
* @return Returns the current priority, as a Linux priority level,
* from -20 for highest scheduling priority to 19 for lowest scheduling
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index aced75d..1a556d5 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -160,6 +160,8 @@
argv = removedArgs;
}
+ // Perform the same initialization that would happen after the Zygote forks.
+ Zygote.nativePreApplicationInit();
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index e065843..91d9d1e 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -121,6 +121,11 @@
int[] fdsToIgnore, String instructionSet, String appDataDir);
/**
+ * Called to do any initialization before starting an application.
+ */
+ native static void nativePreApplicationInit();
+
+ /**
* Special method to start the system server process. In addition to the
* common actions performed in forkAndSpecialize, the pid of the child
* process is recorded such that the death of the child process will cause
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index b5c8815..a271aad 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -58,6 +58,29 @@
jmethodID onTransactID;
} gFields;
+struct JHwBinderHolder : public RefBase {
+ JHwBinderHolder() {}
+
+ sp<JHwBinder> get(JNIEnv *env, jobject obj) {
+ Mutex::Autolock autoLock(mLock);
+
+ sp<JHwBinder> binder = mBinder.promote();
+
+ if (binder == NULL) {
+ binder = new JHwBinder(env, obj);
+ mBinder = binder;
+ }
+
+ return binder;
+ }
+
+private:
+ Mutex mLock;
+ wp<JHwBinder> mBinder;
+
+ DISALLOW_COPY_AND_ASSIGN(JHwBinderHolder);
+};
+
// static
void JHwBinder::InitClass(JNIEnv *env) {
ScopedLocalRef<jclass> clazz(
@@ -75,10 +98,10 @@
}
// static
-sp<JHwBinder> JHwBinder::SetNativeContext(
- JNIEnv *env, jobject thiz, const sp<JHwBinder> &context) {
- sp<JHwBinder> old =
- (JHwBinder *)env->GetLongField(thiz, gFields.contextID);
+sp<JHwBinderHolder> JHwBinder::SetNativeContext(
+ JNIEnv *env, jobject thiz, const sp<JHwBinderHolder> &context) {
+ sp<JHwBinderHolder> old =
+ (JHwBinderHolder *)env->GetLongField(thiz, gFields.contextID);
if (context != NULL) {
context->incStrong(NULL /* id */);
@@ -94,27 +117,27 @@
}
// static
-sp<JHwBinder> JHwBinder::GetNativeContext(
+sp<JHwBinder> JHwBinder::GetNativeBinder(
JNIEnv *env, jobject thiz) {
- return (JHwBinder *)env->GetLongField(thiz, gFields.contextID);
+ JHwBinderHolder *holder =
+ reinterpret_cast<JHwBinderHolder *>(
+ env->GetLongField(thiz, gFields.contextID));
+
+ return holder->get(env, thiz);
}
JHwBinder::JHwBinder(JNIEnv *env, jobject thiz) {
jclass clazz = env->GetObjectClass(thiz);
CHECK(clazz != NULL);
- mClass = (jclass)env->NewGlobalRef(clazz);
- mObject = env->NewWeakGlobalRef(thiz);
+ mObject = env->NewGlobalRef(thiz);
}
JHwBinder::~JHwBinder() {
JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->DeleteWeakGlobalRef(mObject);
+ env->DeleteGlobalRef(mObject);
mObject = NULL;
-
- env->DeleteGlobalRef(mClass);
- mClass = NULL;
}
status_t JHwBinder::onTransact(
@@ -201,10 +224,10 @@
using namespace android;
static void releaseNativeContext(void *nativeContext) {
- sp<JHwBinder> binder = (JHwBinder *)nativeContext;
+ sp<JHwBinderHolder> context = static_cast<JHwBinderHolder *>(nativeContext);
- if (binder != NULL) {
- binder->decStrong(NULL /* id */);
+ if (context != NULL) {
+ context->decStrong(NULL /* id */);
}
}
@@ -215,8 +238,7 @@
}
static void JHwBinder_native_setup(JNIEnv *env, jobject thiz) {
- sp<JHwBinder> context = new JHwBinder(env, thiz);
-
+ sp<JHwBinderHolder> context = new JHwBinderHolder;
JHwBinder::SetNativeContext(env, thiz, context);
}
@@ -244,7 +266,7 @@
return; // XXX exception already pending?
}
- sp<hardware::IBinder> binder = JHwBinder::GetNativeContext(env, thiz);
+ sp<hardware::IBinder> binder = JHwBinder::GetNativeBinder(env, thiz);
/* TODO(b/33440494) this is not right */
sp<hidl::base::V1_0::IBase> base = new hidl::base::V1_0::BpHwBase(binder);
diff --git a/core/jni/android_os_HwBinder.h b/core/jni/android_os_HwBinder.h
index fa8fe01..5352f1e 100644
--- a/core/jni/android_os_HwBinder.h
+++ b/core/jni/android_os_HwBinder.h
@@ -24,13 +24,15 @@
namespace android {
+struct JHwBinderHolder;
+
struct JHwBinder : public hardware::BHwBinder {
static void InitClass(JNIEnv *env);
- static sp<JHwBinder> SetNativeContext(
- JNIEnv *env, jobject thiz, const sp<JHwBinder> &context);
+ static sp<JHwBinderHolder> SetNativeContext(
+ JNIEnv *env, jobject thiz, const sp<JHwBinderHolder> &context);
- static sp<JHwBinder> GetNativeContext(JNIEnv *env, jobject thiz);
+ static sp<JHwBinder> GetNativeBinder(JNIEnv *env, jobject thiz);
JHwBinder(JNIEnv *env, jobject thiz);
@@ -45,7 +47,6 @@
TransactCallback callback);
private:
- jclass mClass;
jobject mObject;
DISALLOW_COPY_AND_ASSIGN(JHwBinder);
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index b21ea828..6ea809a 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -169,7 +169,6 @@
jclass clazz = env->GetObjectClass(thiz);
CHECK(clazz != NULL);
- mClass = (jclass)env->NewGlobalRef(clazz);
mObject = env->NewWeakGlobalRef(thiz);
}
@@ -182,9 +181,6 @@
env->DeleteWeakGlobalRef(mObject);
mObject = NULL;
-
- env->DeleteGlobalRef(mClass);
- mClass = NULL;
}
hardware::Parcel *JHwParcel::getParcel() {
@@ -542,7 +538,7 @@
env, FindClassOrDie(env, PACKAGE_PATH "/HwRemoteBinder"));
if (env->IsInstanceOf(binderObj, hwBinderKlass.get())) {
- binder = JHwBinder::GetNativeContext(env, binderObj);
+ binder = JHwBinder::GetNativeBinder(env, binderObj);
} else if (env->IsInstanceOf(binderObj, hwRemoteBinderKlass.get())) {
binder = JHwRemoteBinder::GetNativeContext(
env, binderObj)->getBinder();
diff --git a/core/jni/android_os_HwParcel.h b/core/jni/android_os_HwParcel.h
index f81de9b..f6e6100 100644
--- a/core/jni/android_os_HwParcel.h
+++ b/core/jni/android_os_HwParcel.h
@@ -53,7 +53,6 @@
virtual ~JHwParcel();
private:
- jclass mClass;
jobject mObject;
hardware::Parcel *mParcel;
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index f2f8e52..9c2ee9c 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -272,7 +272,6 @@
jclass clazz = env->GetObjectClass(thiz);
CHECK(clazz != NULL);
- mClass = (jclass)env->NewGlobalRef(clazz);
mObject = env->NewWeakGlobalRef(thiz);
}
@@ -281,9 +280,6 @@
env->DeleteWeakGlobalRef(mObject);
mObject = NULL;
-
- env->DeleteGlobalRef(mClass);
- mClass = NULL;
}
sp<hardware::IBinder> JHwRemoteBinder::getBinder() const {
diff --git a/core/jni/android_os_HwRemoteBinder.h b/core/jni/android_os_HwRemoteBinder.h
index 77a0278..63aad0a 100644
--- a/core/jni/android_os_HwRemoteBinder.h
+++ b/core/jni/android_os_HwRemoteBinder.h
@@ -68,7 +68,6 @@
virtual ~JHwRemoteBinder();
private:
- jclass mClass;
jobject mObject;
sp<hardware::IBinder> mBinder;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d73e7dd..cb53106 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -221,6 +221,14 @@
// The debug malloc library needs to know whether it's the zygote or a child.
extern "C" int gMallocLeakZygoteChild;
+static void PreApplicationInit() {
+ // The child process sets this to indicate it's not the zygote.
+ gMallocLeakZygoteChild = 1;
+
+ // Set the jemalloc decay time to 1.
+ mallopt(M_DECAY_TIME, 1);
+}
+
static void EnableKeepCapabilities(JNIEnv* env) {
int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
if (rc == -1) {
@@ -517,11 +525,7 @@
pid_t pid = fork();
if (pid == 0) {
- // The child process.
- gMallocLeakZygoteChild = 1;
-
- // Set the jemalloc decay time to 1.
- mallopt(M_DECAY_TIME, 1);
+ PreApplicationInit();
// Clean up any descriptors which must be closed immediately
DetachDescriptors(env, fdsToClose);
@@ -678,6 +682,10 @@
namespace android {
+static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jclass) {
+ PreApplicationInit();
+}
+
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint debug_flags, jobjectArray rlimits,
@@ -807,7 +815,9 @@
{ "nativeAllowFileAcrossFork", "(Ljava/lang/String;)V",
(void *) com_android_internal_os_Zygote_nativeAllowFileAcrossFork },
{ "nativeUnmountStorageOnInit", "()V",
- (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit }
+ (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit },
+ { "nativePreApplicationInit", "()V",
+ (void *) com_android_internal_os_Zygote_nativePreApplicationInit }
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/res/res/values-mcc204-mnc12/config.xml b/core/res/res/values-mcc204-mnc12/config.xml
deleted file mode 100644
index 80432d7..0000000
--- a/core/res/res/values-mcc204-mnc12/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2015, 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 my 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>20408</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc206-mnc05/config.xml b/core/res/res/values-mcc206-mnc05/config.xml
deleted file mode 100644
index a684aaa..0000000
--- a/core/res/res/values-mcc206-mnc05/config.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>20610</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc206-mnc10/config.xml b/core/res/res/values-mcc206-mnc10/config.xml
deleted file mode 100644
index 5c96317..0000000
--- a/core/res/res/values-mcc206-mnc10/config.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>20605</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc208-mnc15/config.xml b/core/res/res/values-mcc208-mnc15/config.xml
deleted file mode 100644
index 32b951c..0000000
--- a/core/res/res/values-mcc208-mnc15/config.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>20801</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc208-mnc26/config.xml b/core/res/res/values-mcc208-mnc26/config.xml
deleted file mode 100644
index 31d2d0f..0000000
--- a/core/res/res/values-mcc208-mnc26/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>20801</item>
- <item>20810</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc02/config.xml b/core/res/res/values-mcc214-mnc02/config.xml
deleted file mode 100755
index c83de57..0000000
--- a/core/res/res/values-mcc214-mnc02/config.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc214-mnc04/config.xml b/core/res/res/values-mcc214-mnc04/config.xml
deleted file mode 100644
index 6dfa87b..0000000
--- a/core/res/res/values-mcc214-mnc04/config.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc05/config.xml b/core/res/res/values-mcc214-mnc05/config.xml
deleted file mode 100755
index 9302b0c..0000000
--- a/core/res/res/values-mcc214-mnc05/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc06/config.xml b/core/res/res/values-mcc214-mnc06/config.xml
deleted file mode 100755
index c3f2643..0000000
--- a/core/res/res/values-mcc214-mnc06/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc08/config.xml b/core/res/res/values-mcc214-mnc08/config.xml
deleted file mode 100755
index 5af6d5d..0000000
--- a/core/res/res/values-mcc214-mnc08/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc09/config.xml b/core/res/res/values-mcc214-mnc09/config.xml
deleted file mode 100755
index d789771..0000000
--- a/core/res/res/values-mcc214-mnc09/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc10/config.xml b/core/res/res/values-mcc214-mnc10/config.xml
deleted file mode 100755
index b66e1a2..0000000
--- a/core/res/res/values-mcc214-mnc10/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc11/config.xml b/core/res/res/values-mcc214-mnc11/config.xml
deleted file mode 100755
index 9fd06db..0000000
--- a/core/res/res/values-mcc214-mnc11/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc12/config.xml b/core/res/res/values-mcc214-mnc12/config.xml
deleted file mode 100755
index 7468238..0000000
--- a/core/res/res/values-mcc214-mnc12/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc13/config.xml b/core/res/res/values-mcc214-mnc13/config.xml
deleted file mode 100755
index 35ff4ae..0000000
--- a/core/res/res/values-mcc214-mnc13/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc14/config.xml b/core/res/res/values-mcc214-mnc14/config.xml
deleted file mode 100755
index b6a7440..0000000
--- a/core/res/res/values-mcc214-mnc14/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc15/config.xml b/core/res/res/values-mcc214-mnc15/config.xml
deleted file mode 100755
index 8296410..0000000
--- a/core/res/res/values-mcc214-mnc15/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc16/config.xml b/core/res/res/values-mcc214-mnc16/config.xml
deleted file mode 100755
index 1aaf577..0000000
--- a/core/res/res/values-mcc214-mnc16/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc17/config.xml b/core/res/res/values-mcc214-mnc17/config.xml
deleted file mode 100755
index be92a32..0000000
--- a/core/res/res/values-mcc214-mnc17/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc18/config.xml b/core/res/res/values-mcc214-mnc18/config.xml
deleted file mode 100755
index 078d7e2..0000000
--- a/core/res/res/values-mcc214-mnc18/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21419</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc19/config.xml b/core/res/res/values-mcc214-mnc19/config.xml
deleted file mode 100755
index d194687..0000000
--- a/core/res/res/values-mcc214-mnc19/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21420</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc20/config.xml b/core/res/res/values-mcc214-mnc20/config.xml
deleted file mode 100755
index 6aaf970..0000000
--- a/core/res/res/values-mcc214-mnc20/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21421</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc214-mnc21/config.xml b/core/res/res/values-mcc214-mnc21/config.xml
deleted file mode 100755
index f890b14..0000000
--- a/core/res/res/values-mcc214-mnc21/config.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21401</item>
- <item>21402</item>
- <item>21403</item>
- <item>21404</item>
- <item>21405</item>
- <item>21406</item>
- <item>21407</item>
- <item>21408</item>
- <item>21409</item>
- <item>21410</item>
- <item>21411</item>
- <item>21412</item>
- <item>21413</item>
- <item>21414</item>
- <item>21415</item>
- <item>21416</item>
- <item>21417</item>
- <item>21418</item>
- <item>21419</item>
- <item>21420</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc219-mnc02/config.xml b/core/res/res/values-mcc219-mnc02/config.xml
deleted file mode 100644
index 2ac6ba6..0000000
--- a/core/res/res/values-mcc219-mnc02/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2015, 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 my 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>21901</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc232-mnc10/config.xml b/core/res/res/values-mcc232-mnc10/config.xml
deleted file mode 100644
index bdf83016..0000000
--- a/core/res/res/values-mcc232-mnc10/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- ** Copyright 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.
- */
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23203</item>
- <item>23205</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc232-mnc11/config.xml b/core/res/res/values-mcc232-mnc11/config.xml
deleted file mode 100644
index 91e37b4..0000000
--- a/core/res/res/values-mcc232-mnc11/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- ** Copyright 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.
- */
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23201</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc232-mnc12/config.xml b/core/res/res/values-mcc232-mnc12/config.xml
deleted file mode 100644
index 91e37b4..0000000
--- a/core/res/res/values-mcc232-mnc12/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- ** Copyright 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.
- */
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23201</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc232-mnc13/config.xml b/core/res/res/values-mcc232-mnc13/config.xml
deleted file mode 100644
index 2c14f87..0000000
--- a/core/res/res/values-mcc232-mnc13/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- ** Copyright 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.
- */
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23203</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc08/config.xml b/core/res/res/values-mcc234-mnc08/config.xml
deleted file mode 100644
index 13d4d8f..0000000
--- a/core/res/res/values-mcc234-mnc08/config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2014, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23430</item>
- <item>23433</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc10/config.xml b/core/res/res/values-mcc234-mnc10/config.xml
deleted file mode 100644
index b704d3f..0000000
--- a/core/res/res/values-mcc234-mnc10/config.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23420</item>
- <item>23426</item>
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc20/config.xml b/core/res/res/values-mcc234-mnc20/config.xml
index 27c91d2..1e4bb0b 100644
--- a/core/res/res/values-mcc234-mnc20/config.xml
+++ b/core/res/res/values-mcc234-mnc20/config.xml
@@ -32,15 +32,4 @@
<!-- Configure mobile network MTU. Carrier specific value is set here.
-->
<integer name="config_mobile_mtu">1440</integer>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23410</item>
- <item>23426</item>
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc234-mnc26/config.xml b/core/res/res/values-mcc234-mnc26/config.xml
deleted file mode 100644
index 8d259de..0000000
--- a/core/res/res/values-mcc234-mnc26/config.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23410</item>
- <item>23420</item>
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc30/config.xml b/core/res/res/values-mcc234-mnc30/config.xml
deleted file mode 100644
index eabdf9a..0000000
--- a/core/res/res/values-mcc234-mnc30/config.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc31/config.xml b/core/res/res/values-mcc234-mnc31/config.xml
deleted file mode 100644
index eabdf9a..0000000
--- a/core/res/res/values-mcc234-mnc31/config.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc32/config.xml b/core/res/res/values-mcc234-mnc32/config.xml
deleted file mode 100644
index eabdf9a..0000000
--- a/core/res/res/values-mcc234-mnc32/config.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc33/config.xml b/core/res/res/values-mcc234-mnc33/config.xml
deleted file mode 100644
index 776b570..0000000
--- a/core/res/res/values-mcc234-mnc33/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. Do not translate. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc34/config.xml b/core/res/res/values-mcc234-mnc34/config.xml
deleted file mode 100644
index eabdf9a..0000000
--- a/core/res/res/values-mcc234-mnc34/config.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc234-mnc86/config.xml b/core/res/res/values-mcc234-mnc86/config.xml
deleted file mode 100644
index eabdf9a..0000000
--- a/core/res/res/values-mcc234-mnc86/config.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>23430</item>
- <item>23431</item>
- <item>23432</item>
- <item>23433</item>
- <item>23434</item>
- <item>23486</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc370/config.xml b/core/res/res/values-mcc302-mnc370/config.xml
index 05265c7..4876a8ae 100644
--- a/core/res/res/values-mcc302-mnc370/config.xml
+++ b/core/res/res/values-mcc302-mnc370/config.xml
@@ -35,14 +35,6 @@
-->
<integer name="config_mobile_mtu">1410</integer>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302220</item>
- <item>302610</item>
- <item>302660</item>
- <item>302720</item>
- <item>302780</item>
- </string-array>
-
<!-- Values for GPS configuration (Rogers) -->
<string-array translatable="false" name="config_gpsParameters">
<item>SUPL_HOST=supl.google.com</item>
diff --git a/core/res/res/values-mcc302-mnc500/config.xml b/core/res/res/values-mcc302-mnc500/config.xml
deleted file mode 100644
index 77f6419..0000000
--- a/core/res/res/values-mcc302-mnc500/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- ** Copyright 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.
- */
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc510/config.xml b/core/res/res/values-mcc302-mnc510/config.xml
deleted file mode 100644
index 77f6419..0000000
--- a/core/res/res/values-mcc302-mnc510/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- ** Copyright 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.
- */
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc302-mnc610/config.xml b/core/res/res/values-mcc302-mnc610/config.xml
index 0af2c39..8ac8f4c 100644
--- a/core/res/res/values-mcc302-mnc610/config.xml
+++ b/core/res/res/values-mcc302-mnc610/config.xml
@@ -18,11 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302</item>
- </string-array>
-
<!-- Configure mobile network MTU. Carrier specific value is set here.
-->
<integer name="config_mobile_mtu">1428</integer>
diff --git a/core/res/res/values-mcc302-mnc640/config.xml b/core/res/res/values-mcc302-mnc640/config.xml
index e005bc0..cba8eed 100644
--- a/core/res/res/values-mcc302-mnc640/config.xml
+++ b/core/res/res/values-mcc302-mnc640/config.xml
@@ -18,11 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302</item>
- </string-array>
-
<!-- Values for GPS configuration (Bell) -->
<string-array translatable="false" name="config_gpsParameters">
<item>SUPL_HOST=supl.google.com</item>
diff --git a/core/res/res/values-mcc302-mnc660/config.xml b/core/res/res/values-mcc302-mnc660/config.xml
index c689d22..8c2e702 100644
--- a/core/res/res/values-mcc302-mnc660/config.xml
+++ b/core/res/res/values-mcc302-mnc660/config.xml
@@ -43,12 +43,4 @@
-->
<integer name="config_mobile_mtu">1430</integer>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302220</item>
- <item>302370</item>
- <item>302610</item>
- <item>302720</item>
- <item>302780</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml
index 7a3540a..dff3678 100644
--- a/core/res/res/values-mcc302-mnc720/config.xml
+++ b/core/res/res/values-mcc302-mnc720/config.xml
@@ -37,14 +37,6 @@
-->
<integer name="config_mobile_mtu">1430</integer>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302220</item>
- <item>302370</item>
- <item>302610</item>
- <item>302660</item>
- <item>302780</item>
- </string-array>
-
<!-- Values for GPS configuration (Rogers) -->
<string-array translatable="false" name="config_gpsParameters">
<item>SUPL_HOST=supl.google.com</item>
diff --git a/core/res/res/values-mcc302-mnc780/config.xml b/core/res/res/values-mcc302-mnc780/config.xml
index a48f695..d300dab 100644
--- a/core/res/res/values-mcc302-mnc780/config.xml
+++ b/core/res/res/values-mcc302-mnc780/config.xml
@@ -20,12 +20,6 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302</item>
- </string-array>
-
<!-- Configure mobile network MTU. Carrier specific value is set here.
-->
<integer name="config_mobile_mtu">1358</integer>
diff --git a/core/res/res/values-mcc310-mnc150/config.xml b/core/res/res/values-mcc310-mnc150/config.xml
index e1f696e..e7d1325 100644
--- a/core/res/res/values-mcc310-mnc150/config.xml
+++ b/core/res/res/values-mcc310-mnc150/config.xml
@@ -18,23 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Show roaming icon though same named operators. -->
- <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
- <item>310110</item>
- <item>310140</item>
- <item>310400</item>
- <item>310470</item>
- <item>311170</item>
- </string-array>
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>310</item>
- <item>311</item>
- <item>312</item>
- <item>313</item>
- <item>314</item>
- <item>315</item>
- <item>316</item>
- </string-array>
<string-array translatable="false" name="config_twoDigitNumberPattern">
<item>"0"</item>
<item>"00"</item>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
index 9accdf0..00ab712 100644
--- a/core/res/res/values-mcc310-mnc410/config.xml
+++ b/core/res/res/values-mcc310-mnc410/config.xml
@@ -20,28 +20,9 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
<!-- Configure mobile network MTU. Carrier specific value is set here.
-->
<integer name="config_mobile_mtu">1410</integer>
- <!-- Show roaming icon though same named operators. -->
- <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
- <item>310110</item>
- <item>310140</item>
- <item>310400</item>
- <item>310470</item>
- <item>311170</item>
- </string-array>
-
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>310</item>
- <item>311</item>
- <item>312</item>
- <item>313</item>
- <item>314</item>
- <item>315</item>
- <item>316</item>
- </string-array>
<!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
<string-array name="config_twoDigitNumberPattern">
<item>"0"</item>
diff --git a/core/res/res/values-mcc340-mnc01/config.xml b/core/res/res/values-mcc340-mnc01/config.xml
index cfc1380..1ca8963 100644
--- a/core/res/res/values-mcc340-mnc01/config.xml
+++ b/core/res/res/values-mcc340-mnc01/config.xml
@@ -38,10 +38,4 @@
<string-array translatable="false" name="config_tether_apndata">
<item>Orangeweb,orangeweb,,,orange,orange,,,,,340,01,1,DUN</item>
</string-array>
-
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>20801</item>
- <item>20815</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc404/config.xml b/core/res/res/values-mcc404/config.xml
index 17539d8..6b77e9c 100644
--- a/core/res/res/values-mcc404/config.xml
+++ b/core/res/res/values-mcc404/config.xml
@@ -18,11 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Show roaming icon though same named operators. -->
- <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
- <item>404</item>
- <item>405</item>
- </string-array>
<!-- Whether camera shutter sound is forced or not (country specific). -->
<bool name="config_camera_sound_forced">true</bool>
</resources>
diff --git a/core/res/res/values-mcc405/config.xml b/core/res/res/values-mcc405/config.xml
index 17539d8..6b77e9c 100644
--- a/core/res/res/values-mcc405/config.xml
+++ b/core/res/res/values-mcc405/config.xml
@@ -18,11 +18,6 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Show roaming icon though same named operators. -->
- <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
- <item>404</item>
- <item>405</item>
- </string-array>
<!-- Whether camera shutter sound is forced or not (country specific). -->
<bool name="config_camera_sound_forced">true</bool>
</resources>
diff --git a/core/res/res/values-mcc425-mnc07/config.xml b/core/res/res/values-mcc425-mnc07/config.xml
index a092fb9..770cebd 100644
--- a/core/res/res/values-mcc425-mnc07/config.xml
+++ b/core/res/res/values-mcc425-mnc07/config.xml
@@ -39,9 +39,4 @@
<string-array translatable="false" name="config_tether_apndata">
<item>PC HOT mobile,pc.hotm,,,,,,,,,425,07,,DUN</item>
</string-array>
-
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>42503</item>
- </string-array>
</resources>
diff --git a/core/res/res/values-mcc425-mnc08/config.xml b/core/res/res/values-mcc425-mnc08/config.xml
deleted file mode 100644
index 8470b86..0000000
--- a/core/res/res/values-mcc425-mnc08/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>42502</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc510-mnc21/config.xml b/core/res/res/values-mcc510-mnc21/config.xml
deleted file mode 100644
index 1fd9dfa..0000000
--- a/core/res/res/values-mcc510-mnc21/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>51001</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc520/config.xml b/core/res/res/values-mcc520/config.xml
deleted file mode 100644
index b2f3efa..0000000
--- a/core/res/res/values-mcc520/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Show roaming icon though same named operators. -->
- <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
- <item>520</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc530-mnc24/config.xml b/core/res/res/values-mcc530-mnc24/config.xml
deleted file mode 100644
index 5598e8d..0000000
--- a/core/res/res/values-mcc530-mnc24/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Show roaming icon though same named operators. -->
- <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
- <item>53001</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc722-mnc36/config.xml b/core/res/res/values-mcc722-mnc36/config.xml
deleted file mode 100644
index daf5373..0000000
--- a/core/res/res/values-mcc722-mnc36/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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 my 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>72234</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc730-mnc01/config.xml b/core/res/res/values-mcc730-mnc01/config.xml
deleted file mode 100644
index 22f4027..0000000
--- a/core/res/res/values-mcc730-mnc01/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2015, 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 my 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>73010</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc730-mnc07/config.xml b/core/res/res/values-mcc730-mnc07/config.xml
deleted file mode 100644
index 836ddf9..0000000
--- a/core/res/res/values-mcc730-mnc07/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2015, 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 my 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>73002</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc730-mnc08/config.xml b/core/res/res/values-mcc730-mnc08/config.xml
deleted file mode 100644
index 836ddf9..0000000
--- a/core/res/res/values-mcc730-mnc08/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2015, 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 my 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>73002</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc730-mnc10/config.xml b/core/res/res/values-mcc730-mnc10/config.xml
deleted file mode 100644
index 58b7d78..0000000
--- a/core/res/res/values-mcc730-mnc10/config.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2015, 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 my 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Don't use roaming icon for considered operators -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>73001</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 37d03ad..7dbd44a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2182,15 +2182,6 @@
when alpha identifier is not provided by the UICC -->
<bool name="config_stkNoAlphaUsrCnf">true</bool>
- <!-- Don't use roaming icon for considered operators.
- A match on config_sameNamedOperatorConsideredRoaming supersedes a match on this.
- Can use mcc or mcc+mnc as item. For example, 302 or 21407.
- If operators, 21404 and 21407, make roaming agreements, user of 21404 should not see
- the roaming icon as using 21407 network.
- To do this, add 21407 item to values-mcc214-mnc04/config.xml -->
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- </string-array>
-
<!-- Threshold (in ms) under which a screen off / screen on will be considered a reset of the
immersive mode confirmation prompt.-->
<integer name="config_immersive_mode_confirmation_panic">5000</integer>
@@ -2198,17 +2189,6 @@
<!-- For some operators, PDU has garbages. To fix it, need to use valid index -->
<integer name="config_valid_wappush_index">-1</integer>
- <!-- This is NOT just for same named operators unlike the name suggests (will blacklist regardless of name).
- A match on this supersedes a match on config_operatorConsideredNonRoaming.
- Uses "startsWith" so you can use a leading substring like the mcc or
- use the complete mcc+mnc string.
- For a given mcc/mcc-mnc, some operators may want to roam (even if
- config_operatorConsideredNonRoaming has the mcc/mcc-mnc).
- user of 40485 should see the roaming icon as using 40483 network
- though same Reliance network.
- To do this, add 40483 item to values-mcc404-mnc85/config.xml -->
- <string-array translatable="false" name="config_sameNamedOperatorConsideredRoaming">
- </string-array>
<!-- call barring MMI code from TS 22.030 Annex B -->
<string-array translatable="false" name="config_callBarringMMI">
<item>33</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 270a215..7363a9b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1164,8 +1164,6 @@
<java-symbol type="array" name="config_cdma_dun_supported_types" />
<java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" />
<java-symbol type="array" name="config_disabledUntilUsedPreinstalledCarrierApps" />
- <java-symbol type="array" name="config_operatorConsideredNonRoaming" />
- <java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" />
<java-symbol type="array" name="config_callBarringMMI" />
<java-symbol type="array" name="config_globalActionsList" />
<java-symbol type="array" name="config_telephonyHardware" />
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
index a9357c9..7f4819b 100644
--- a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
+++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
@@ -107,7 +107,7 @@
"2016a", formatVersion(1, 1), true /* operationInProgress */,
RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
- checkParcelableRoundTrip(rulesStateWithNulls);
+ checkParcelableRoundTrip(rulesStateWithUnknowns);
}
private static void checkParcelableRoundTrip(RulesState rulesState) {
@@ -121,55 +121,14 @@
}
@Test
- public void isSystemVersionOlderThan() {
+ public void isSystemVersionNewerThan() {
RulesState rulesState = new RulesState(
"2016b", formatVersion(1, 1), false /* operationInProgress */,
RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
- assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016a", 1)));
- assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016b", 1)));
- assertTrue(rulesState.isSystemVersionOlderThan(rulesVersion("2016c", 1)));
- }
-
- @Test
- public void isInstalledDistroOlderThan() {
- RulesState operationInProgress = new RulesState(
- "2016b", formatVersion(1, 1), true /* operationInProgress */,
- RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
- RulesState.STAGED_OPERATION_UNKNOWN, null /* installedDistroRulesVersion */);
- try {
- operationInProgress.isInstalledDistroOlderThan(rulesVersion("2016b", 1));
- fail();
- } catch (IllegalStateException expected) {
- }
-
- RulesState nothingInstalled = new RulesState(
- "2016b", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
- try {
- nothingInstalled.isInstalledDistroOlderThan(rulesVersion("2016b", 1));
- fail();
- } catch (IllegalStateException expected) {
- }
-
- DistroRulesVersion installedVersion = rulesVersion("2016b", 3);
- RulesState rulesStateWithInstalledVersion = new RulesState(
- "2016b", formatVersion(1, 1), false /* operationInProgress */,
- RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
- RulesState.DISTRO_STATUS_INSTALLED, installedVersion);
-
- DistroRulesVersion olderRules = rulesVersion("2016a", 1);
- assertEquals(installedVersion.isOlderThan(olderRules),
- rulesStateWithInstalledVersion.isInstalledDistroOlderThan(olderRules));
-
- DistroRulesVersion sameRules = rulesVersion("2016b", 1);
- assertEquals(installedVersion.isOlderThan(sameRules),
- rulesStateWithInstalledVersion.isInstalledDistroOlderThan(sameRules));
-
- DistroRulesVersion newerRules = rulesVersion("2016c", 1);
- assertEquals(installedVersion.isOlderThan(newerRules),
- rulesStateWithInstalledVersion.isInstalledDistroOlderThan(newerRules));
+ assertTrue(rulesState.isSystemVersionNewerThan(rulesVersion("2016a", 1)));
+ assertFalse(rulesState.isSystemVersionNewerThan(rulesVersion("2016b", 1)));
+ assertFalse(rulesState.isSystemVersionNewerThan(rulesVersion("2016c", 1)));
}
private static void assertEqualsContract(RulesState one, RulesState two) {
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index d13f37a..7480ad1 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -47,6 +47,9 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
+
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
@@ -55,6 +58,7 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
public class CaptivePortalLoginActivity extends Activity {
private static final String TAG = CaptivePortalLoginActivity.class.getSimpleName();
@@ -63,7 +67,14 @@
private static final int SOCKET_TIMEOUT_MS = 10000;
- private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS };
+ private enum Result {
+ DISMISSED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED),
+ UNWANTED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_UNWANTED),
+ WANTED_AS_IS(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_WANTED_AS_IS);
+
+ final int metricsEvent;
+ Result(int metricsEvent) { this.metricsEvent = metricsEvent; }
+ };
private URL mUrl;
private String mUserAgent;
@@ -73,10 +84,15 @@
private ConnectivityManager mCm;
private boolean mLaunchBrowser = false;
private MyWebViewClient mWebViewClient;
+ // Ensures that done() happens once exactly, handling concurrent callers with atomic operations.
+ private final AtomicBoolean isDone = new AtomicBoolean(false);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ logMetricsEvent(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
+
mCm = ConnectivityManager.from(this);
mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
@@ -166,13 +182,14 @@
}
private void done(Result result) {
+ if (isDone.getAndSet(true)) {
+ // isDone was already true: done() already called
+ return;
+ }
if (DBG) {
Log.d(TAG, String.format("Result %s for %s", result.name(), mUrl.toString()));
}
- if (mNetworkCallback != null) {
- mCm.unregisterNetworkCallback(mNetworkCallback);
- mNetworkCallback = null;
- }
+ logMetricsEvent(result.metricsEvent);
switch (result) {
case DISMISSED:
mCaptivePortal.reportCaptivePortalDismissed();
@@ -231,8 +248,8 @@
public void onDestroy() {
super.onDestroy();
if (mNetworkCallback != null) {
+ // mNetworkCallback is not null if mUrl is not null.
mCm.unregisterNetworkCallback(mNetworkCallback);
- mNetworkCallback = null;
}
if (mLaunchBrowser) {
// Give time for this network to become default. After 500ms just proceed.
@@ -381,6 +398,7 @@
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+ logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR);
Log.w(TAG, "SSL error (error: " + error.getPrimaryError() + " host: " +
// Only show host to avoid leaking private info.
Uri.parse(error.getUrl()).getHost() + " certificate: " +
@@ -492,4 +510,8 @@
}
return url.getHost();
}
+
+ private void logMetricsEvent(int event) {
+ MetricsLogger.action(this, event, getPackageName());
+ }
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 8bc7520..58f1cd8 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2278,6 +2278,11 @@
// OS: O DR
ACTION_WIFI_SIGNIN = 1008;
+ // CaptivePortalLoginActivity displays SSL error page
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: O DR
+ CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR = 1013;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/core/Android.mk b/services/core/Android.mk
index f9b0d2f..5e5c69d 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -25,7 +25,7 @@
android.hidl.manager-V1.0-java \
LOCAL_STATIC_JAVA_LIBRARIES := \
- tzdata_shared2 \
+ time_zone_distro \
tzdata_update2 \
android.hidl.base-V1.0-java-static \
android.hardware.tetheroffload.control-V1.0-java-static \
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index ac2f4d0..15932cc 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1029,6 +1029,15 @@
}
@Override
+ public void setIPv6AddrGenMode(String iface, int mode) throws ServiceSpecificException {
+ try {
+ mNetdService.setIPv6AddrGenMode(iface, mode);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ @Override
public void disableIpv6(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 4a5129d..3327bec 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -877,6 +877,7 @@
}
if (!TextUtils.isEmpty(ifname)) {
+ maybeTrackNewInterfaceLocked(ifname, ConnectivityManager.TETHERING_WIFI);
changeInterfaceState(ifname, ipServingMode);
} else {
tetherMatchingInterfaces(ipServingMode, ConnectivityManager.TETHERING_WIFI);
@@ -1258,10 +1259,10 @@
sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
}
}
- setUpstreamByType(ns);
+ setUpstreamNetwork(ns);
}
- protected void setUpstreamByType(NetworkState ns) {
+ protected void setUpstreamNetwork(NetworkState ns) {
String iface = null;
if (ns != null && ns.linkProperties != null) {
// Find the interface with the default IPv4 route. It may be the
@@ -1786,7 +1787,9 @@
}
}
- mLog.log(String.format("OBSERVED LinkProperties update iface=%s state=%s", iface, state));
+ mLog.log(String.format(
+ "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
+ iface, IControlsTethering.getStateString(state), newLp));
final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
mTetherMasterSM.sendMessage(which, state, 0, newLp);
}
@@ -1798,7 +1801,10 @@
mLog.log(iface + " is not a tetherable iface, ignoring");
return;
}
+ maybeTrackNewInterfaceLocked(iface, interfaceType);
+ }
+ private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
// If we have already started a TISM for this interface, skip.
if (mTetherStates.containsKey(iface)) {
mLog.log("active iface (" + iface + ") reported as added, ignoring");
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
index aaa63b1..2b81347 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
@@ -33,6 +33,16 @@
public static final int STATE_TETHERED = 2;
public static final int STATE_LOCAL_ONLY = 3;
+ public static String getStateString(int state) {
+ switch (state) {
+ case STATE_UNAVAILABLE: return "UNAVAILABLE";
+ case STATE_AVAILABLE: return "AVAILABLE";
+ case STATE_TETHERED: return "TETHERED";
+ case STATE_LOCAL_ONLY: return "LOCAL_ONLY";
+ }
+ return "UNKNOWN: " + state;
+ }
+
/**
* Notify that |who| has changed its tethering state.
*
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 3aca45f..08deef8 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -85,13 +85,16 @@
mLog.i("tethering offload control not supported");
stop();
}
+ mLog.log("tethering offload started");
}
public void stop() {
+ final boolean wasStarted = started();
mUpstreamLinkProperties = null;
mHwInterface.stopOffloadControl();
mControlInitialized = false;
mConfigInitialized = false;
+ if (wasStarted) mLog.log("tethering offload stopped");
}
public void setUpstreamLinkProperties(LinkProperties lp) {
@@ -161,6 +164,7 @@
}
}
- return mHwInterface.setUpstreamParameters(iface, v4addr, v4gateway, v6gateways);
+ return mHwInterface.setUpstreamParameters(
+ iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 3ecf0d1..1fc1684 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity.tethering;
+import static com.android.internal.util.BitUtils.uint16;
+
import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
@@ -33,6 +35,9 @@
*/
public class OffloadHardwareInterface {
private static final String TAG = OffloadHardwareInterface.class.getSimpleName();
+ private static final String NO_INTERFACE_NAME = "";
+ private static final String NO_IPV4_ADDRESS = "";
+ private static final String NO_IPV4_GATEWAY = "";
private static native boolean configOffload();
@@ -107,6 +112,11 @@
public boolean setUpstreamParameters(
String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
+ iface = iface != null ? iface : NO_INTERFACE_NAME;
+ v4addr = v4addr != null ? v4addr : NO_IPV4_ADDRESS;
+ v4gateway = v4gateway != null ? v4gateway : NO_IPV4_GATEWAY;
+ v6gws = v6gws != null ? v6gws : new ArrayList<>();
+
final CbResults results = new CbResults();
try {
mOffloadControl.setUpstreamParameters(
@@ -143,8 +153,8 @@
handler.post(() -> {
controlCb.onNatTimeoutUpdate(
params.proto,
- params.src.addr, params.src.port,
- params.dst.addr, params.dst.port);
+ params.src.addr, uint16(params.src.port),
+ params.dst.addr, uint16(params.dst.port));
});
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index bff13d4..86b2551 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -56,9 +56,10 @@
import java.util.Random;
/**
- * @hide
+ * Provides the interface to IP-layer serving functionality for a given network
+ * interface, e.g. for tethering or "local-only hotspot" mode.
*
- * Tracks the eligibility of a given network interface for tethering.
+ * @hide
*/
public class TetherInterfaceStateMachine extends StateMachine {
private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64");
@@ -117,6 +118,12 @@
private String mMyUpstreamIfaceName; // may change over time
private NetworkInterface mNetworkInterface;
private byte[] mHwAddr;
+ // TODO: De-duplicate this with mLinkProperties above. Currently, these link
+ // properties are those selected by the IPv6TetheringCoordinator and relayed
+ // to us. By comparison, mLinkProperties contains the addresses and directly
+ // connected routes that have been formed from these properties iff. we have
+ // succeeded in configuring them and are able to announce them within Router
+ // Advertisements (otherwise, we do not add them to mLinkProperties at all).
private LinkProperties mLastIPv6LinkProperties;
private RouterAdvertisementDaemon mRaDaemon;
private RaParams mLastRaParams;
@@ -133,7 +140,7 @@
mIfaceName = ifaceName;
mInterfaceType = interfaceType;
mLinkProperties = new LinkProperties();
- mLinkProperties.setInterfaceName(mIfaceName);
+ resetLinkProperties();
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
mInitialState = new InitialState();
@@ -162,10 +169,15 @@
* Internals.
*/
- // configured when we start tethering and unconfig'd on error or conclusion
- private boolean configureIfaceIp(boolean enabled) {
- if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")");
+ private boolean startIPv4() { return configureIPv4(true); }
+ private void stopIPv4() { configureIPv4(false); }
+
+ private boolean configureIPv4(boolean enabled) {
+ if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
+
+ // TODO: Replace this hard-coded information with dynamically selected
+ // config passed down to us by a higher layer IP-coordinating element.
String ipAsString = null;
int prefixLen = 0;
if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
@@ -179,32 +191,45 @@
return true;
}
- InterfaceConfiguration ifcg = null;
+ final LinkAddress linkAddr;
try {
- ifcg = mNMService.getInterfaceConfig(mIfaceName);
- if (ifcg != null) {
- InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
- ifcg.setLinkAddress(new LinkAddress(addr, prefixLen));
- if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
- // The WiFi stack has ownership of the interface up/down state.
- // It is unclear whether the bluetooth or USB stacks will manage their own
- // state.
- ifcg.ignoreInterfaceUpDownStatus();
- } else {
- if (enabled) {
- ifcg.setInterfaceUp();
- } else {
- ifcg.setInterfaceDown();
- }
- }
- ifcg.clearFlag("running");
- mNMService.setInterfaceConfig(mIfaceName, ifcg);
+ final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
+ if (ifcg == null) {
+ mLog.e("Received null interface config");
+ return false;
}
+
+ InetAddress addr = NetworkUtils.numericToInetAddress(ipAsString);
+ linkAddr = new LinkAddress(addr, prefixLen);
+ ifcg.setLinkAddress(linkAddr);
+ if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
+ // The WiFi stack has ownership of the interface up/down state.
+ // It is unclear whether the Bluetooth or USB stacks will manage their own
+ // state.
+ ifcg.ignoreInterfaceUpDownStatus();
+ } else {
+ if (enabled) {
+ ifcg.setInterfaceUp();
+ } else {
+ ifcg.setInterfaceDown();
+ }
+ }
+ ifcg.clearFlag("running");
+ mNMService.setInterfaceConfig(mIfaceName, ifcg);
} catch (Exception e) {
mLog.e("Error configuring interface " + e);
return false;
}
+ // Directly-connected route.
+ final RouteInfo route = new RouteInfo(linkAddr);
+ if (enabled) {
+ mLinkProperties.addLinkAddress(linkAddr);
+ mLinkProperties.addRoute(route);
+ } else {
+ mLinkProperties.removeLinkAddress(linkAddr);
+ mLinkProperties.removeRoute(route);
+ }
return true;
}
@@ -294,7 +319,7 @@
mLastIPv6LinkProperties = v6only;
}
- private void configureLocalRoutes(
+ private void configureLocalIPv6Routes(
HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
// [1] Remove the routes that are deprecated.
if (!deprecatedPrefixes.isEmpty()) {
@@ -309,6 +334,8 @@
} catch (RemoteException e) {
mLog.e("Failed to remove IPv6 routes from local table: " + e);
}
+
+ for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
}
// [2] Add only the routes that have not previously been added.
@@ -340,11 +367,13 @@
} catch (RemoteException e) {
mLog.e("Failed to add IPv6 routes to local table: " + e);
}
+
+ for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
}
}
}
- private void configureLocalDns(
+ private void configureLocalIPv6Dns(
HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
final INetd netd = NetdService.getInstance();
if (netd == null) {
@@ -362,6 +391,8 @@
} catch (ServiceSpecificException | RemoteException e) {
mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
}
+
+ mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
}
}
@@ -380,6 +411,8 @@
mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
newDnses.remove(dns);
}
+
+ mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
}
}
@@ -396,10 +429,10 @@
final RaParams deprecatedParams =
RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
- configureLocalRoutes(deprecatedParams.prefixes,
+ configureLocalIPv6Routes(deprecatedParams.prefixes,
(newParams != null) ? newParams.prefixes : null);
- configureLocalDns(deprecatedParams.dnses,
+ configureLocalIPv6Dns(deprecatedParams.dnses,
(newParams != null) ? newParams.dnses : null);
mRaDaemon.buildNewRa(deprecatedParams, newParams);
@@ -419,12 +452,19 @@
private void sendInterfaceState(int newInterfaceState) {
mTetherController.updateInterfaceState(
TetherInterfaceStateMachine.this, newInterfaceState, mLastError);
- // TODO: Populate mLinkProperties correctly, and send more sensible
- // updates more frequently (not just here).
+ sendLinkProperties();
+ }
+
+ private void sendLinkProperties() {
mTetherController.updateLinkProperties(
TetherInterfaceStateMachine.this, new LinkProperties(mLinkProperties));
}
+ private void resetLinkProperties() {
+ mLinkProperties.clear();
+ mLinkProperties.setInterfaceName(mIfaceName);
+ }
+
class InitialState extends State {
@Override
public void enter() {
@@ -464,7 +504,7 @@
class BaseServingState extends State {
@Override
public void enter() {
- if (!configureIfaceIp(true)) {
+ if (!startIPv4()) {
mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
return;
}
@@ -498,7 +538,9 @@
mLog.e("Failed to untether interface: " + e);
}
- configureIfaceIp(false);
+ stopIPv4();
+
+ resetLinkProperties();
}
@Override
@@ -515,6 +557,7 @@
break;
case CMD_IPV6_TETHER_UPDATE:
updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
+ sendLinkProperties();
break;
case CMD_IP_FORWARDING_ENABLE_ERROR:
case CMD_IP_FORWARDING_DISABLE_ERROR:
@@ -625,7 +668,6 @@
if (super.processMessage(message)) return true;
maybeLogMessage(this, message.what);
- boolean retValue = true;
switch (message.what) {
case CMD_TETHER_REQUESTED:
mLog.e("CMD_TETHER_REQUESTED while already tethering.");
@@ -655,10 +697,9 @@
mMyUpstreamIfaceName = newUpstreamIfaceName;
break;
default:
- retValue = false;
- break;
+ return false;
}
- return retValue;
+ return true;
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 651de89..9b034ae 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity.tethering;
import static android.content.Context.TELEPHONY_SERVICE;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
@@ -208,29 +209,26 @@
// *always* an upstream, regardless of the upstream interface types
// specified by configuration resources.
if (dunCheck == DUN_REQUIRED) {
- if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) {
- upstreamIfaceTypes.add(TYPE_MOBILE_DUN);
- }
+ appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_DUN);
} else if (dunCheck == DUN_NOT_REQUIRED) {
- if (!upstreamIfaceTypes.contains(TYPE_MOBILE)) {
- upstreamIfaceTypes.add(TYPE_MOBILE);
- }
- if (!upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)) {
- upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
- }
+ appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE);
+ appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_HIPRI);
} else {
// Fix upstream interface types for case DUN_UNSPECIFIED.
// Do not modify if a cellular interface type is already present in the
// upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no
// cellular interface types are found in the upstream interface types.
- if (!(upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)
- || upstreamIfaceTypes.contains(TYPE_MOBILE)
- || upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI))) {
+ if (!(containsOneOf(upstreamIfaceTypes,
+ TYPE_MOBILE_DUN, TYPE_MOBILE, TYPE_MOBILE_HIPRI))) {
upstreamIfaceTypes.add(TYPE_MOBILE);
upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
}
}
+ // Always make sure our good friend Ethernet is present.
+ // TODO: consider unilaterally forcing this at the front.
+ prependIfNotPresent(upstreamIfaceTypes, TYPE_ETHERNET);
+
return upstreamIfaceTypes;
}
@@ -253,4 +251,21 @@
private static String[] copy(String[] strarray) {
return Arrays.copyOf(strarray, strarray.length);
}
+
+ private static void prependIfNotPresent(ArrayList<Integer> list, int value) {
+ if (list.contains(value)) return;
+ list.add(0, value);
+ }
+
+ private static void appendIfNotPresent(ArrayList<Integer> list, int value) {
+ if (list.contains(value)) return;
+ list.add(value);
+ }
+
+ private static boolean containsOneOf(ArrayList<Integer> list, Integer... values) {
+ for (Integer value : values) {
+ if (list.contains(value)) return true;
+ }
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index 82bd356..58bdeb9 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -18,6 +18,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService;
+import com.android.timezone.distro.DistroException;
+import com.android.timezone.distro.DistroVersion;
+import com.android.timezone.distro.TimeZoneDistro;
+import com.android.timezone.distro.StagedDistroOperation;
import android.app.timezone.Callback;
import android.app.timezone.DistroFormatVersion;
@@ -36,9 +40,6 @@
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
-import libcore.tzdata.shared2.DistroException;
-import libcore.tzdata.shared2.DistroVersion;
-import libcore.tzdata.shared2.StagedDistroOperation;
import libcore.tzdata.update2.TimeZoneDistroInstaller;
// TODO(nfuller) Add EventLog calls where useful in the system server.
@@ -224,7 +225,8 @@
try {
byte[] distroBytes =
RulesManagerService.this.mFileDescriptorHelper.readFully(mTimeZoneDistro);
- int installerResult = mInstaller.stageInstallWithErrorCode(distroBytes);
+ TimeZoneDistro distro = new TimeZoneDistro(distroBytes);
+ int installerResult = mInstaller.stageInstallWithErrorCode(distro);
int resultCode = mapInstallerResultToApiCode(installerResult);
sendFinishedStatus(mCallback, resultCode);
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
index 3c73c88..2be69ac 100644
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
@@ -16,6 +16,8 @@
package com.android.server.updates;
+import com.android.timezone.distro.TimeZoneDistro;
+
import android.util.Slog;
import java.io.File;
@@ -46,7 +48,8 @@
@Override
protected void install(byte[] content, int version) throws IOException {
- boolean valid = installer.install(content);
+ TimeZoneDistro distro = new TimeZoneDistro(content);
+ boolean valid = installer.install(distro);
Slog.i(TAG, "Timezone data install valid for this device: " + valid);
// Even if !valid, we call super.install(). Only in the event of an exception should we
// not. If we didn't do this we could attempt to install repeatedly.
diff --git a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
index 241ccf6..4e5c27f 100644
--- a/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
+++ b/services/core/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
@@ -71,7 +71,7 @@
// auto-close it (otherwise there would be double-close problems).
//
// Rely upon the compiler to eliminate the constexprs used for clarity.
-hidl_handle&& handleFromFileDescriptor(base::unique_fd fd) {
+hidl_handle handleFromFileDescriptor(base::unique_fd fd) {
hidl_handle h;
NATIVE_HANDLE_DECLARE_STORAGE(storage, 0, 0);
@@ -83,7 +83,7 @@
static constexpr bool kTakeOwnership = true;
h.setTo(nh, kTakeOwnership);
- return std::move(h);
+ return h;
}
} // namespace
@@ -116,13 +116,14 @@
bool rval;
hidl_string msg;
- configInterface->setHandles(h1, h2,
+ const auto status = configInterface->setHandles(h1, h2,
[&rval, &msg](bool success, const hidl_string& errMsg) {
rval = success;
msg = errMsg;
});
- if (!rval) {
- ALOGE("IOffloadConfig::setHandles() error: %s", msg.c_str());
+ if (!status.isOk() || !rval) {
+ ALOGE("IOffloadConfig::setHandles() error: '%s' / '%s'",
+ status.description().c_str(), msg.c_str());
}
return rval;
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 6608167..7b57bbd 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -20,16 +20,17 @@
import com.android.internal.util.WakeupMessage;
import android.content.Context;
-import android.net.apf.ApfCapabilities;
-import android.net.apf.ApfFilter;
import android.net.DhcpResults;
+import android.net.INetd;
import android.net.InterfaceConfiguration;
import android.net.LinkAddress;
-import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
+import android.net.LinkProperties;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
+import android.net.apf.ApfCapabilities;
+import android.net.apf.ApfFilter;
import android.net.dhcp.DhcpClient;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
@@ -38,7 +39,9 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.os.SystemClock;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
@@ -319,6 +322,16 @@
return this;
}
+ public Builder withIPv6AddrGenModeEUI64() {
+ mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
+ return this;
+ }
+
+ public Builder withIPv6AddrGenModeStablePrivacy() {
+ mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
+ return this;
+ }
+
public ProvisioningConfiguration build() {
return new ProvisioningConfiguration(mConfig);
}
@@ -331,6 +344,7 @@
/* package */ StaticIpConfiguration mStaticIpConfig;
/* package */ ApfCapabilities mApfCapabilities;
/* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS;
+ /* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
public ProvisioningConfiguration() {}
@@ -354,6 +368,7 @@
.add("mStaticIpConfig: " + mStaticIpConfig)
.add("mApfCapabilities: " + mApfCapabilities)
.add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs)
+ .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
.toString();
}
}
@@ -1044,16 +1059,25 @@
return true;
}
+ private void setIPv6AddrGenModeIfSupported() throws RemoteException {
+ try {
+ mNwService.setIPv6AddrGenMode(mInterfaceName, mConfiguration.mIPv6AddrGenMode);
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode != OsConstants.EOPNOTSUPP) {
+ throw e;
+ }
+ }
+ }
+
private boolean startIPv6() {
// Set privacy extensions.
try {
mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
+
+ setIPv6AddrGenModeIfSupported();
mNwService.enableIpv6(mInterfaceName);
- } catch (RemoteException re) {
- logError("Unable to change interface settings: %s", re);
- return false;
- } catch (IllegalStateException ie) {
- logError("Unable to change interface settings: %s", ie);
+ } catch (IllegalStateException | RemoteException | ServiceSpecificException e) {
+ logError("Unable to change interface settings: %s", e);
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
index a7f4c99..86116a9 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -16,6 +16,10 @@
package com.android.server.timezone;
+import com.android.timezone.distro.DistroVersion;
+import com.android.timezone.distro.TimeZoneDistro;
+import com.android.timezone.distro.StagedDistroOperation;
+
import org.junit.Before;
import org.junit.Test;
@@ -29,8 +33,6 @@
import java.io.IOException;
import java.util.concurrent.Executor;
import javax.annotation.Nullable;
-import libcore.tzdata.shared2.DistroVersion;
-import libcore.tzdata.shared2.StagedDistroOperation;
import libcore.tzdata.update2.TimeZoneDistroInstaller;
import static com.android.server.timezone.RulesManagerService.REQUIRED_UPDATER_PERMISSION;
@@ -402,14 +404,16 @@
verifyNoInstallerCallsMade();
verifyNoPackageTrackerCallsMade();
+ TimeZoneDistro expectedDistro = new TimeZoneDistro(expectedContent);
+
// Set up the installer.
- configureStageInstallExpectation(expectedContent, TimeZoneDistroInstaller.INSTALL_SUCCESS);
+ configureStageInstallExpectation(expectedDistro, TimeZoneDistroInstaller.INSTALL_SUCCESS);
// Simulate the async execution.
mFakeExecutor.simulateAsyncExecutionOfLastCommand();
// Verify the expected calls were made to other components.
- verifyStageInstallCalled(expectedContent);
+ verifyStageInstallCalled(expectedDistro);
verifyPackageTrackerCalled(token, true /* success */);
// Check the callback was called.
@@ -435,14 +439,16 @@
verifyNoInstallerCallsMade();
callback.assertNoResultReceived();
+ TimeZoneDistro expectedDistro = new TimeZoneDistro(expectedContent);
+
// Set up the installer.
- configureStageInstallExpectation(expectedContent, TimeZoneDistroInstaller.INSTALL_SUCCESS);
+ configureStageInstallExpectation(expectedDistro, TimeZoneDistroInstaller.INSTALL_SUCCESS);
// Simulate the async execution.
mFakeExecutor.simulateAsyncExecutionOfLastCommand();
// Verify the expected calls were made to other components.
- verifyStageInstallCalled(expectedContent);
+ verifyStageInstallCalled(expectedDistro);
verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
// Check the callback was received.
@@ -470,15 +476,17 @@
verifyNoInstallerCallsMade();
callback.assertNoResultReceived();
+ TimeZoneDistro expectedDistro = new TimeZoneDistro(expectedContent);
+
// Set up the installer.
configureStageInstallExpectation(
- expectedContent, TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR);
+ expectedDistro, TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR);
// Simulate the async execution.
mFakeExecutor.simulateAsyncExecutionOfLastCommand();
// Verify the expected calls were made to other components.
- verifyStageInstallCalled(expectedContent);
+ verifyStageInstallCalled(expectedDistro);
// Validation failure is treated like a successful check: repeating it won't improve things.
boolean expectedSuccess = true;
@@ -779,9 +787,9 @@
.thenThrow(new IOException("Simulated failure"));
}
- private void configureStageInstallExpectation(byte[] expectedContent, int resultCode)
+ private void configureStageInstallExpectation(TimeZoneDistro expected, int resultCode)
throws Exception {
- when(mMockTimeZoneDistroInstaller.stageInstallWithErrorCode(eq(expectedContent)))
+ when(mMockTimeZoneDistroInstaller.stageInstallWithErrorCode(eq(expected)))
.thenReturn(resultCode);
}
@@ -789,8 +797,8 @@
doReturn(success).when(mMockTimeZoneDistroInstaller).stageUninstall();
}
- private void verifyStageInstallCalled(byte[] expectedContent) throws Exception {
- verify(mMockTimeZoneDistroInstaller).stageInstallWithErrorCode(eq(expectedContent));
+ private void verifyStageInstallCalled(TimeZoneDistro expected) throws Exception {
+ verify(mMockTimeZoneDistroInstaller).stageInstallWithErrorCode(eq(expected));
verifyNoMoreInteractions(mMockTimeZoneDistroInstaller);
reset(mMockTimeZoneDistroInstaller);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e3d66e7..17ad779 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1347,6 +1347,30 @@
public static final String KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL =
"disable_voice_barring_notification_bool";
+ /**
+ * List of operators considered non-roaming which won't show roaming icon.
+ * <p>
+ * Can use mcc or mcc+mnc as item. For example, 302 or 21407.
+ * If operators, 21404 and 21407, make roaming agreements, users of 21404 should not see
+ * the roaming icon as using 21407 network.
+ * @hide
+ */
+ public static final String KEY_NON_ROAMING_OPERATOR_STRING_ARRAY =
+ "non_roaming_operator_string_array";
+
+ /**
+ * List of operators considered roaming with the roaming icon.
+ * <p>
+ * Can use mcc or mcc+mnc as item. For example, 302 or 21407.
+ * If operators, 21404 and 21407, make roaming agreements, users of 21404 should see
+ * the roaming icon as using 21407 network.
+ * <p>
+ * A match on this supersedes a match on {@link #KEY_NON_ROAMING_OPERATOR_STRING_ARRAY}.
+ * @hide
+ */
+ public static final String KEY_ROAMING_OPERATOR_STRING_ARRAY =
+ "roaming_operator_string_array";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1583,6 +1607,8 @@
sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
+ sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
+ sDefaults.putStringArray(KEY_ROAMING_OPERATOR_STRING_ARRAY, null);
}
/**
diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java
index c8c6d01..79ee37a 100644
--- a/telephony/java/android/telephony/MbmsDownloadManager.java
+++ b/telephony/java/android/telephony/MbmsDownloadManager.java
@@ -16,10 +16,13 @@
package android.telephony;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
@@ -27,13 +30,18 @@
import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.DownloadStatus;
import android.telephony.mbms.IMbmsDownloadManagerCallback;
+import android.telephony.mbms.MbmsDownloadManagerCallback;
+import android.telephony.mbms.MbmsDownloadReceiver;
import android.telephony.mbms.MbmsException;
+import android.telephony.mbms.MbmsTempFileProvider;
import android.telephony.mbms.MbmsUtils;
import android.telephony.mbms.vendor.IMbmsDownloadService;
import android.util.Log;
+import java.io.File;
+import java.io.IOException;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -47,7 +55,7 @@
* The MBMS middleware should send this when a download of single file has completed or
* failed. Mandatory extras are
* {@link #EXTRA_RESULT}
- * {@link #EXTRA_INFO}
+ * {@link #EXTRA_FILE_INFO}
* {@link #EXTRA_REQUEST}
* {@link #EXTRA_TEMP_LIST}
* {@link #EXTRA_FINAL_URI}
@@ -93,7 +101,7 @@
* is for. Must not be null.
* TODO: future systemapi (here and and all extras) except the two for the app intent
*/
- public static final String EXTRA_INFO = "android.telephony.mbms.extra.INFO";
+ public static final String EXTRA_FILE_INFO = "android.telephony.mbms.extra.FILE_INFO";
/**
* Extra containing the {@link DownloadRequest} for which the download result or file
@@ -144,6 +152,14 @@
"android.telephony.mbms.extra.PAUSED_URI_LIST";
/**
+ * Extra containing a string that points to the middleware's knowledge of where the temp file
+ * root for the app is. The path should be a canonical path as returned by
+ * {@link File#getCanonicalPath()}
+ */
+ public static final String EXTRA_TEMP_FILE_ROOT =
+ "android.telephony.mbms.extra.TEMP_FILE_ROOT";
+
+ /**
* Extra containing a list of {@link Uri}s indicating temp files which the middleware is
* still using.
*/
@@ -165,12 +181,10 @@
public static final int RESULT_EXPIRED = 3;
// TODO - more results!
- private static final long BIND_TIMEOUT_MS = 3000;
-
private final Context mContext;
- private int mSubId = INVALID_SUBSCRIPTION_ID;
+ private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
- private IMbmsDownloadService mService;
+ private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null);
private final IMbmsDownloadManagerCallback mCallback;
private final String mDownloadAppName;
@@ -179,116 +193,221 @@
mContext = context;
mCallback = callback;
mDownloadAppName = downloadAppName;
- mSubId = subId;
+ mSubscriptionId = subId;
}
/**
* Create a new MbmsDownloadManager using the system default data subscription ID.
- *
- * Note that this call will bind a remote service and that may take a bit. This
- * may throw an Illegal ArgumentException or RemoteException.
+ * See {@link #create(Context, IMbmsDownloadManagerCallback, String, int)}
*
* @hide
*/
- public static MbmsDownloadManager createManager(Context context,
+ public static MbmsDownloadManager create(Context context,
IMbmsDownloadManagerCallback listener, String downloadAppName)
throws MbmsException {
- MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName,
+ return create(context, listener, downloadAppName,
SubscriptionManager.getDefaultSubscriptionId());
- mdm.bindAndInitialize();
- return mdm;
}
/**
* Create a new MbmsDownloadManager using the given subscription ID.
*
- * Note that this call will bind a remote service and that may take a bit. This
- * may throw an Illegal ArgumentException or RemoteException.
+ * Note that this call will bind a remote service and that may take a bit. The instance of
+ * {@link MbmsDownloadManager} that is returned will not be ready for use until
+ * {@link IMbmsDownloadManagerCallback#middlewareReady()} is called on the provided callback.
+ * If you attempt to use the manager before it is ready, a {@link MbmsException} will be thrown.
*
+ * This also may throw an {@link IllegalArgumentException} or a {@link MbmsException}.
+ *
+ * @param context The instance of {@link Context} to use
+ * @param listener A callback to get asynchronous error messages and file service updates.
+ * @param downloadAppName The app name, as negotiated with the eMBMS provider
+ * @param subscriptionId The data subscription ID to use
* @hide
*/
-
- public static MbmsDownloadManager createManager(Context context,
- IMbmsDownloadManagerCallback listener, String downloadAppName, int subId)
+ public static MbmsDownloadManager create(Context context,
+ IMbmsDownloadManagerCallback listener, String downloadAppName, int subscriptionId)
throws MbmsException {
MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName,
- subId);
+ subscriptionId);
mdm.bindAndInitialize();
return mdm;
}
private void bindAndInitialize() throws MbmsException {
- // TODO: fold binding for download and streaming into a common utils class.
- final CountDownLatch latch = new CountDownLatch(1);
- ServiceConnection bindListener = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mService = IMbmsDownloadService.Stub.asInterface(service);
- latch.countDown();
- }
+ MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION,
+ new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ IMbmsDownloadService downloadService =
+ IMbmsDownloadService.Stub.asInterface(service);
+ try {
+ downloadService.initialize(
+ mDownloadAppName, mSubscriptionId, mCallback);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Service died before initialization");
+ return;
+ }
+ mService.set(downloadService);
+ }
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
- };
-
- Intent bindIntent = new Intent();
- bindIntent.setComponent(MbmsUtils.toComponentName(
- MbmsUtils.getMiddlewareServiceInfo(mContext, MBMS_DOWNLOAD_SERVICE_ACTION)));
-
- // Kick off the binding, and synchronously wait until binding is complete
- mContext.bindService(bindIntent, bindListener, Context.BIND_AUTO_CREATE);
-
- MbmsUtils.waitOnLatchWithTimeout(latch, BIND_TIMEOUT_MS);
-
- // TODO: initialize
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService.set(null);
+ }
+ });
}
/**
- * Gets the list of files published for download.
- * They may occur at times far in the future.
- * servicesClasses lets the app filter on types of files and is opaque data between
- * the app and the carrier
+ * An inspection API to retrieve the list of available
+ * {@link android.telephony.mbms.FileServiceInfo}s currently being advertised.
+ * The results are returned asynchronously via a call to
+ * {@link IMbmsDownloadManagerCallback#fileServicesUpdated(List)}
*
- * Multiple calls replace trhe list of serviceClasses of interest.
+ * The serviceClasses argument lets the app filter on types of programming and is opaque data
+ * negotiated beforehand between the app and the carrier.
*
- * May throw an IllegalArgumentException or RemoteException.
+ * Multiple calls replace the list of serviceClasses of interest.
*
- * Synchronous responses include
- * <li>SUCCESS</li>
- * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+ * This may throw an {@link MbmsException} containing one of the following errors:
+ * {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
+ * {@link MbmsException#ERROR_CONCURRENT_SERVICE_LIMIT_REACHED}
+ * {@link MbmsException#ERROR_SERVICE_LOST}
*
- * Asynchronous errors through the listener include any of the errors except
- * <li>ERROR_MSDC_UNABLE_TO_)START_SERVICE</li>
- * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
- * <li>ERROR_MSDC_END_OF_SESSION</li>
+ * Asynchronous error codes via the {@link MbmsDownloadManagerCallback#error(int, String)}
+ * callback can include any of the errors except:
+ * {@link MbmsException#ERROR_UNABLE_TO_START_SERVICE}
+ * {@link MbmsException#ERROR_END_OF_SESSION}
*/
- public int getFileServices(List<String> serviceClasses) {
- return 0;
+ public void getFileServices(List<String> classList) throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+ try {
+ int returnCode = downloadService.getFileServices(
+ mDownloadAppName, mSubscriptionId, classList);
+ if (returnCode != MbmsException.SUCCESS) {
+ throw new MbmsException(returnCode);
+ }
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Remote process died");
+ mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ }
}
+ /**
+ * Sets the temp file root for downloads.
+ * All temp files created for the middleware to write to will be contained in the specified
+ * directory. Applications that wish to specify a location only need to call this method once
+ * as long their data is persisted in storage -- the argument will be stored both in a
+ * local instance of {@link android.content.SharedPreferences} and by the middleware.
+ *
+ * If this method is not called at least once before calling
+ * {@link #download(DownloadRequest, IDownloadCallback)}, the framework
+ * will default to a directory formed by the concatenation of the app's files directory and
+ * {@link android.telephony.mbms.MbmsTempFileProvider#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY}.
+ *
+ * This method may not be called while any download requests are still active. If this is
+ * the case, an {@link MbmsException} will be thrown with code
+ * {@link MbmsException#ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT}
+ *
+ * The {@link File} supplied as a root temp file directory must already exist. If not, an
+ * {@link IllegalArgumentException} will be thrown.
+ * @param tempFileRootDirectory A directory to place temp files in.
+ */
+ public void setTempFileRootDirectory(@NonNull File tempFileRootDirectory)
+ throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
+ }
+ if (!tempFileRootDirectory.exists()) {
+ throw new IllegalArgumentException("Provided directory does not exist");
+ }
+ if (!tempFileRootDirectory.isDirectory()) {
+ throw new IllegalArgumentException("Provided File is not a directory");
+ }
+ String filePath;
+ try {
+ filePath = tempFileRootDirectory.getCanonicalPath();
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Unable to canonicalize the provided path: " + e);
+ }
+
+ try {
+ int result = downloadService.setTempFileRootDirectory(
+ mDownloadAppName, mSubscriptionId, filePath);
+ if (result != MbmsException.SUCCESS) {
+ throw new MbmsException(result);
+ }
+ } catch (RemoteException e) {
+ mService.set(null);
+ throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
+ }
+
+ SharedPreferences prefs = mContext.getSharedPreferences(
+ MbmsTempFileProvider.TEMP_FILE_ROOT_PREF_FILE_NAME, 0);
+ prefs.edit().putString(MbmsTempFileProvider.TEMP_FILE_ROOT_PREF_NAME, filePath).apply();
+ }
/**
- * Requests a future download.
- * returns a token which may be used to cancel a download.
+ * Requests a download of a file that is available via multicast.
+ *
* downloadListener is an optional callback object which can be used to get progress reports
* of a currently occuring download. Note this can only run while the calling app
* is running, so future downloads will simply result in resultIntents being sent
* for completed or errored-out downloads. A NULL indicates no callbacks are needed.
*
- * May throw an IllegalArgumentException or RemoteExcpetion.
+ * May throw an {@link IllegalArgumentException}
+ *
+ * If {@link #setTempFileRootDirectory(File)} has not called after the app has been installed,
+ * this method will create a directory at the default location defined at
+ * {@link MbmsTempFileProvider#DEFAULT_TOP_LEVEL_TEMP_DIRECTORY} and store that as the temp
+ * file root directory.
*
* Asynchronous errors through the listener include any of the errors
+ *
+ * @param request The request that specifies what should be downloaded
+ * @param callback Optional callback that will provide progress updates if the app is running.
*/
- public DownloadRequest download(DownloadRequest request, IDownloadCallback listener) {
- request.setAppName(mDownloadAppName);
- try {
- mService.download(request, listener);
- } catch (RemoteException e) {
- mService = null;
+ public void download(DownloadRequest request, IDownloadCallback callback)
+ throws MbmsException {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
+ throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
}
- return request;
+
+ // Check to see whether the app's set a temp root dir yet, and set it if not.
+ SharedPreferences prefs = mContext.getSharedPreferences(
+ MbmsTempFileProvider.TEMP_FILE_ROOT_PREF_FILE_NAME, 0);
+ if (prefs.getString(MbmsTempFileProvider.TEMP_FILE_ROOT_PREF_NAME, null) == null) {
+ File tempRootDirectory = new File(mContext.getFilesDir(),
+ MbmsTempFileProvider.DEFAULT_TOP_LEVEL_TEMP_DIRECTORY);
+ tempRootDirectory.mkdirs();
+ setTempFileRootDirectory(tempRootDirectory);
+ }
+
+ request.setAppName(mDownloadAppName);
+ // Check if the request is a multipart download. If so, validate that the destination is
+ // a directory that exists.
+ // TODO: figure out what qualifies a request as a multipart download request.
+ if (request.getSourceUri().getLastPathSegment() != null &&
+ request.getSourceUri().getLastPathSegment().contains("*")) {
+ File toFile = new File(request.getDestinationUri().getSchemeSpecificPart());
+ if (!toFile.isDirectory()) {
+ throw new IllegalArgumentException("Multipart download must specify valid " +
+ "destination directory.");
+ }
+ }
+ // TODO: check to make sure destination is clear
+ // TODO: write download request token
+ try {
+ downloadService.download(request, callback);
+ } catch (RemoteException e) {
+ mService.set(null);
+ }
}
/**
@@ -355,13 +474,45 @@
return 0;
}
+ /**
+ * Retrieves the {@link ComponentName} for the {@link android.content.BroadcastReceiver} that
+ * the various intents from the middleware should be targeted towards.
+ * @param uid The uid of the frontend app.
+ * @return The component name of the receiver that the middleware should send its intents to,
+ * or null if the app didn't declare it in the manifest.
+ *
+ * @hide
+ * future systemapi
+ */
+ public static ComponentName getAppReceiverFromUid(Context context, int uid) {
+ String[] packageNames = context.getPackageManager().getPackagesForUid(uid);
+ if (packageNames == null) {
+ return null;
+ }
+
+ for (String packageName : packageNames) {
+ ComponentName candidate = new ComponentName(packageName,
+ MbmsDownloadReceiver.class.getCanonicalName());
+ Intent queryIntent = new Intent();
+ queryIntent.setComponent(candidate);
+ List<ResolveInfo> receivers =
+ context.getPackageManager().queryBroadcastReceivers(queryIntent, 0);
+ if (receivers != null && receivers.size() > 0) {
+ return candidate;
+ }
+ }
+ return null;
+ }
+
public void dispose() {
try {
- if (mService != null) {
- mService.dispose(mDownloadAppName, mSubId);
- } else {
+ IMbmsDownloadService downloadService = mService.get();
+ if (downloadService == null) {
Log.i(LOG_TAG, "Service already dead");
+ return;
}
+ downloadService.dispose(mDownloadAppName, mSubscriptionId);
+ mService.set(null);
} catch (RemoteException e) {
// Ignore
Log.i(LOG_TAG, "Remote exception while disposing of service");
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
index f68e243..af7f333 100644
--- a/telephony/java/android/telephony/MbmsStreamingManager.java
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -18,11 +18,7 @@
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.mbms.MbmsException;
@@ -34,56 +30,18 @@
import android.telephony.mbms.vendor.IMbmsStreamingService;
import android.util.Log;
-import java.util.LinkedList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
/** @hide */
public class MbmsStreamingManager {
- private interface ServiceListener {
- void onServiceConnected();
- void onServiceDisconnected();
- }
-
private static final String LOG_TAG = "MbmsStreamingManager";
public static final String MBMS_STREAMING_SERVICE_ACTION =
"android.telephony.action.EmbmsStreaming";
- private static final boolean DEBUG = true;
- private static final int BIND_TIMEOUT_MS = 3000;
-
- private IMbmsStreamingService mService;
- private ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (service != null) {
- Log.i(LOG_TAG, String.format("Connected to service %s", name));
- synchronized (MbmsStreamingManager.this) {
- mService = IMbmsStreamingService.Stub.asInterface(service);
- for (ServiceListener l : mServiceListeners) {
- l.onServiceConnected();
- }
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Log.i(LOG_TAG, String.format("Disconnected from service %s", name));
- synchronized (MbmsStreamingManager.this) {
- mService = null;
- for (ServiceListener l : mServiceListeners) {
- l.onServiceDisconnected();
- }
- }
- }
- };
-
- private List<ServiceListener> mServiceListeners = new LinkedList<>();
-
+ private AtomicReference<IMbmsStreamingService> mService = new AtomicReference<>(null);
private MbmsStreamingManagerCallback mCallbackToApp;
private final String mAppName;
@@ -128,28 +86,26 @@
public static MbmsStreamingManager create(Context context,
MbmsStreamingManagerCallback listener, String streamingAppName)
throws MbmsException {
- int subId = SubscriptionManager.getDefaultSubscriptionId();
- MbmsStreamingManager manager = new MbmsStreamingManager(context, listener,
- streamingAppName, subId);
- manager.bindAndInitialize();
- return manager;
+ return create(context, listener, streamingAppName,
+ SubscriptionManager.getDefaultSubscriptionId());
}
/**
* Terminates this instance, ending calls to the registered listener. Also terminates
* any streaming services spawned from this instance.
*/
- public synchronized void dispose() {
- if (mService == null) {
+ public void dispose() {
+ IMbmsStreamingService streamingService = mService.get();
+ if (streamingService == null) {
// Ignore and return, assume already disposed.
return;
}
try {
- mService.dispose(mAppName, mSubscriptionId);
+ streamingService.dispose(mAppName, mSubscriptionId);
} catch (RemoteException e) {
// Ignore for now
}
- mService = null;
+ mService.set(null);
}
/**
@@ -171,17 +127,19 @@
* {@link MbmsException#ERROR_END_OF_SESSION}
*/
public void getStreamingServices(List<String> classList) throws MbmsException {
- if (mService == null) {
+ IMbmsStreamingService streamingService = mService.get();
+ if (streamingService == null) {
throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
}
try {
- int returnCode = mService.getStreamingServices(mAppName, mSubscriptionId, classList);
+ int returnCode = streamingService.getStreamingServices(
+ mAppName, mSubscriptionId, classList);
if (returnCode != MbmsException.SUCCESS) {
throw new MbmsException(returnCode);
}
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
- mService = null;
+ mService.set(null);
throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
}
}
@@ -190,7 +148,7 @@
* Starts streaming a requested service, reporting status to the indicated listener.
* Returns an object used to control that stream. The stream may not be ready for consumption
* immediately upon return from this method -- wait until the streaming state has been
- * reported via {@link android.telephony.mbms.StreamingServiceCallback#streamStateChanged(int)}.
+ * reported via {@link android.telephony.mbms.StreamingServiceCallback#streamStateUpdated(int)}
*
* May throw an {@link MbmsException} containing any of the following error codes:
* {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
@@ -203,71 +161,47 @@
*/
public StreamingService startStreaming(StreamingServiceInfo serviceInfo,
StreamingServiceCallback listener) throws MbmsException {
- if (mService == null) {
+ IMbmsStreamingService streamingService = mService.get();
+ if (streamingService == null) {
throw new MbmsException(MbmsException.ERROR_MIDDLEWARE_NOT_BOUND);
}
try {
- int returnCode = mService.startStreaming(
+ int returnCode = streamingService.startStreaming(
mAppName, mSubscriptionId, serviceInfo.getServiceId(), listener);
if (returnCode != MbmsException.SUCCESS) {
throw new MbmsException(returnCode);
}
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
- mService = null;
+ mService.set(null);
throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
}
return new StreamingService(
- mAppName, mSubscriptionId, mService, serviceInfo, listener);
+ mAppName, mSubscriptionId, streamingService, serviceInfo, listener);
}
private void bindAndInitialize() throws MbmsException {
- // Kick off the binding, and synchronously wait until binding is complete
- final CountDownLatch latch = new CountDownLatch(1);
- ServiceListener bindListener = new ServiceListener() {
- @Override
- public void onServiceConnected() {
- latch.countDown();
- }
+ MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION,
+ new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ IMbmsStreamingService streamingService =
+ IMbmsStreamingService.Stub.asInterface(service);
+ try {
+ streamingService.initialize(mCallbackToApp, mAppName, mSubscriptionId);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Service died before initialization");
+ return;
+ }
+ mService.set(null);
+ }
- @Override
- public void onServiceDisconnected() {
- }
- };
-
- synchronized (this) {
- mServiceListeners.add(bindListener);
- }
-
- Intent bindIntent = new Intent();
- bindIntent.setComponent(MbmsUtils.toComponentName(
- MbmsUtils.getMiddlewareServiceInfo(mContext, MBMS_STREAMING_SERVICE_ACTION)));
-
- mContext.bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
-
- MbmsUtils.waitOnLatchWithTimeout(latch, BIND_TIMEOUT_MS);
-
- // Remove the listener and call the initialization method through the interface.
- synchronized (this) {
- mServiceListeners.remove(bindListener);
-
- if (mService == null) {
- throw new MbmsException(MbmsException.ERROR_BIND_TIMEOUT_OR_FAILURE);
- }
-
- try {
- int returnCode = mService.initialize(mCallbackToApp, mAppName, mSubscriptionId);
- if (returnCode != MbmsException.SUCCESS) {
- throw new MbmsException(returnCode);
- }
- } catch (RemoteException e) {
- mService = null;
- Log.e(LOG_TAG, "Service died before initialization");
- throw new MbmsException(MbmsException.ERROR_SERVICE_LOST);
- }
- }
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService.set(null);
+ }
+ });
}
-
}
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java
index f3ca058..c561741 100644
--- a/telephony/java/android/telephony/mbms/DownloadRequest.java
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.java
@@ -35,9 +35,8 @@
private FileServiceInfo serviceInfo;
private Uri source;
private Uri dest;
- private int sub;
+ private int subscriptionId;
private String appIntent;
- private String appName; // not the Android app Name, the embms app Name
public Builder setId(int id) {
this.id = id;
@@ -59,8 +58,8 @@
return this;
}
- public Builder setSub(int sub) {
- this.sub = sub;
+ public Builder setSubscriptionId(int sub) {
+ this.subscriptionId = sub;
return this;
}
@@ -70,7 +69,8 @@
}
public DownloadRequest build() {
- return new DownloadRequest(id, serviceInfo, source, dest, sub, appIntent, appName);
+ return new DownloadRequest(id, serviceInfo, source, dest,
+ subscriptionId, appIntent, null);
}
}
@@ -78,7 +78,7 @@
private final FileServiceInfo fileServiceInfo;
private final Uri sourceUri;
private final Uri destinationUri;
- private final int subId;
+ private final int subscriptionId;
private final String serializedResultIntentForApp;
private String appName; // not the Android app Name, the embms app name
@@ -89,7 +89,7 @@
fileServiceInfo = serviceInfo;
sourceUri = source;
destinationUri = dest;
- subId = sub;
+ subscriptionId = sub;
serializedResultIntentForApp = appIntent;
appName = name;
}
@@ -103,7 +103,7 @@
fileServiceInfo = dr.fileServiceInfo;
sourceUri = dr.sourceUri;
destinationUri = dr.destinationUri;
- subId = dr.subId;
+ subscriptionId = dr.subscriptionId;
serializedResultIntentForApp = dr.serializedResultIntentForApp;
appName = dr.appName;
}
@@ -113,7 +113,7 @@
fileServiceInfo = in.readParcelable(getClass().getClassLoader());
sourceUri = in.readParcelable(getClass().getClassLoader());
destinationUri = in.readParcelable(getClass().getClassLoader());
- subId = in.readInt();
+ subscriptionId = in.readInt();
serializedResultIntentForApp = in.readString();
appName = in.readString();
}
@@ -127,7 +127,7 @@
out.writeParcelable(fileServiceInfo, flags);
out.writeParcelable(sourceUri, flags);
out.writeParcelable(destinationUri, flags);
- out.writeInt(subId);
+ out.writeInt(subscriptionId);
out.writeString(serializedResultIntentForApp);
out.writeString(appName);
}
@@ -148,8 +148,8 @@
return destinationUri;
}
- public int getSubId() {
- return subId;
+ public int getSubscriptionId() {
+ return subscriptionId;
}
public Intent getIntentForApp() {
diff --git a/telephony/java/android/telephony/mbms/FileInfo.java b/telephony/java/android/telephony/mbms/FileInfo.java
index d3888bd..1b87393 100644
--- a/telephony/java/android/telephony/mbms/FileInfo.java
+++ b/telephony/java/android/telephony/mbms/FileInfo.java
@@ -31,29 +31,22 @@
* This is used internally but is also one of the few pieces of data about the content that is
* exposed and may be needed for disambiguation by the application.
*/
- final Uri uri;
+ private final Uri uri;
/**
* The mime type of the content.
*/
- final String mimeType;
+ private final String mimeType;
/**
* The size of the file in bytes.
*/
- final long size;
+ private final long size;
/**
* The MD5 hash of the file.
*/
- final byte md5Hash[];
-
- /**
- * Gets the parent service for this file.
- */
- public FileServiceInfo getFileServiceInfo() {
- return null;
- }
+ private final byte md5Hash[];
public static final Parcelable.Creator<FileInfo> CREATOR =
new Parcelable.Creator<FileInfo>() {
@@ -68,6 +61,13 @@
}
};
+ public FileInfo(Uri uri, String mimeType, long size, byte[] md5Hash) {
+ this.uri = uri;
+ this.mimeType = mimeType;
+ this.size = size;
+ this.md5Hash = md5Hash;
+ }
+
private FileInfo(Parcel in) {
uri = in.readParcelable(null);
mimeType = in.readString();
@@ -90,4 +90,20 @@
public int describeContents() {
return 0;
}
+
+ public Uri getUri() {
+ return uri;
+ }
+
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public byte[] getMd5Hash() {
+ return md5Hash;
+ }
}
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java
index 8e890fd..6646dc8 100644
--- a/telephony/java/android/telephony/mbms/FileServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java
@@ -30,13 +30,13 @@
* @hide
*/
public class FileServiceInfo extends ServiceInfo implements Parcelable {
- public List<FileInfo> files;
+ private final List<FileInfo> files;
public FileServiceInfo(Map<Locale, String> newNames, String newClassName,
List<Locale> newLocales, String newServiceId, Date start, Date end,
List<FileInfo> newFiles) {
super(newNames, newClassName, newLocales, newServiceId, start, end);
- files = new ArrayList(newFiles);
+ files = new ArrayList<>(newFiles);
}
public static final Parcelable.Creator<FileServiceInfo> CREATOR =
@@ -68,4 +68,9 @@
public int describeContents() {
return 0;
}
+
+ public List<FileInfo> getFiles() {
+ return files;
+ }
+
}
diff --git a/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl
index 03227d0..ac2f202 100755
--- a/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl
@@ -24,19 +24,11 @@
* The interface the clients top-level file download listener will satisfy.
* @hide
*/
-interface IMbmsDownloadManagerCallback
+oneway interface IMbmsDownloadManagerCallback
{
void error(int errorCode, String message);
- /**
- * Called to indicate published File Services have changed.
- *
- * This will only be called after the application has requested
- * a list of file services and specified a service class list
- * of interest AND the results of a subsequent getFileServices
- * call with the same service class list would
- * return different
- * results.
- */
void fileServicesUpdated(in List<FileServiceInfo> services);
+
+ void middlewareReady();
}
diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
index cbf0fca..8116a7f 100755
--- a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
@@ -24,30 +24,13 @@
* The interface the clients top-level streaming listener will satisfy.
* @hide
*/
-interface IMbmsStreamingManagerCallback
+oneway interface IMbmsStreamingManagerCallback
{
void error(int errorCode, String message);
- /**
- * Called to indicate published Streaming Services have changed.
- *
- * This will only be called after the application has requested
- * a list of streaming services and specified a service class list
- * of interest AND the results of a subsequent getStreamServices
- * call with the same service class list would
- * return different
- * results.
- */
void streamingServicesUpdated(in List<StreamingServiceInfo> services);
- /**
- * Called to indicate the active Streaming Services have changed.
- *
- * This will be caused whenever a new service starts streaming or whenever
- * MbmsStreamServiceManager.getActiveStreamingServices is called.
- *
- * @param services a list of StreamingServiceInfos. May be empty if
- * there are no active StreamingServices
- */
void activeStreamingServicesUpdated(in List<StreamingServiceInfo> services);
+
+ void middlewareReady();
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
index 16fafe4..5b22199 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
@@ -48,4 +48,17 @@
public void fileServicesUpdated(List<FileServiceInfo> services) {
// default implementation empty
}
+
+ /**
+ * Called to indicate that the middleware has been initialized and is ready.
+ *
+ * Before this method is called, calling any method on an instance of
+ * {@link android.telephony.MbmsDownloadManager} will result in an {@link MbmsException}
+ * being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
+ * or {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ */
+ @Override
+ public void middlewareReady() {
+ // default implementation empty
+ }
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index c01ddae..b51c367 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -31,8 +31,8 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
import java.util.UUID;
/**
@@ -54,6 +54,11 @@
setResultCode(1 /* TODO: define error constants */);
return;
}
+ if (!Objects.equals(intent.getStringExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT),
+ MbmsTempFileProvider.getEmbmsTempFileDir(context).getPath())) {
+ setResultCode(1 /* TODO: define error constants */);
+ return;
+ }
if (MbmsDownloadManager.ACTION_DOWNLOAD_RESULT_INTERNAL.equals(intent.getAction())) {
moveDownloadedFile(context, intent);
@@ -74,7 +79,11 @@
Log.w(LOG_TAG, "Download result did not include the associated request. Ignoring.");
return false;
}
- if (!intent.hasExtra(MbmsDownloadManager.EXTRA_INFO)) {
+ if (!intent.hasExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT)) {
+ Log.w(LOG_TAG, "Download result did not include the temp file root. Ignoring.");
+ return false;
+ }
+ if (!intent.hasExtra(MbmsDownloadManager.EXTRA_FILE_INFO)) {
Log.w(LOG_TAG, "Download result did not include the associated file info. " +
"Ignoring.");
return false;
@@ -90,6 +99,10 @@
Log.w(LOG_TAG, "Temp file request not include the associated request. Ignoring.");
return false;
}
+ if (!intent.hasExtra(MbmsDownloadManager.EXTRA_TEMP_FILE_ROOT)) {
+ Log.w(LOG_TAG, "Download result did not include the temp file root. Ignoring.");
+ return false;
+ }
return true;
}
@@ -121,12 +134,15 @@
}
String relativePath = calculateDestinationFileRelativePath(request,
- (FileInfo) intent.getParcelableExtra(MbmsDownloadManager.EXTRA_INFO));
+ (FileInfo) intent.getParcelableExtra(MbmsDownloadManager.EXTRA_FILE_INFO));
- if (!moveTempFile(finalTempFile, destinationUri, relativePath)) {
+ Uri finalFileLocation = moveTempFile(finalTempFile, destinationUri, relativePath);
+ if (finalFileLocation == null) {
Log.w(LOG_TAG, "Failed to move temp file to final destination");
+ // TODO: how do we notify the app of this?
setResultCode(1);
}
+ intentForApp.putExtra(MbmsDownloadManager.EXTRA_COMPLETED_FILE_URI, finalFileLocation);
context.sendBroadcast(intentForApp);
setResultCode(0);
@@ -226,7 +242,6 @@
return null;
}
-
private ArrayList<UriPathPair> generateUrisForPausedFiles(Context context,
DownloadRequest request, List<Uri> pausedFiles) {
if (pausedFiles == null) {
@@ -258,13 +273,15 @@
private static String calculateDestinationFileRelativePath(DownloadRequest request,
FileInfo info) {
- // TODO: determine whether this is actually the path determination scheme we want to use
- List<String> filePathComponents = info.uri.getPathSegments();
+ List<String> filePathComponents = info.getUri().getPathSegments();
List<String> requestPathComponents = request.getSourceUri().getPathSegments();
Iterator<String> filePathIter = filePathComponents.iterator();
Iterator<String> requestPathIter = requestPathComponents.iterator();
- LinkedList<String> relativePathComponents = new LinkedList<>();
+ StringBuilder pathBuilder = new StringBuilder();
+ // Iterate through the segments of the carrier's URI to the file, along with the segments
+ // of the source URI specified in the download request. The relative path is calculated
+ // as the tail of the file's URI that does not match the path segments in the source URI.
while (filePathIter.hasNext()) {
String currFilePathComponent = filePathIter.next();
if (requestPathIter.hasNext()) {
@@ -273,28 +290,44 @@
continue;
}
}
- relativePathComponents.add(currFilePathComponent);
+ pathBuilder.append(currFilePathComponent);
+ pathBuilder.append('/');
}
- return String.join("/", relativePathComponents);
+ // remove the trailing slash
+ if (pathBuilder.length() > 0) {
+ pathBuilder.deleteCharAt(pathBuilder.length() - 1);
+ }
+ return pathBuilder.toString();
}
- private static boolean moveTempFile(Uri fromPath, Uri toPath, String relativePath) {
+ /*
+ * Moves a tempfile located at fromPath to a new location at toPath. If
+ * toPath is a directory, the destination file will be located at relativePath
+ * underneath toPath.
+ */
+ private static Uri moveTempFile(Uri fromPath, Uri toPath, String relativePath) {
if (!ContentResolver.SCHEME_FILE.equals(fromPath.getScheme())) {
Log.w(LOG_TAG, "Moving source uri " + fromPath+ " does not have a file scheme");
- return false;
+ return null;
}
if (!ContentResolver.SCHEME_FILE.equals(toPath.getScheme())) {
Log.w(LOG_TAG, "Moving destination uri " + toPath + " does not have a file scheme");
- return false;
+ return null;
}
File fromFile = new File(fromPath.getSchemeSpecificPart());
- File toFile = new File(toPath.getSchemeSpecificPart(), relativePath);
+ File toFile = new File(toPath.getSchemeSpecificPart());
+ if (toFile.isDirectory()) {
+ toFile = new File(toFile, relativePath);
+ }
toFile.getParentFile().mkdirs();
- // TODO: This may not work if the two files are on different filesystems. Should we
- // enforce that the temp file storage and the permanent storage are both in the same fs?
- return fromFile.renameTo(toFile);
+ // TODO: This will not work if the two files are on different filesystems. Add manual
+ // copy later.
+ if (fromFile.renameTo(toFile)) {
+ return Uri.fromFile(toFile);
+ }
+ return null;
}
private static boolean verifyTempFilePath(Context context, DownloadRequest request,
@@ -323,8 +356,7 @@
* Returns a File linked to the directory used to store temp files for this request
*/
private static File getEmbmsTempFileDirForRequest(Context context, DownloadRequest request) {
- File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(
- context, getFileProviderAuthority(context));
+ File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(context);
// TODO: better naming scheme for temp file dirs
String tempFileDirName = String.valueOf(request.getFileServiceInfo().getServiceId());
diff --git a/telephony/java/android/telephony/mbms/MbmsException.java b/telephony/java/android/telephony/mbms/MbmsException.java
index 6b90592..8260b72 100644
--- a/telephony/java/android/telephony/mbms/MbmsException.java
+++ b/telephony/java/android/telephony/mbms/MbmsException.java
@@ -22,7 +22,7 @@
public static final int ERROR_NO_SERVICE_INSTALLED = 1;
public static final int ERROR_MULTIPLE_SERVICES_INSTALLED = 2;
public static final int ERROR_BIND_TIMEOUT_OR_FAILURE = 3;
- public static final int ERROR_UNABLE_TO_INITIALIZE = 4;
+ public static final int ERROR_MIDDLEWARE_NOT_YET_READY = 4;
public static final int ERROR_ALREADY_INITIALIZED = 5;
public static final int ERROR_CONCURRENT_SERVICE_LIMIT_REACHED = 6;
public static final int ERROR_MIDDLEWARE_NOT_BOUND = 7;
@@ -36,6 +36,7 @@
public static final int ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE = 15;
public static final int ERROR_UNABLE_TO_READ_SIM = 16;
public static final int ERROR_CARRIER_CHANGE_NOT_ALLOWED = 17;
+ public static final int ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT = 18;
private final int mErrorCode;
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
index b3bc814..27d9878 100644
--- a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
@@ -61,4 +61,17 @@
public void activeStreamingServicesUpdated(List<StreamingServiceInfo> services) {
// default implementation empty
}
+
+ /**
+ * Called to indicate that the middleware has been initialized and is ready.
+ *
+ * Before this method is called, calling any method on an instance of
+ * {@link android.telephony.MbmsStreamingManager} will result in an {@link MbmsException}
+ * being thrown with error code {@link MbmsException#ERROR_MIDDLEWARE_NOT_BOUND}
+ * or {@link MbmsException#ERROR_MIDDLEWARE_NOT_YET_READY}
+ */
+ @Override
+ public void middlewareReady() {
+ // default implementation empty
+ }
}
diff --git a/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java b/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
index 9842581..c4d033b 100644
--- a/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
+++ b/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
@@ -22,6 +22,7 @@
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
@@ -32,14 +33,15 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.Objects;
/**
* @hide
*/
public class MbmsTempFileProvider extends ContentProvider {
- public static final String META_DATA_USE_EXTERNAL_STORAGE = "use-external-storage";
- public static final String META_DATA_TEMP_FILE_DIRECTORY = "temp-file-path";
public static final String DEFAULT_TOP_LEVEL_TEMP_DIRECTORY = "androidMbmsTempFileRoot";
+ public static final String TEMP_FILE_ROOT_PREF_FILE_NAME = "MbmsTempFileRootPrefs";
+ public static final String TEMP_FILE_ROOT_PREF_NAME = "mbms_temp_file_root";
private String mAuthority;
private Context mContext;
@@ -114,7 +116,7 @@
// Make sure the temp file is contained in the temp file directory as configured in the
// manifest
- File tempFileDir = getEmbmsTempFileDir(context, authority);
+ File tempFileDir = getEmbmsTempFileDir(context);
if (!MbmsUtils.isContainedIn(tempFileDir, file)) {
throw new IllegalArgumentException("File " + file + " is not contained in the temp " +
"file directory, which is " + tempFileDir);
@@ -147,13 +149,17 @@
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
throw new IllegalArgumentException("Uri must have scheme content");
}
+ if (!Objects.equals(authority, uri.getAuthority())) {
+ throw new IllegalArgumentException("Uri does not have a matching authority: " +
+ authority + ", " + uri.getAuthority());
+ }
String relPath = Uri.decode(uri.getEncodedPath());
File file;
File tempFileDir;
try {
- tempFileDir = getEmbmsTempFileDir(context, authority).getCanonicalFile();
+ tempFileDir = getEmbmsTempFileDir(context).getCanonicalFile();
file = new File(tempFileDir, relPath).getCanonicalFile();
} catch (IOException e) {
throw new FileNotFoundException("Could not resolve paths");
@@ -169,25 +175,18 @@
/**
* Returns a File for the directory used to store temp files for this app
*/
- public static File getEmbmsTempFileDir(Context context, String authority) {
- Bundle metadata = getMetadata(context, authority);
- File parentDirectory;
- if (metadata.getBoolean(META_DATA_USE_EXTERNAL_STORAGE, false)) {
- parentDirectory = context.getExternalFilesDir(null);
- } else {
- parentDirectory = context.getFilesDir();
+ public static File getEmbmsTempFileDir(Context context) {
+ SharedPreferences prefs = context.getSharedPreferences(TEMP_FILE_ROOT_PREF_FILE_NAME, 0);
+ String storedTempFileRoot = prefs.getString(TEMP_FILE_ROOT_PREF_NAME, null);
+ try {
+ if (storedTempFileRoot != null) {
+ return new File(storedTempFileRoot).getCanonicalFile();
+ } else {
+ return new File(context.getFilesDir(), DEFAULT_TOP_LEVEL_TEMP_DIRECTORY)
+ .getCanonicalFile();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to canonicalize temp file root path " + e);
}
-
- String tmpFilePath = metadata.getString(META_DATA_TEMP_FILE_DIRECTORY);
- if (tmpFilePath == null) {
- tmpFilePath = DEFAULT_TOP_LEVEL_TEMP_DIRECTORY;
- }
- return new File(parentDirectory, tmpFilePath);
- }
-
- private static Bundle getMetadata(Context context, String authority) {
- final ProviderInfo info = context.getPackageManager()
- .resolveContentProvider(authority, PackageManager.GET_META_DATA);
- return info.metaData;
}
}
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index de30805..7d47275 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.content.pm.*;
import android.content.pm.ServiceInfo;
import android.telephony.MbmsDownloadManager;
@@ -46,20 +47,6 @@
}
}
- public static void waitOnLatchWithTimeout(CountDownLatch l, long timeoutMs) {
- long endTime = System.currentTimeMillis() + timeoutMs;
- while (System.currentTimeMillis() < endTime) {
- try {
- l.await(timeoutMs, TimeUnit.MILLISECONDS);
- } catch (InterruptedException e) {
- // keep waiting
- }
- if (l.getCount() <= 0) {
- return;
- }
- }
- }
-
public static ComponentName toComponentName(ComponentInfo ci) {
return new ComponentName(ci.packageName, ci.name);
}
@@ -83,4 +70,19 @@
}
return downloadServices.get(0).serviceInfo;
}
+
+ public static void startBinding(Context context, String serviceAction,
+ ServiceConnection serviceConnection) throws MbmsException {
+ Intent bindIntent = new Intent();
+ ServiceInfo mbmsServiceInfo =
+ MbmsUtils.getMiddlewareServiceInfo(context, serviceAction);
+
+ if (mbmsServiceInfo == null) {
+ throw new MbmsException(MbmsException.ERROR_NO_SERVICE_INSTALLED);
+ }
+
+ bindIntent.setComponent(MbmsUtils.toComponentName(mbmsServiceInfo));
+
+ context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
+ }
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
index 6c2b816..ff7d233 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -47,6 +47,7 @@
*/
int getFileServices(String appName, int subId, in List<String> serviceClasses);
+ int setTempFileRootDirectory(String appName, int subId, String rootDirectoryPath);
/**
* should move the params into a DownloadRequest parcelable
*/
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 505aeae..9577dd2 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -32,13 +32,19 @@
*/
public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
@Override
- public void initialize(String appName, int subId, IMbmsDownloadManagerCallback listener)
- throws RemoteException {
+ public void initialize(String appName, int subscriptionId,
+ IMbmsDownloadManagerCallback listener) throws RemoteException {
}
@Override
- public int getFileServices(String appName, int subId, List<String> serviceClasses) throws
- RemoteException {
+ public int getFileServices(String appName, int subscriptionId, List<String> serviceClasses)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int setTempFileRootDirectory(String appName, int subscriptionId,
+ String rootDirectoryPath) throws RemoteException {
return 0;
}
diff --git a/test-runner/src/android/test/DatabaseTestUtils.java b/test-runner/src/android/test/DatabaseTestUtils.java
deleted file mode 100644
index 1980d92..0000000
--- a/test-runner/src/android/test/DatabaseTestUtils.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 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.test;
-
-import android.database.sqlite.SQLiteDatabase;
-import android.database.Cursor;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A collection of utilities for writing unit tests for database code.
- * @hide pending API council approval
- */
-@Deprecated
-public class DatabaseTestUtils {
-
- /**
- * Compares the schema of two databases and asserts that they are equal.
- * @param expectedDb the db that is known to have the correct schema
- * @param db the db whose schema should be checked
- */
- public static void assertSchemaEquals(SQLiteDatabase expectedDb, SQLiteDatabase db) {
- Set<String> expectedSchema = getSchemaSet(expectedDb);
- Set<String> schema = getSchemaSet(db);
- MoreAsserts.assertEquals(expectedSchema, schema);
- }
-
- private static Set<String> getSchemaSet(SQLiteDatabase db) {
- Set<String> schemaSet = new HashSet<>();
-
- Cursor entityCursor = db.rawQuery("SELECT sql FROM sqlite_master", null);
- try {
- while (entityCursor.moveToNext()) {
- String sql = entityCursor.getString(0);
- schemaSet.add(sql);
- }
- } finally {
- entityCursor.close();
- }
- return schemaSet;
- }
-}
diff --git a/test-runner/src/android/test/InstrumentationCoreTestRunner.java b/test-runner/src/android/test/InstrumentationCoreTestRunner.java
deleted file mode 100644
index 2b05e4a..0000000
--- a/test-runner/src/android/test/InstrumentationCoreTestRunner.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2008 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.test;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.List;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestListener;
-import android.os.Bundle;
-import android.test.suitebuilder.TestMethod;
-import android.test.suitebuilder.annotation.HasAnnotation;
-import android.util.Log;
-
-/**
- * This test runner extends the default InstrumentationTestRunner. It overrides
- * the {@code onCreate(Bundle)} method and sets the system properties necessary
- * for many core tests to run. This is needed because there are some core tests
- * that need writing access to the file system. We also need to set the harness
- * Thread's context ClassLoader. Otherwise some classes and resources will not
- * be found. Finally, we add a means to free memory allocated by a TestCase
- * after its execution.
- *
- * @hide
- */
-@Deprecated
-public class InstrumentationCoreTestRunner extends InstrumentationTestRunner {
-
- /**
- * Convenience definition of our log tag.
- */
- private static final String TAG = "InstrumentationCoreTestRunner";
-
- /**
- * True if (and only if) we are running in single-test mode (as opposed to
- * batch mode).
- */
- private boolean singleTest = false;
-
- @Override
- public void onCreate(Bundle arguments) {
- // We might want to move this to /sdcard, if is is mounted/writable.
- File cacheDir = getTargetContext().getCacheDir();
-
- // Set some properties that the core tests absolutely need.
- System.setProperty("user.language", "en");
- System.setProperty("user.region", "US");
-
- System.setProperty("java.home", cacheDir.getAbsolutePath());
- System.setProperty("user.home", cacheDir.getAbsolutePath());
- System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-
- if (arguments != null) {
- String classArg = arguments.getString(ARGUMENT_TEST_CLASS);
- singleTest = classArg != null && classArg.contains("#");
- }
-
- super.onCreate(arguments);
- }
-
- @Override
- protected AndroidTestRunner getAndroidTestRunner() {
- AndroidTestRunner runner = super.getAndroidTestRunner();
-
- runner.addTestListener(new TestListener() {
- /**
- * The last test class we executed code from.
- */
- private Class<?> lastClass;
-
- /**
- * The minimum time we expect a test to take.
- */
- private static final int MINIMUM_TIME = 100;
-
- /**
- * The start time of our current test in System.currentTimeMillis().
- */
- private long startTime;
-
- public void startTest(Test test) {
- if (test.getClass() != lastClass) {
- lastClass = test.getClass();
- printMemory(test.getClass());
- }
-
- Thread.currentThread().setContextClassLoader(
- test.getClass().getClassLoader());
-
- startTime = System.currentTimeMillis();
- }
-
- public void endTest(Test test) {
- if (test instanceof TestCase) {
- cleanup((TestCase)test);
-
- /*
- * Make sure all tests take at least MINIMUM_TIME to
- * complete. If they don't, we wait a bit. The Cupcake
- * Binder can't handle too many operations in a very
- * short time, which causes headache for the CTS.
- */
- long timeTaken = System.currentTimeMillis() - startTime;
-
- if (timeTaken < MINIMUM_TIME) {
- try {
- Thread.sleep(MINIMUM_TIME - timeTaken);
- } catch (InterruptedException ignored) {
- // We don't care.
- }
- }
- }
- }
-
- public void addError(Test test, Throwable t) {
- // This space intentionally left blank.
- }
-
- public void addFailure(Test test, AssertionFailedError t) {
- // This space intentionally left blank.
- }
-
- /**
- * Dumps some memory info.
- */
- private void printMemory(Class<? extends Test> testClass) {
- Runtime runtime = Runtime.getRuntime();
-
- long total = runtime.totalMemory();
- long free = runtime.freeMemory();
- long used = total - free;
-
- Log.d(TAG, "Total memory : " + total);
- Log.d(TAG, "Used memory : " + used);
- Log.d(TAG, "Free memory : " + free);
- Log.d(TAG, "Now executing : " + testClass.getName());
- }
-
- /**
- * Nulls all non-static reference fields in the given test class.
- * This method helps us with those test classes that don't have an
- * explicit tearDown() method. Normally the garbage collector should
- * take care of everything, but since JUnit keeps references to all
- * test cases, a little help might be a good idea.
- */
- private void cleanup(TestCase test) {
- Class<?> clazz = test.getClass();
-
- while (clazz != TestCase.class) {
- Field[] fields = clazz.getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- Field f = fields[i];
- if (!f.getType().isPrimitive() &&
- !Modifier.isStatic(f.getModifiers())) {
- try {
- f.setAccessible(true);
- f.set(test, null);
- } catch (Exception ignored) {
- // Nothing we can do about it.
- }
- }
- }
-
- clazz = clazz.getSuperclass();
- }
- }
-
- });
-
- return runner;
- }
-}
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index 9bd4c96..6e5492b 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -178,13 +178,13 @@
public class InstrumentationTestRunner extends Instrumentation implements TestSuiteProvider {
/** @hide */
- public static final String ARGUMENT_TEST_CLASS = "class";
+ static final String ARGUMENT_TEST_CLASS = "class";
/** @hide */
- public static final String ARGUMENT_TEST_PACKAGE = "package";
+ private static final String ARGUMENT_TEST_PACKAGE = "package";
/** @hide */
- public static final String ARGUMENT_TEST_SIZE_PREDICATE = "size";
+ private static final String ARGUMENT_TEST_SIZE_PREDICATE = "size";
/** @hide */
- public static final String ARGUMENT_DELAY_MSEC = "delay_msec";
+ static final String ARGUMENT_DELAY_MSEC = "delay_msec";
private static final String SMALL_SUITE = "small";
private static final String MEDIUM_SUITE = "medium";
@@ -208,7 +208,7 @@
*/
private static final float MEDIUM_SUITE_MAX_RUNTIME = 1000;
- /**
+ /*
* The following keys are used in the status bundle to provide structured reports to
* an IInstrumentationWatcher.
*/
@@ -476,7 +476,7 @@
/**
* Returns the test predicate object, corresponding to the annotation class value provided via
- * the {@link ARGUMENT_ANNOTATION} argument.
+ * the {@link #ARGUMENT_ANNOTATION} argument.
*
* @return the predicate or <code>null</code>
*/
@@ -490,7 +490,7 @@
/**
* Returns the negative test predicate object, corresponding to the annotation class value
- * provided via the {@link ARGUMENT_NOT_ANNOTATION} argument.
+ * provided via the {@link #ARGUMENT_NOT_ANNOTATION} argument.
*
* @return the predicate or <code>null</code>
*/
diff --git a/test-runner/src/android/test/InstrumentationUtils.java b/test-runner/src/android/test/InstrumentationUtils.java
deleted file mode 100644
index cc50813..0000000
--- a/test-runner/src/android/test/InstrumentationUtils.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2007 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.test;
-
-/**
- * The InstrumentationUtils class has all the utility functions needed for
- * instrumentation tests.
- *
- * {@hide} - Not currently used.
- */
-@Deprecated
-public class InstrumentationUtils {
- /**
- * An utility function that returns the menu identifier for a particular
- * menu item.
- *
- * @param cls Class object of the class that handles the menu ite,.
- * @param identifier Menu identifier.
- * @return The integer corresponding to the menu item.
- */
- public static int getMenuIdentifier(Class cls, String identifier) {
- int id = -1;
- try {
- Integer field = (Integer)cls.getDeclaredField(identifier).get(cls);
- id = field.intValue();
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- return id;
- }
-
-}
diff --git a/test-runner/src/android/test/suitebuilder/InstrumentationTestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/InstrumentationTestSuiteBuilder.java
deleted file mode 100644
index 128396e..0000000
--- a/test-runner/src/android/test/suitebuilder/InstrumentationTestSuiteBuilder.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2008 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.test.suitebuilder;
-
-/**
- * A suite builder that finds instrumentation tests.
- *
- * {@hide} Not needed for 1.0 SDK.
- */
-public class InstrumentationTestSuiteBuilder extends TestSuiteBuilder {
-
- public InstrumentationTestSuiteBuilder(Class clazz) {
- this(clazz.getName(), clazz.getClassLoader());
- }
-
-
- public InstrumentationTestSuiteBuilder(String name, ClassLoader classLoader) {
- super(name, classLoader);
- addRequirements(TestPredicates.SELECT_INSTRUMENTATION);
- }
-}
diff --git a/test-runner/src/android/test/suitebuilder/TestGrouping.java b/test-runner/src/android/test/suitebuilder/TestGrouping.java
index a2b94ff..307afb5 100644
--- a/test-runner/src/android/test/suitebuilder/TestGrouping.java
+++ b/test-runner/src/android/test/suitebuilder/TestGrouping.java
@@ -44,23 +44,23 @@
*
* {@hide} Not needed for 1.0 SDK.
*/
-public class TestGrouping {
+class TestGrouping {
private static final String LOG_TAG = "TestGrouping";
- SortedSet<Class<? extends TestCase>> testCaseClasses;
+ private final SortedSet<Class<? extends TestCase>> testCaseClasses;
- public static final Comparator<Class<? extends TestCase>> SORT_BY_SIMPLE_NAME
+ static final Comparator<Class<? extends TestCase>> SORT_BY_SIMPLE_NAME
= new SortBySimpleName();
- public static final Comparator<Class<? extends TestCase>> SORT_BY_FULLY_QUALIFIED_NAME
+ static final Comparator<Class<? extends TestCase>> SORT_BY_FULLY_QUALIFIED_NAME
= new SortByFullyQualifiedName();
- protected String firstIncludedPackage = null;
- private ClassLoader classLoader;
+ private final ClassLoader classLoader;
- public TestGrouping(Comparator<Class<? extends TestCase>> comparator) {
+ TestGrouping(Comparator<Class<? extends TestCase>> comparator, ClassLoader classLoader) {
testCaseClasses = new TreeSet<Class<? extends TestCase>>(comparator);
+ this.classLoader = classLoader;
}
/**
@@ -77,15 +77,11 @@
return testMethods;
}
- protected List<Method> getTestMethods(Class<? extends TestCase> testCaseClass) {
+ private List<Method> getTestMethods(Class<? extends TestCase> testCaseClass) {
List<Method> methods = Arrays.asList(testCaseClass.getMethods());
return select(methods, new TestMethodPredicate());
}
- SortedSet<Class<? extends TestCase>> getTestCaseClasses() {
- return testCaseClasses;
- }
-
public boolean equals(Object o) {
if (this == o) {
return true;
@@ -110,9 +106,8 @@
* or in a sub-package.
*
* @param packageNames Names of packages to add.
- * @return The {@link TestGrouping} for method chaining.
*/
- public TestGrouping addPackagesRecursive(String... packageNames) {
+ void addPackagesRecursive(String... packageNames) {
for (String packageName : packageNames) {
List<Class<? extends TestCase>> addedClasses = testCaseClassesInPackage(packageName);
if (addedClasses.isEmpty()) {
@@ -120,11 +115,7 @@
+ "' could not be found or has no tests");
}
testCaseClasses.addAll(addedClasses);
- if (firstIncludedPackage == null) {
- firstIncludedPackage = packageName;
- }
}
- return this;
}
/**
@@ -132,21 +123,11 @@
* specified.
*
* @param packageNames Names of packages to remove.
- * @return The {@link TestGrouping} for method chaining.
*/
- public TestGrouping removePackagesRecursive(String... packageNames) {
+ void removePackagesRecursive(String... packageNames) {
for (String packageName : packageNames) {
testCaseClasses.removeAll(testCaseClassesInPackage(packageName));
}
- return this;
- }
-
- /**
- * @return The first package name passed to {@link #addPackagesRecursive(String[])}, or null
- * if that method was never called.
- */
- public String getFirstIncludedPackage() {
- return firstIncludedPackage;
}
private List<Class<? extends TestCase>> testCaseClassesInPackage(String packageName) {
@@ -176,10 +157,6 @@
return selectedItems;
}
- public void setClassLoader(ClassLoader classLoader) {
- this.classLoader = classLoader;
- }
-
/**
* Sort classes by their simple names (i.e. without the package prefix), using
* their packages to sort classes with the same name.
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index cf6936b..6158e0c 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -44,8 +44,7 @@
@Deprecated
public class TestSuiteBuilder {
- private Context context;
- private final TestGrouping testGrouping = new TestGrouping(SORT_BY_FULLY_QUALIFIED_NAME);
+ private final TestGrouping testGrouping;
private final Set<Predicate<TestMethod>> predicates = new HashSet<Predicate<TestMethod>>();
private List<TestCase> testCases;
private TestSuite rootSuite;
@@ -67,7 +66,7 @@
public TestSuiteBuilder(String name, ClassLoader classLoader) {
this.suiteName = name;
- this.testGrouping.setClassLoader(classLoader);
+ this.testGrouping = new TestGrouping(SORT_BY_FULLY_QUALIFIED_NAME, classLoader);
this.testCases = new ArrayList<>();
addRequirements(REJECT_SUPPRESSED);
}
@@ -244,15 +243,6 @@
}
}
- /**
- * @return the test package that represents the packages that were included for our test suite.
- *
- * {@hide} Not needed for 1.0 SDK.
- */
- protected TestGrouping getTestGrouping() {
- return testGrouping;
- }
-
private boolean satisfiesAllPredicates(TestMethod test) {
for (Predicate<TestMethod> predicate : predicates) {
if (!predicate.apply(test)) {
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
index 68fd662..cc9b01d 100644
--- a/test-runner/tests/Android.mk
+++ b/test-runner/tests/Android.mk
@@ -16,6 +16,13 @@
include $(CLEAR_VARS)
# We only want this apk build for tests.
+#
+# Run the tests using the following commands:
+# adb -r install ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
+# adb shell am instrument \
+ -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \
+ -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner
+#
LOCAL_MODULE_TAGS := tests
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/test-runner/tests/src/android/test/TestCaseUtilTest.java b/test-runner/tests/src/android/test/TestCaseUtilTest.java
index bc6fa92..9d12eaf 100644
--- a/test-runner/tests/src/android/test/TestCaseUtilTest.java
+++ b/test-runner/tests/src/android/test/TestCaseUtilTest.java
@@ -29,9 +29,7 @@
List<String> testCaseNames = TestCaseUtil.getTestCaseNames(testSuite, false);
- assertEquals(2, testCaseNames.size());
- assertTrue(testCaseNames.get(0).endsWith("OneTestTestCase"));
- assertTrue(testCaseNames.get(1).endsWith("OneTestTestSuite"));
+ assertEquals(0, testCaseNames.size());
}
public void testGetTestCaseNamesForTestCaseWithSuiteMethod() throws Exception {
diff --git a/test-runner/tests/src/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java b/test-runner/tests/src/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
deleted file mode 100644
index 1872803..0000000
--- a/test-runner/tests/src/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2008 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.test.suitebuilder;
-
-import static android.test.suitebuilder.ListTestCaseNames.getTestCaseNames;
-import android.test.suitebuilder.examples.OuterTest;
-import android.test.suitebuilder.examples.instrumentation.InstrumentationTest;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestListener;
-import junit.framework.TestResult;
-import junit.framework.TestSuite;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-public class InstrumentationTestSuiteBuilderTest extends TestCase {
-
- private InstrumentationTestSuiteBuilder instrumentationTestSuiteBuilder;
-
- protected void setUp() throws Exception {
- super.setUp();
- instrumentationTestSuiteBuilder = new InstrumentationTestSuiteBuilder(getClass());
- }
-
- public void testShouldIncludeIntrumentationTests() throws Exception {
- instrumentationTestSuiteBuilder.includePackages(packageFor(InstrumentationTest.class));
-
- SuiteExecutionRecorder recorder = runSuite(instrumentationTestSuiteBuilder);
-
- assertEquals(1, recorder.testsSeen.size());
- assertTrue(recorder.saw("InstrumentationTest.testInstrumentation"));
- }
-
- public void testShouldOnlyIncludeIntrumentationTests() throws Exception {
- TestSuite testSuite = new OuterTest()
- .buildTestsUnderHereWith(instrumentationTestSuiteBuilder);
- List<String> testCaseNames = getTestCaseNames(testSuite);
- assertEquals(1, testCaseNames.size());
- assertEquals("testInstrumentation", testCaseNames.get(0));
- }
-
- private static String packageFor(Class clazz) {
- String className = clazz.getName();
- return className.substring(0, className.lastIndexOf('.'));
- }
-
- private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) {
- TestSuite suite = builder.build();
- SuiteExecutionRecorder recorder = new SuiteExecutionRecorder();
- TestResult result = new TestResult();
- result.addListener(recorder);
- suite.run(result);
- return recorder;
- }
-
- private class SuiteExecutionRecorder implements TestListener {
-
- private Set<String> failures = new HashSet<String>();
- private Set<String> errors = new HashSet<String>();
- private Set<String> testsSeen = new HashSet<String>();
-
- public void addError(Test test, Throwable t) {
- errors.add(testName(test));
- }
-
- public void addFailure(Test test, AssertionFailedError t) {
- failures.add(testName(test));
- }
-
- public void endTest(Test test) {
- }
-
- public void startTest(Test test) {
- testsSeen.add(testName(test));
- }
-
- public boolean saw(String testName) {
- return testsSeen.contains(testName);
- }
-
- public boolean failed(String testName) {
- return failures.contains(testName);
- }
-
- public boolean errored(String testName) {
- return errors.contains(testName);
- }
-
- public boolean passed(String testName) {
- return saw(testName) && !failed(testName) && !errored(testName);
- }
-
- private String testName(Test test) {
- TestCase testCase = (TestCase) test;
- return testCase.getClass().getSimpleName() + "." + testCase.getName();
- }
- }
-}
diff --git a/test-runner/tests/src/android/test/suitebuilder/TestGroupingTest.java b/test-runner/tests/src/android/test/suitebuilder/TestGroupingTest.java
index f4477d1..972bfb4 100644
--- a/test-runner/tests/src/android/test/suitebuilder/TestGroupingTest.java
+++ b/test-runner/tests/src/android/test/suitebuilder/TestGroupingTest.java
@@ -30,7 +30,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mGrouping = new TestGrouping(TestGrouping.SORT_BY_SIMPLE_NAME);
+ mGrouping = new TestGrouping(TestGrouping.SORT_BY_SIMPLE_NAME, getClass().getClassLoader());
}
/**
diff --git a/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java b/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java
index 293c813..a2e51a1 100644
--- a/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java
+++ b/test-runner/tests/src/android/test/suitebuilder/TestSuiteBuilderTest.java
@@ -135,10 +135,23 @@
TestSuite testSuite = new OuterTest().buildTestsUnderHereRecursively();
assertContentsInOrder(getTestCaseNames(testSuite),
- "testOuter", "testErrorOne", "testErrorTwo", "testFailOne", "testFailTwo",
- "testInstrumentation", "testLevel1", "testLevel2", "testAnotherOne",
- "testSimpleOne", "testSimpleTwo", "testNonSmoke", "testSmoke", "testSubclass",
- "testSuperclass", "testUnSuppressedMethod");
+ "testOuter",
+ "testPublicConstructor",
+ "testErrorOne",
+ "testErrorTwo",
+ "testFailOne",
+ "testFailTwo",
+ "testInstrumentation",
+ "testLevel1",
+ "testLevel2",
+ "testAnotherOne",
+ "testSimpleOne",
+ "testSimpleTwo",
+ "testNonSmoke",
+ "testSmoke",
+ "testSubclass",
+ "testSuperclass",
+ "testUnSuppressedMethod");
}
private void assertContentsInOrder(List<String> actual, String... source) {
diff --git a/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java
index f1f6113..ddf5dd1 100644
--- a/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java
+++ b/test-runner/tests/src/android/test/suitebuilder/examples/error/ErrorTest.java
@@ -18,6 +18,7 @@
import junit.framework.TestCase;
+@RunAsPartOfSeparateTest
public class ErrorTest extends TestCase {
public void testErrorOne() throws Exception {
diff --git a/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java
index 428fd23..0170b2f 100644
--- a/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java
+++ b/test-runner/tests/src/android/test/suitebuilder/examples/error/FailingTest.java
@@ -18,6 +18,7 @@
import junit.framework.TestCase;
+@RunAsPartOfSeparateTest
public class FailingTest extends TestCase {
public void testFailOne() throws Exception {
diff --git a/test-runner/tests/src/android/test/suitebuilder/examples/error/RunAsPartOfSeparateTest.java b/test-runner/tests/src/android/test/suitebuilder/examples/error/RunAsPartOfSeparateTest.java
new file mode 100644
index 0000000..2b3a252
--- /dev/null
+++ b/test-runner/tests/src/android/test/suitebuilder/examples/error/RunAsPartOfSeparateTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.test.suitebuilder.examples.error;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that marks tests that should only be run as part of a separate test and not on their
+ * own.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface RunAsPartOfSeparateTest {
+}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index be0924a..5b4e901 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -264,13 +264,16 @@
mIntents.remove(bcast);
}
- public void workingLocalOnlyHotspot(boolean enrichedApBroadcast) throws Exception {
+ public void workingLocalOnlyHotspot(
+ boolean withInterfaceStateChanged, boolean enrichedApBroadcast) throws Exception {
when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
// hotspot mode is to be started.
- mTethering.interfaceStatusChanged(mTestIfname, true);
+ if (withInterfaceStateChanged) {
+ mTethering.interfaceStatusChanged(mTestIfname, true);
+ }
if (enrichedApBroadcast) {
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, mTestIfname, IFACE_IP_MODE_LOCAL_ONLY);
} else {
@@ -320,12 +323,17 @@
@Test
public void workingLocalOnlyHotspotLegacyApBroadcast() throws Exception {
- workingLocalOnlyHotspot(false);
+ workingLocalOnlyHotspot(true, false);
}
@Test
public void workingLocalOnlyHotspotEnrichedApBroadcast() throws Exception {
- workingLocalOnlyHotspot(true);
+ workingLocalOnlyHotspot(true, true);
+ }
+
+ @Test
+ public void workingLocalOnlyHotspotEnrichedApBroadcastWithoutInterfaceUp() throws Exception {
+ workingLocalOnlyHotspot(false, true);
}
public void workingWifiTethering(boolean enrichedApBroadcast) throws Exception {
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 4d340d1..1ddaf66 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -62,7 +62,8 @@
@Mock private OffloadHardwareInterface mHardware;
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
- final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class);
+ private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
+ ArgumentCaptor.forClass(ArrayList.class);
private MockContentResolver mContentResolver;
@Before public void setUp() throws Exception {
@@ -155,8 +156,7 @@
lp.setInterfaceName(testIfName);
offload.setUpstreamLinkProperties(lp);
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
- eq(testIfName), eq(null), eq(null), mStringArrayCaptor.capture());
- assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ eq(testIfName), eq(null), eq(null), eq(null));
inOrder.verifyNoMoreInteractions();
final String ipv4Addr = "192.0.2.5";
@@ -164,16 +164,14 @@
lp.addLinkAddress(new LinkAddress(linkAddr));
offload.setUpstreamLinkProperties(lp);
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
- eq(testIfName), eq(ipv4Addr), eq(null), mStringArrayCaptor.capture());
- assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ eq(testIfName), eq(ipv4Addr), eq(null), eq(null));
inOrder.verifyNoMoreInteractions();
final String ipv4Gateway = "192.0.2.1";
lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway)));
offload.setUpstreamLinkProperties(lp);
inOrder.verify(mHardware, times(1)).setUpstreamParameters(
- eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), mStringArrayCaptor.capture());
- assertTrue(mStringArrayCaptor.getValue().isEmpty());
+ eq(testIfName), eq(ipv4Addr), eq(ipv4Gateway), eq(null));
inOrder.verifyNoMoreInteractions();
final String ipv6Gw1 = "fe80::cafe";
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index ce419a5..db5373a 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity.tethering;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@@ -40,17 +42,23 @@
import android.net.ConnectivityManager;
import android.net.INetworkStatsService;
import android.net.InterfaceConfiguration;
+import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import android.text.TextUtils;
+
+import java.net.Inet4Address;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -69,6 +77,8 @@
@Mock private SharedLog mSharedLog;
private final TestLooper mLooper = new TestLooper();
+ private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
+ ArgumentCaptor.forClass(LinkProperties.class);
private TetherInterfaceStateMachine mTestedSm;
private void initStateMachine(int interfaceType) throws Exception {
@@ -77,7 +87,7 @@
mNMService, mStatsService, mTetherHelper);
mTestedSm.start();
// Starting the state machine always puts us in a consistent state and notifies
- // the test of the world that we've changed from an unknown to available state.
+ // the rest of the world that we've changed from an unknown to available state.
mLooper.dispatchAll();
reset(mNMService, mStatsService, mTetherHelper);
when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
@@ -181,7 +191,8 @@
inOrder.verify(mTetherHelper).updateInterfaceState(
mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
inOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), any(LinkProperties.class));
+ eq(mTestedSm), mLinkPropertiesCaptor.capture());
+ assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
}
@@ -281,7 +292,8 @@
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), any(LinkProperties.class));
+ eq(mTestedSm), mLinkPropertiesCaptor.capture());
+ assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
}
}
@@ -298,7 +310,8 @@
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), any(LinkProperties.class));
+ eq(mTestedSm), mLinkPropertiesCaptor.capture());
+ assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
}
@Test
@@ -313,7 +326,8 @@
usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
- eq(mTestedSm), any(LinkProperties.class));
+ eq(mTestedSm), mLinkPropertiesCaptor.capture());
+ assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
}
@Test
@@ -360,4 +374,28 @@
upstreamIface);
mLooper.dispatchAll();
}
+
+ private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) {
+ // Find the first IPv4 LinkAddress.
+ LinkAddress addr4 = null;
+ for (LinkAddress addr : lp.getLinkAddresses()) {
+ if (!(addr.getAddress() instanceof Inet4Address)) continue;
+ addr4 = addr;
+ break;
+ }
+ assertTrue("missing IPv4 address", addr4 != null);
+
+ // Assert the presence of the associated directly connected route.
+ final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName());
+ assertTrue("missing directly connected route: '" + directlyConnected.toString() + "'",
+ lp.getRoutes().contains(directlyConnected));
+ }
+
+ private void assertNoAddressesNorRoutes(LinkProperties lp) {
+ assertTrue(lp.getLinkAddresses().isEmpty());
+ assertTrue(lp.getRoutes().isEmpty());
+ // We also check that interface name is non-empty, because we should
+ // never see an empty interface name in any LinkProperties update.
+ assertFalse(TextUtils.isEmpty(lp.getInterfaceName()));
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 27be135..b68f203 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -16,6 +16,7 @@
package com.android.server.connectivity.tethering;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
@@ -38,6 +39,8 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
+import java.util.Iterator;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -134,4 +137,61 @@
assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI));
}
+
+ @Test
+ public void testNoDefinedUpstreamTypesAddsEthernet() {
+ when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+ .thenReturn(new int[]{});
+ mHasTelephonyManager = false;
+ when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
+
+ final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
+ // The following is because the code always adds some kind of mobile
+ // upstream, be it DUN or, in this case where we use DUN_UNSPECIFIED,
+ // both vanilla and hipri mobile types.
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_MOBILE, upstreamIterator.next().intValue());
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue());
+ assertFalse(upstreamIterator.hasNext());
+ }
+
+ @Test
+ public void testDefinedUpstreamTypesSansEthernetAddsEthernet() {
+ when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+ .thenReturn(new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI});
+ mHasTelephonyManager = false;
+ when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
+
+ final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_WIFI, upstreamIterator.next().intValue());
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue());
+ assertFalse(upstreamIterator.hasNext());
+ }
+
+ @Test
+ public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() {
+ when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
+ .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI});
+ mHasTelephonyManager = false;
+ when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
+
+ final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_WIFI, upstreamIterator.next().intValue());
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
+ assertTrue(upstreamIterator.hasNext());
+ assertEquals(TYPE_MOBILE_HIPRI, upstreamIterator.next().intValue());
+ assertFalse(upstreamIterator.hasNext());
+ }
}
diff --git a/tools/locked_region_code_injection/Android.mk b/tools/locked_region_code_injection/Android.mk
new file mode 100644
index 0000000..0aed0ce
--- /dev/null
+++ b/tools/locked_region_code_injection/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_JAR_MANIFEST := manifest.txt
+LOCAL_MODULE := lockedregioncodeinjection
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ asm-5.2 \
+ asm-commons-5.2 \
+ asm-tree-5.2 \
+ asm-analysis-5.2
+
+
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/locked_region_code_injection/manifest.txt b/tools/locked_region_code_injection/manifest.txt
new file mode 100644
index 0000000..4b9de00
--- /dev/null
+++ b/tools/locked_region_code_injection/manifest.txt
@@ -0,0 +1 @@
+Main-Class: lockedregioncodeinjection.Main
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java
new file mode 100644
index 0000000..9374f23
--- /dev/null
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockFindingClassVisitor.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package lockedregioncodeinjection;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.TryCatchBlockSorter;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.InsnList;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TryCatchBlockNode;
+import org.objectweb.asm.tree.analysis.Analyzer;
+import org.objectweb.asm.tree.analysis.AnalyzerException;
+import org.objectweb.asm.tree.analysis.BasicValue;
+import org.objectweb.asm.tree.analysis.Frame;
+
+/**
+ * This visitor does two things:
+ *
+ * 1. Finds all the MONITOR_ENTER / MONITOR_EXIT in the byte code and insert the corresponding pre
+ * and post methods calls should it matches one of the given target type in the Configuration.
+ *
+ * 2. Find all methods that are synchronized and insert pre method calls in the beginning and post
+ * method calls just before all return instructions.
+ */
+class LockFindingClassVisitor extends ClassVisitor {
+ private String className = null;
+ private final List<LockTarget> targets;
+
+ public LockFindingClassVisitor(List<LockTarget> targets, ClassVisitor chain) {
+ super(Utils.ASM_VERSION, chain);
+ this.targets = targets;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ assert this.className != null;
+ MethodNode mn = new TryCatchBlockSorter(null, access, name, desc, signature, exceptions);
+ MethodVisitor chain = super.visitMethod(access, name, desc, signature, exceptions);
+ return new LockFindingMethodVisitor(this.className, mn, chain);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ this.className = name;
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ class LockFindingMethodVisitor extends MethodVisitor {
+ private String owner;
+ private MethodVisitor chain;
+
+ public LockFindingMethodVisitor(String owner, MethodNode mn, MethodVisitor chain) {
+ super(Opcodes.ASM5, mn);
+ assert owner != null;
+ this.owner = owner;
+ this.chain = chain;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void visitEnd() {
+ MethodNode mn = (MethodNode) mv;
+
+ Analyzer a = new Analyzer(new LockTargetStateAnalysis(targets));
+
+ LockTarget ownerMonitor = null;
+ if ((mn.access & Opcodes.ACC_SYNCHRONIZED) != 0) {
+ for (LockTarget t : targets) {
+ if (t.getTargetDesc().equals("L" + owner + ";")) {
+ ownerMonitor = t;
+ }
+ }
+ }
+
+ try {
+ a.analyze(owner, mn);
+ } catch (AnalyzerException e) {
+ e.printStackTrace();
+ }
+ InsnList instructions = mn.instructions;
+
+ Frame[] frames = a.getFrames();
+ List<Frame> frameMap = new LinkedList<>();
+ frameMap.addAll(Arrays.asList(frames));
+
+ List<List<TryCatchBlockNode>> handlersMap = new LinkedList<>();
+
+ for (int i = 0; i < instructions.size(); i++) {
+ handlersMap.add(a.getHandlers(i));
+ }
+
+ if (ownerMonitor != null) {
+ AbstractInsnNode s = instructions.getFirst();
+ MethodInsnNode call = new MethodInsnNode(Opcodes.INVOKESTATIC,
+ ownerMonitor.getPreOwner(), ownerMonitor.getPreMethod(), "()V", false);
+ insertMethodCallBefore(mn, frameMap, handlersMap, s, 0, call);
+ }
+
+ for (int i = 0; i < instructions.size(); i++) {
+ AbstractInsnNode s = instructions.get(i);
+
+ if (s.getOpcode() == Opcodes.MONITORENTER) {
+ Frame f = frameMap.get(i);
+ BasicValue operand = (BasicValue) f.getStack(f.getStackSize() - 1);
+ if (operand instanceof LockTargetState) {
+ LockTargetState state = (LockTargetState) operand;
+ for (int j = 0; j < state.getTargets().size(); j++) {
+ LockTarget target = state.getTargets().get(j);
+ MethodInsnNode call = new MethodInsnNode(Opcodes.INVOKESTATIC,
+ target.getPreOwner(), target.getPreMethod(), "()V", false);
+ insertMethodCallAfter(mn, frameMap, handlersMap, s, i, call);
+ }
+ }
+ }
+
+ if (s.getOpcode() == Opcodes.MONITOREXIT) {
+ Frame f = frameMap.get(i);
+ BasicValue operand = (BasicValue) f.getStack(f.getStackSize() - 1);
+ if (operand instanceof LockTargetState) {
+ LockTargetState state = (LockTargetState) operand;
+ for (int j = 0; j < state.getTargets().size(); j++) {
+ LockTarget target = state.getTargets().get(j);
+ MethodInsnNode call = new MethodInsnNode(Opcodes.INVOKESTATIC,
+ target.getPostOwner(), target.getPostMethod(), "()V", false);
+ insertMethodCallAfter(mn, frameMap, handlersMap, s, i, call);
+ }
+ }
+ }
+
+ if (ownerMonitor != null && (s.getOpcode() == Opcodes.RETURN
+ || s.getOpcode() == Opcodes.ARETURN || s.getOpcode() == Opcodes.DRETURN
+ || s.getOpcode() == Opcodes.FRETURN || s.getOpcode() == Opcodes.IRETURN)) {
+ MethodInsnNode call =
+ new MethodInsnNode(Opcodes.INVOKESTATIC, ownerMonitor.getPostOwner(),
+ ownerMonitor.getPostMethod(), "()V", false);
+ insertMethodCallBefore(mn, frameMap, handlersMap, s, i, call);
+ i++; // Skip ahead. Otherwise, we will revisit this instruction again.
+ }
+ }
+ super.visitEnd();
+ mn.accept(chain);
+ }
+ }
+
+ public static void insertMethodCallBefore(MethodNode mn, List<Frame> frameMap,
+ List<List<TryCatchBlockNode>> handlersMap, AbstractInsnNode node, int index,
+ MethodInsnNode call) {
+ List<TryCatchBlockNode> handlers = handlersMap.get(index);
+ InsnList instructions = mn.instructions;
+ LabelNode end = new LabelNode();
+ instructions.insert(node, end);
+ frameMap.add(index, null);
+ handlersMap.add(index, null);
+ instructions.insertBefore(node, call);
+ frameMap.add(index, null);
+ handlersMap.add(index, null);
+
+ LabelNode start = new LabelNode();
+ instructions.insert(node, start);
+ frameMap.add(index, null);
+ handlersMap.add(index, null);
+ updateCatchHandler(mn, handlers, start, end, handlersMap);
+ }
+
+ public static void insertMethodCallAfter(MethodNode mn, List<Frame> frameMap,
+ List<List<TryCatchBlockNode>> handlersMap, AbstractInsnNode node, int index,
+ MethodInsnNode call) {
+ List<TryCatchBlockNode> handlers = handlersMap.get(index + 1);
+ InsnList instructions = mn.instructions;
+
+ LabelNode end = new LabelNode();
+ instructions.insert(node, end);
+ frameMap.add(index + 1, null);
+ handlersMap.add(index + 1, null);
+
+ instructions.insert(node, call);
+ frameMap.add(index + 1, null);
+ handlersMap.add(index + 1, null);
+
+ LabelNode start = new LabelNode();
+ instructions.insert(node, start);
+ frameMap.add(index + 1, null);
+ handlersMap.add(index + 1, null);
+
+ updateCatchHandler(mn, handlers, start, end, handlersMap);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void updateCatchHandler(MethodNode mn, List<TryCatchBlockNode> handlers,
+ LabelNode start, LabelNode end, List<List<TryCatchBlockNode>> handlersMap) {
+ if (handlers == null || handlers.size() == 0) {
+ return;
+ }
+
+ InsnList instructions = mn.instructions;
+ List<TryCatchBlockNode> newNodes = new ArrayList<>(handlers.size());
+ for (TryCatchBlockNode handler : handlers) {
+ if (!(instructions.indexOf(handler.start) <= instructions.indexOf(start)
+ && instructions.indexOf(end) <= instructions.indexOf(handler.end))) {
+ TryCatchBlockNode newNode =
+ new TryCatchBlockNode(start, end, handler.handler, handler.type);
+ newNodes.add(newNode);
+ for (int i = instructions.indexOf(start); i <= instructions.indexOf(end); i++) {
+ if (handlersMap.get(i) == null) {
+ handlersMap.set(i, new ArrayList<>());
+ }
+ handlersMap.get(i).add(newNode);
+ }
+ } else {
+ for (int i = instructions.indexOf(start); i <= instructions.indexOf(end); i++) {
+ if (handlersMap.get(i) == null) {
+ handlersMap.set(i, new ArrayList<>());
+ }
+ handlersMap.get(i).add(handler);
+ }
+ }
+ }
+ mn.tryCatchBlocks.addAll(0, newNodes);
+ }
+}
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTarget.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTarget.java
new file mode 100644
index 0000000..c5e59e3
--- /dev/null
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTarget.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package lockedregioncodeinjection;
+
+/**
+ * Represent a specific class that is used for synchronization. A pre and post method can be
+ * specified to by the user to be called right after monitor_enter and after monitor_exit
+ * respectively.
+ */
+public class LockTarget {
+ public static final LockTarget NO_TARGET = new LockTarget("", null, null);
+
+ private final String targetDesc;
+ private final String pre;
+ private final String post;
+
+ public LockTarget(String targetDesc, String pre, String post) {
+ this.targetDesc = targetDesc;
+ this.pre = pre;
+ this.post = post;
+ }
+
+ public String getTargetDesc() {
+ return targetDesc;
+ }
+
+ public String getPre() {
+ return pre;
+ }
+
+ public String getPreOwner() {
+ return pre.substring(0, pre.lastIndexOf('.'));
+ }
+
+ public String getPreMethod() {
+ return pre.substring(pre.lastIndexOf('.') + 1);
+ }
+
+ public String getPost() {
+ return post;
+ }
+
+ public String getPostOwner() {
+ return post.substring(0, post.lastIndexOf('.'));
+ }
+
+ public String getPostMethod() {
+ return post.substring(post.lastIndexOf('.') + 1);
+ }
+}
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTargetState.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTargetState.java
new file mode 100644
index 0000000..99d8418
--- /dev/null
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTargetState.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package lockedregioncodeinjection;
+
+import java.util.List;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.analysis.BasicValue;
+
+public class LockTargetState extends BasicValue {
+ private final List<LockTarget> lockTargets;
+
+ /**
+ * @param type
+ */
+ public LockTargetState(Type type, List<LockTarget> lockTargets) {
+ super(type);
+ this.lockTargets = lockTargets;
+ }
+
+ public List<LockTarget> getTargets() {
+ return lockTargets;
+ }
+}
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTargetStateAnalysis.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTargetStateAnalysis.java
new file mode 100644
index 0000000..1002c88
--- /dev/null
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/LockTargetStateAnalysis.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package lockedregioncodeinjection;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.analysis.AnalyzerException;
+import org.objectweb.asm.tree.analysis.BasicInterpreter;
+import org.objectweb.asm.tree.analysis.BasicValue;
+
+/**
+ * A simple dataflow analysis to determine if the operands on the stack must be one of target lock
+ * class type.
+ */
+public class LockTargetStateAnalysis extends BasicInterpreter {
+
+ private final List<LockTarget> targetLocks;
+
+ public LockTargetStateAnalysis(List<LockTarget> targetLocks) {
+ this.targetLocks = targetLocks;
+ }
+
+ @Override
+ public BasicValue naryOperation(AbstractInsnNode inst, @SuppressWarnings("rawtypes") List args)
+ throws AnalyzerException {
+ // We target the return type of any invocation.
+
+ @SuppressWarnings("unchecked")
+ BasicValue base = super.naryOperation(inst, args);
+ if (!(inst instanceof MethodInsnNode)) {
+ return base;
+ }
+
+ MethodInsnNode invoke = (MethodInsnNode) inst;
+ Type returnType = Type.getReturnType(invoke.desc);
+ if (returnType.equals(Type.VOID_TYPE)) {
+ return base;
+ }
+
+ List<LockTarget> types = new ArrayList<>();
+
+ for (LockTarget target : targetLocks) {
+ if (returnType.getDescriptor().equals(target.getTargetDesc())) {
+ types.add(target);
+ }
+ }
+
+ return new LockTargetState(base.getType(), types);
+ }
+
+ @Override
+ public BasicValue newValue(Type type) {
+ BasicValue base = super.newValue(type);
+ List<LockTarget> types = new ArrayList<>();
+
+ if (type == null) {
+ return base;
+ }
+ for (LockTarget target : targetLocks) {
+ if (type.getDescriptor().equals(target.getTargetDesc())) {
+ types.add(target);
+ }
+ }
+
+ if (types.isEmpty()) {
+ return base;
+ }
+
+ return new LockTargetState(base.getType(), types);
+ }
+
+ @Override
+ public BasicValue merge(BasicValue v1, BasicValue v2) {
+ BasicValue base = super.merge(v1, v2);
+
+ if (!(v1 instanceof LockTargetState)) {
+ return base;
+ }
+ if (!(v2 instanceof LockTargetState)) {
+ return base;
+ }
+
+ LockTargetState state1 = (LockTargetState) v1;
+ LockTargetState state2 = (LockTargetState) v2;
+
+ List<LockTarget> newList = new ArrayList<>(state1.getTargets());
+ for (LockTarget otherTarget : state2.getTargets()) {
+ if (!newList.contains(otherTarget)) {
+ newList.add(otherTarget);
+ }
+ }
+
+ return new LockTargetState(base.getType(), newList);
+ }
+}
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/Main.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/Main.java
new file mode 100644
index 0000000..edb9a49
--- /dev/null
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/Main.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package lockedregioncodeinjection;
+
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+public class Main {
+ public static void main(String[] args) throws IOException {
+ String inJar = null;
+ String outJar = null;
+
+ String legacyTargets = null;
+ String legacyPreMethods = null;
+ String legacyPostMethods = null;
+ for (int i = 0; i < args.length; i++) {
+ if ("-i".equals(args[i].trim())) {
+ i++;
+ inJar = args[i].trim();
+ } else if ("-o".equals(args[i].trim())) {
+ i++;
+ outJar = args[i].trim();
+ } else if ("--targets".equals(args[i].trim())) {
+ i++;
+ legacyTargets = args[i].trim();
+ } else if ("--pre".equals(args[i].trim())) {
+ i++;
+ legacyPreMethods = args[i].trim();
+ } else if ("--post".equals(args[i].trim())) {
+ i++;
+ legacyPostMethods = args[i].trim();
+ }
+
+ }
+
+ // TODO(acleung): Better help message than asserts.
+ assert inJar != null;
+ assert outJar != null;
+ assert legacyTargets == null || (legacyPreMethods != null && legacyPostMethods != null);
+
+ ZipFile zipSrc = new ZipFile(inJar);
+ ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outJar));
+ List<LockTarget> targets = null;
+ if (legacyTargets != null) {
+ targets = Utils.getTargetsFromLegacyJackConfig(legacyTargets, legacyPreMethods,
+ legacyPostMethods);
+ } else {
+ targets = Collections.emptyList();
+ }
+
+ Enumeration<? extends ZipEntry> srcEntries = zipSrc.entries();
+ while (srcEntries.hasMoreElements()) {
+ ZipEntry entry = srcEntries.nextElement();
+ ZipEntry newEntry = new ZipEntry(entry.getName());
+ zos.putNextEntry(newEntry);
+ BufferedInputStream bis = new BufferedInputStream(zipSrc.getInputStream(entry));
+
+ if (entry.getName().endsWith(".class")) {
+ convert(bis, zos, targets);
+ } else {
+ while (bis.available() > 0) {
+ zos.write(bis.read());
+ }
+ zos.closeEntry();
+ bis.close();
+ }
+ }
+ zos.finish();
+ zos.close();
+ zipSrc.close();
+ }
+
+ private static void convert(InputStream in, OutputStream out, List<LockTarget> targets)
+ throws IOException {
+ ClassReader cr = new ClassReader(in);
+ ClassWriter cw = new ClassWriter(0);
+ LockFindingClassVisitor cv = new LockFindingClassVisitor(targets, cw);
+ cr.accept(cv, 0);
+ byte[] data = cw.toByteArray();
+ out.write(data);
+ }
+}
diff --git a/tools/locked_region_code_injection/src/lockedregioncodeinjection/Utils.java b/tools/locked_region_code_injection/src/lockedregioncodeinjection/Utils.java
new file mode 100644
index 0000000..d2a2e7b
--- /dev/null
+++ b/tools/locked_region_code_injection/src/lockedregioncodeinjection/Utils.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package lockedregioncodeinjection;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.objectweb.asm.Opcodes;
+
+public class Utils {
+
+ public static final int ASM_VERSION = Opcodes.ASM5;
+
+ /**
+ * Reads a comma separated configuration similar to the Jack definition.
+ */
+ public static List<LockTarget> getTargetsFromLegacyJackConfig(String classList,
+ String requestList, String resetList) {
+
+ String[] classes = classList.split(",");
+ String[] requests = requestList.split(",");
+ String[] resets = resetList.split(",");
+
+ int total = classes.length;
+ assert requests.length == total;
+ assert resets.length == total;
+
+ List<LockTarget> config = new ArrayList<LockTarget>();
+
+ for (int i = 0; i < total; i++) {
+ config.add(new LockTarget(classes[i], requests[i], resets[i]));
+ }
+
+ return config;
+ }
+}
diff --git a/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java
new file mode 100644
index 0000000..1d4f2d4
--- /dev/null
+++ b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestMain.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package lockedregioncodeinjection;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * To run the unit tests:
+ *
+ * <pre>
+ * <code>
+ * set -x
+ *
+ * # Clean
+ * rm -fr out/*
+ *
+ * # Make booster
+ * javac -cp lib/asm-all-5.2.jar src/*/*.java -d out/
+ * pushd out
+ * jar cfe lockedregioncodeinjection.jar lockedregioncodeinjection.Main */*.class
+ * popd
+ *
+ * # Make unit tests.
+ * javac -cp lib/junit-4.12.jar test/*/*.java -d out/
+ *
+ * pushd out
+ * jar cfe test_input.jar lockedregioncodeinjection.Test */*.class
+ * popd
+ *
+ * # Run tool on unit tests.
+ * java -ea -cp lib/asm-all-5.2.jar:out/lockedregioncodeinjection.jar \
+ * lockedregioncodeinjection.Main \
+ * -i out/test_input.jar -o out/test_output.jar \
+ * --targets 'Llockedregioncodeinjection/TestTarget;' \
+ * --pre 'lockedregioncodeinjection/TestTarget.boost' \
+ * --post 'lockedregioncodeinjection/TestTarget.unboost'
+ *
+ * # Run unit tests.
+ * java -ea -cp lib/hamcrest-core-1.3.jar:lib/junit-4.12.jar:out/test_output.jar \
+ * org.junit.runner.JUnitCore lockedregioncodeinjection.TestMain
+ * </code>
+ * </pre>
+ */
+public class TestMain {
+ @Test
+ public void testSimpleSynchronizedBlock() {
+ TestTarget.resetCount();
+ TestTarget t = new TestTarget();
+
+ Assert.assertEquals(TestTarget.boostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+
+ synchronized (t) {
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+ TestTarget.invoke();
+ }
+
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 1);
+ Assert.assertEquals(TestTarget.invokeCount, 1);
+ }
+
+ @Test
+ public void testSimpleSynchronizedMethod() {
+ TestTarget.resetCount();
+ TestTarget t = new TestTarget();
+
+ Assert.assertEquals(TestTarget.boostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+
+ t.synchronizedCall();
+
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 1);
+ Assert.assertEquals(TestTarget.invokeCount, 1);
+ }
+
+ @Test
+ public void testSimpleSynchronizedMethod2() {
+ TestTarget.resetCount();
+ TestTarget t = new TestTarget();
+
+ Assert.assertEquals(TestTarget.boostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+
+ t.synchronizedCallReturnInt();
+
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 1);
+ Assert.assertEquals(TestTarget.invokeCount, 1);
+ }
+
+ @Test
+ public void testSimpleSynchronizedMethod3() {
+ TestTarget.resetCount();
+ TestTarget t = new TestTarget();
+
+ Assert.assertEquals(TestTarget.boostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+
+ t.synchronizedCallReturnObject();
+
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 1);
+ Assert.assertEquals(TestTarget.invokeCount, 1);
+ }
+
+ @SuppressWarnings("unused")
+ @Test
+ public void testCaughtException() {
+ TestTarget.resetCount();
+ TestTarget t = new TestTarget();
+ boolean caughtException = false;
+
+ Assert.assertEquals(TestTarget.boostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+
+ try {
+ synchronized (t) {
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+ if (true) {
+ throw new RuntimeException();
+ }
+ TestTarget.invoke();
+ }
+ } catch (Throwable e) {
+ caughtException = true;
+ }
+
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 1);
+ Assert.assertEquals(TestTarget.invokeCount, 0); // Not called
+ Assert.assertTrue(caughtException);
+ }
+
+ @SuppressWarnings("unused")
+ private void testUncaughtException() {
+ TestTarget t = new TestTarget();
+ synchronized (t) {
+ if (true) {
+ throw new RuntimeException();
+ }
+ TestTarget.invoke();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @Test
+ public void testHandledFinally() {
+ TestTarget.resetCount();
+ try {
+ testUncaughtException();
+ } catch (Throwable t) {
+
+ }
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 1);
+ Assert.assertEquals(TestTarget.invokeCount, 0); // Not called
+ }
+
+ @Test
+ public void testNestedSynchronizedBlock() {
+ TestTarget.resetCount();
+ TestTarget t = new TestTarget();
+
+ Assert.assertEquals(TestTarget.boostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+
+ synchronized (t) {
+ synchronized (t) {
+ synchronized (t) {
+ synchronized (t) {
+ synchronized (t) {
+ synchronized (t) {
+ Assert.assertEquals(TestTarget.boostCount, 6);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+ TestTarget.invoke();
+ }
+ Assert.assertEquals(TestTarget.unboostCount, 1);
+ }
+ Assert.assertEquals(TestTarget.unboostCount, 2);
+ }
+ Assert.assertEquals(TestTarget.unboostCount, 3);
+ }
+ Assert.assertEquals(TestTarget.unboostCount, 4);
+ }
+ Assert.assertEquals(TestTarget.unboostCount, 5);
+ }
+
+ Assert.assertEquals(TestTarget.boostCount, 6);
+ Assert.assertEquals(TestTarget.unboostCount, 6);
+ Assert.assertEquals(TestTarget.invokeCount, 1);
+ }
+
+ @Test
+ public void testMethodWithControlFlow() {
+ TestTarget.resetCount();
+ TestTarget t = new TestTarget();
+
+ Assert.assertEquals(TestTarget.boostCount, 0);
+ Assert.assertEquals(TestTarget.unboostCount, 0);
+
+ if ((t.hashCode() + " ").contains("1")) {
+ t.synchronizedCall();
+ } else {
+ t.synchronizedCall();
+ }
+
+ // Should only be boosted once.
+ Assert.assertEquals(TestTarget.boostCount, 1);
+ Assert.assertEquals(TestTarget.unboostCount, 1);
+ Assert.assertEquals(TestTarget.invokeCount, 1);
+ }
+}
diff --git a/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java
new file mode 100644
index 0000000..8e7d478
--- /dev/null
+++ b/tools/locked_region_code_injection/test/lockedregioncodeinjection/TestTarget.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package lockedregioncodeinjection;
+
+public class TestTarget {
+ public static int boostCount = 0;
+ public static int unboostCount = 0;
+ public static int invokeCount = 0;
+
+ public static void boost() {
+ boostCount++;
+ }
+
+ public static void unboost() {
+ unboostCount++;
+ }
+
+ public static void invoke() {
+ invokeCount++;
+ }
+
+ public static void resetCount() {
+ boostCount = 0;
+ unboostCount = 0;
+ invokeCount = 0;
+ }
+
+ public synchronized void synchronizedCall() {
+ invoke();
+ }
+
+ public synchronized int synchronizedCallReturnInt() {
+ invoke();
+ return 0;
+ }
+
+ public synchronized Object synchronizedCallReturnObject() {
+ invoke();
+ return this;
+ }
+}