Merge "Fix bad arguments handling"
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 6506df2..1254f1a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -139,6 +139,9 @@
BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event = 125;
BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed = 126;
BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed = 127;
+ AppDowngraded app_downgraded = 128;
+ AppOptimizedAfterDowngraded app_optimized_after_downgraded = 129;
+ LowStorageStateChanged low_storage_state_changed = 130;
NfcErrorOccurred nfc_error_occurred = 134;
NfcStateChanged nfc_state_changed = 135;
NfcBeamOccurred nfc_beam_occurred = 136;
@@ -166,6 +169,7 @@
BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167;
ProcessStartTime process_start_time = 169;
BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171;
+ DeviceIdentifierAccessDenied device_identifier_access_denied = 172;
NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"];
}
@@ -2007,6 +2011,47 @@
}
/**
+ * Logs when a volume entered low Storage state.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+ */
+message LowStorageStateChanged {
+ // Volume that ran out of storage.
+ optional string volume_description = 1;
+
+ enum State {
+ UNKNOWN = 0;
+ OFF = 1;
+ ON = 2;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs when an app is downgraded.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+ */
+message AppDowngraded {
+ optional string package_name = 1;
+ // Size of the package (all data) before being downgraded.
+ optional int64 size_in_bytes_before = 2;
+ // Size of the package (all data) after being downgraded.
+ optional int64 size_in_bytes_after = 3;
+
+ optional bool aggressive = 4;
+}
+
+/**
+ * Logs when an app is optimized after being downgraded.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+ */
+message AppOptimizedAfterDowngraded {
+ optional string package_name = 1;
+}
+
+/**
* Logs when an app crashes.
* Logged from:
* frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3054,3 +3099,22 @@
optional android.stats.connectivity.NetworkStackEventData network_stack_event = 2 [(log_mode) = MODE_BYTES];
}
+/**
+ * Logs when a package is denied access to a device identifier based on the new access requirements.
+ *
+ * Logged from:
+ * frameworks/base/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+ */
+message DeviceIdentifierAccessDenied {
+ // The name of the package denied access to the requested device identifier.
+ optional string package_name = 1;
+
+ // The name of the device identifier method the package attempted to invoke.
+ optional string method_name = 2;
+
+ // True if the package is preinstalled.
+ optional bool is_preinstalled = 3;
+
+ // True if the package is privileged.
+ optional bool is_priv_app = 4;
+}
\ No newline at end of file
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e2322f3..79a23d6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5654,6 +5654,31 @@
}
/**
+ * Returns whether the specified package can read the device identifiers.
+ *
+ * @param packageName The package name of the app to check for device identifier access.
+ * @param pid The process id of the package to be checked.
+ * @param uid The uid of the package to be checked.
+ * @return whether the package can read the device identifiers.
+ *
+ * @hide
+ */
+ public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
+ throwIfParentInstance("checkDeviceIdentifierAccess");
+ if (packageName == null) {
+ return false;
+ }
+ if (mService != null) {
+ try {
+ return mService.checkDeviceIdentifierAccess(packageName, pid, uid);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
* @hide
* @return the human readable name of the organisation associated with this DPM or {@code null}
* if one is not set.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 0e95e639..d74943a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -146,6 +146,7 @@
int getDeviceOwnerUserId();
boolean setProfileOwner(in ComponentName who, String ownerName, int userHandle);
+ ComponentName getProfileOwnerAsUser(int userHandle);
ComponentName getProfileOwner(int userHandle);
String getProfileOwnerName(int userHandle);
void setProfileEnabled(in ComponentName who);
@@ -153,6 +154,8 @@
void clearProfileOwner(in ComponentName who);
boolean hasUserSetupCompleted();
+ boolean checkDeviceIdentifierAccess(in String packageName, int pid, int uid);
+
void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
CharSequence getDeviceOwnerLockScreenInfo();
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index cd8dc63..965b064 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -556,7 +556,7 @@
* @hide
*/
public PackageInfo(ApexInfo apexInfo) {
- packageName = apexInfo.packageName;
+ packageName = apexInfo.moduleName;
setLongVersionCode(apexInfo.versionCode);
isApex = true;
}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index e568ef7..2bd401f 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -25,6 +25,7 @@
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.media.ExifInterface;
import android.media.MediaScanner;
import android.net.Uri;
import android.os.BatteryManager;
@@ -47,6 +48,7 @@
import com.google.android.collect.Sets;
import java.io.File;
+import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -843,6 +845,52 @@
return obj.getFormat();
}
+ private boolean getThumbnailInfo(int handle, long[] outLongs) {
+ MtpStorageManager.MtpObject obj = mManager.getObject(handle);
+ if (obj == null) {
+ return false;
+ }
+
+ String path = obj.getPath().toString();
+ switch (obj.getFormat()) {
+ case MtpConstants.FORMAT_HEIF:
+ case MtpConstants.FORMAT_EXIF_JPEG:
+ case MtpConstants.FORMAT_JFIF:
+ try {
+ ExifInterface exif = new ExifInterface(path);
+ long[] thumbOffsetAndSize = exif.getThumbnailRange();
+ outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0;
+ outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0);
+ outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0);
+ return true;
+ } catch (IOException e) {
+ // ignore and fall through
+ }
+ }
+ return false;
+ }
+
+ private byte[] getThumbnailData(int handle) {
+ MtpStorageManager.MtpObject obj = mManager.getObject(handle);
+ if (obj == null) {
+ return null;
+ }
+
+ String path = obj.getPath().toString();
+ switch (obj.getFormat()) {
+ case MtpConstants.FORMAT_HEIF:
+ case MtpConstants.FORMAT_EXIF_JPEG:
+ case MtpConstants.FORMAT_JFIF:
+ try {
+ ExifInterface exif = new ExifInterface(path);
+ return exif.getThumbnail();
+ } catch (IOException e) {
+ // ignore and fall through
+ }
+ }
+ return null;
+ }
+
private int beginDeleteObject(int handle) {
MtpStorageManager.MtpObject obj = mManager.getObject(handle);
if (obj == null) {
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 7a41c77..557eb9f 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -50,7 +50,6 @@
"libstagefright_foundation",
"libcamera_client",
"libmtp",
- "libexif",
"libpiex",
"libprocessgroup",
"libandroidfw",
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index a6c5fc8..c5389d1 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -30,13 +30,6 @@
#include "src/piex_types.h"
#include "src/piex.h"
-extern "C" {
-#include "libexif/exif-content.h"
-#include "libexif/exif-data.h"
-#include "libexif/exif-tag.h"
-#include "libexif/exif-utils.h"
-}
-
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <jni.h>
@@ -70,6 +63,8 @@
static jmethodID method_getObjectPropertyList;
static jmethodID method_getObjectInfo;
static jmethodID method_getObjectFilePath;
+static jmethodID method_getThumbnailInfo;
+static jmethodID method_getThumbnailData;
static jmethodID method_beginDeleteObject;
static jmethodID method_endDeleteObject;
static jmethodID method_beginMoveObject;
@@ -219,7 +214,7 @@
return; // Already threw.
}
mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
- jlongArray longArray = env->NewLongArray(2);
+ jlongArray longArray = env->NewLongArray(3);
if (!longArray) {
return; // Already threw.
}
@@ -780,57 +775,6 @@
return result;
}
-static void foreachentry(ExifEntry *entry, void* /* user */) {
- char buf[1024];
- ALOGI("entry %x, format %d, size %d: %s",
- entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf)));
-}
-
-static void foreachcontent(ExifContent *content, void *user) {
- ALOGI("content %d", exif_content_get_ifd(content));
- exif_content_foreach_entry(content, foreachentry, user);
-}
-
-static long getLongFromExifEntry(ExifEntry *e) {
- ExifByteOrder o = exif_data_get_byte_order(e->parent->parent);
- return exif_get_long(e->data, o);
-}
-
-static ExifData *getExifFromExtractor(const char *path) {
- std::unique_ptr<uint8_t[]> exifBuf;
- ExifData *exifdata = NULL;
-
- FILE *fp = fopen (path, "rb");
- if (!fp) {
- ALOGE("failed to open file");
- return NULL;
- }
-
- sp<NuMediaExtractor> extractor = new NuMediaExtractor();
- fseek(fp, 0L, SEEK_END);
- if (extractor->setDataSource(fileno(fp), 0, ftell(fp)) != OK) {
- ALOGE("failed to setDataSource");
- fclose(fp);
- return NULL;
- }
-
- off64_t offset;
- size_t size;
- if (extractor->getExifOffsetSize(&offset, &size) != OK) {
- fclose(fp);
- return NULL;
- }
-
- exifBuf.reset(new uint8_t[size]);
- fseek(fp, offset, SEEK_SET);
- if (fread(exifBuf.get(), 1, size, fp) == size) {
- exifdata = exif_data_new_from_data(exifBuf.get(), size);
- }
-
- fclose(fp);
- return exifdata;
-}
-
MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
MtpObjectInfo& info) {
MtpStringBuffer path;
@@ -877,26 +821,23 @@
case MTP_FORMAT_EXIF_JPEG:
case MTP_FORMAT_HEIF:
case MTP_FORMAT_JFIF: {
- ExifData *exifdata;
- if (info.mFormat == MTP_FORMAT_HEIF) {
- exifdata = getExifFromExtractor(path);
- } else {
- exifdata = exif_data_new_from_file(path);
- }
- if (exifdata) {
- if ((false)) {
- exif_data_foreach_content(exifdata, foreachcontent, NULL);
- }
+ env = AndroidRuntime::getJNIEnv();
+ if (env->CallBooleanMethod(
+ mDatabase, method_getThumbnailInfo, (jint)handle, mLongBuffer)) {
- ExifEntry *w = exif_content_get_entry(
- exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION);
- ExifEntry *h = exif_content_get_entry(
- exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION);
- info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0;
- info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
- info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0;
- info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0;
- exif_data_unref(exifdata);
+ jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
+ jlong size = longValues[0];
+ jlong w = longValues[1];
+ jlong h = longValues[2];
+ if (size > 0 && size <= UINT32_MAX &&
+ w > 0 && w <= UINT32_MAX &&
+ h > 0 && h <= UINT32_MAX) {
+ info.mThumbCompressedSize = size;
+ info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
+ info.mImagePixWidth = w;
+ info.mImagePixHeight = h;
+ }
+ env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
}
break;
}
@@ -941,22 +882,19 @@
case MTP_FORMAT_EXIF_JPEG:
case MTP_FORMAT_HEIF:
case MTP_FORMAT_JFIF: {
- ExifData *exifdata;
- if (format == MTP_FORMAT_HEIF) {
- exifdata = getExifFromExtractor(path);
- } else {
- exifdata = exif_data_new_from_file(path);
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jbyteArray thumbData = (jbyteArray) env->CallObjectMethod(
+ mDatabase, method_getThumbnailData, (jint)handle);
+ if (thumbData == NULL) {
+ return nullptr;
}
- if (exifdata) {
- if (exifdata->data) {
- result = malloc(exifdata->size);
- if (result) {
- memcpy(result, exifdata->data, exifdata->size);
- outThumbSize = exifdata->size;
- }
- }
- exif_data_unref(exifdata);
+ jsize thumbSize = env->GetArrayLength(thumbData);
+ result = malloc(thumbSize);
+ if (result) {
+ env->GetByteArrayRegion(thumbData, 0, thumbSize, (jbyte*)result);
+ outThumbSize = thumbSize;
}
+ env->DeleteLocalRef(thumbData);
break;
}
@@ -1388,6 +1326,8 @@
GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;");
GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z");
GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I");
+ GET_METHOD_ID(getThumbnailInfo, clazz, "(I[J)Z");
+ GET_METHOD_ID(getThumbnailData, clazz, "(I)[B");
GET_METHOD_ID(beginDeleteObject, clazz, "(I)I");
GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V");
GET_METHOD_ID(beginMoveObject, clazz, "(III)I");
diff --git a/services/core/java/com/android/server/NewNetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
similarity index 98%
rename from services/core/java/com/android/server/NewNetworkTimeUpdateService.java
rename to services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
index d21741a..b0b45f4 100644
--- a/services/core/java/com/android/server/NewNetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
@@ -55,7 +55,7 @@
* available.
* </p>
*/
-public class NewNetworkTimeUpdateService extends Binder implements NetworkTimeUpdateService {
+public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeUpdateService {
private static final String TAG = "NetworkTimeUpdateService";
private static final boolean DBG = false;
@@ -98,7 +98,7 @@
// connection to happen.
private int mTryAgainCounter;
- public NewNetworkTimeUpdateService(Context context) {
+ public NetworkTimeUpdateServiceImpl(Context context) {
mContext = context;
mTime = NtpTrustedTime.getInstance(context);
mAlarmManager = mContext.getSystemService(AlarmManager.class);
diff --git a/services/core/java/com/android/server/OldNetworkTimeUpdateService.java b/services/core/java/com/android/server/OldNetworkTimeUpdateService.java
deleted file mode 100644
index 068b83d..0000000
--- a/services/core/java/com/android/server/OldNetworkTimeUpdateService.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.NtpTrustedTime;
-import android.util.TimeUtils;
-
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.DumpUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Monitors the network time and updates the system time if it is out of sync
- * and there hasn't been any NITZ update from the carrier recently.
- * If looking up the network time fails for some reason, it tries a few times with a short
- * interval and then resets to checking on longer intervals.
- * <p>
- * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
- * available.
- * </p>
- */
-public class OldNetworkTimeUpdateService extends Binder implements NetworkTimeUpdateService {
-
- private static final String TAG = "NetworkTimeUpdateService";
- private static final boolean DBG = false;
-
- private static final int EVENT_AUTO_TIME_CHANGED = 1;
- private static final int EVENT_POLL_NETWORK_TIME = 2;
- private static final int EVENT_NETWORK_CHANGED = 3;
-
- private static final String ACTION_POLL =
- "com.android.server.NetworkTimeUpdateService.action.POLL";
-
- private static final int POLL_REQUEST = 0;
-
- private static final long NOT_SET = -1;
- private long mNitzTimeSetTime = NOT_SET;
- private Network mDefaultNetwork = null;
-
- private final Context mContext;
- private final NtpTrustedTime mTime;
- private final AlarmManager mAlarmManager;
- private final ConnectivityManager mCM;
- private final PendingIntent mPendingPollIntent;
- private final PowerManager.WakeLock mWakeLock;
-
- // NTP lookup is done on this thread and handler
- private Handler mHandler;
- private SettingsObserver mSettingsObserver;
- private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
-
- // Normal polling frequency
- private final long mPollingIntervalMs;
- // Try-again polling interval, in case the network request failed
- private final long mPollingIntervalShorterMs;
- // Number of times to try again
- private final int mTryAgainTimesMax;
- // If the time difference is greater than this threshold, then update the time.
- private final int mTimeErrorThresholdMs;
- // Keeps track of how many quick attempts were made to fetch NTP time.
- // During bootup, the network may not have been up yet, or it's taking time for the
- // connection to happen.
- private int mTryAgainCounter;
-
- public OldNetworkTimeUpdateService(Context context) {
- mContext = context;
- mTime = NtpTrustedTime.getInstance(context);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
- mCM = mContext.getSystemService(ConnectivityManager.class);
-
- Intent pollIntent = new Intent(ACTION_POLL, null);
- mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
-
- mPollingIntervalMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingInterval);
- mPollingIntervalShorterMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingIntervalShorter);
- mTryAgainTimesMax = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpRetry);
- mTimeErrorThresholdMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpThreshold);
-
- mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, TAG);
- }
-
- @Override
- public void systemRunning() {
- registerForTelephonyIntents();
- registerForAlarms();
-
- HandlerThread thread = new HandlerThread(TAG);
- thread.start();
- mHandler = new MyHandler(thread.getLooper());
- mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
- mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
-
- mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
- mSettingsObserver.observe(mContext);
- }
-
- private void registerForTelephonyIntents() {
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
- mContext.registerReceiver(mNitzReceiver, intentFilter);
- }
-
- private void registerForAlarms() {
- mContext.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
- }
- }, new IntentFilter(ACTION_POLL));
- }
-
- private void onPollNetworkTime(int event) {
- // If Automatic time is not set, don't bother. Similarly, if we don't
- // have any default network, don't bother.
- if (mDefaultNetwork == null) return;
- mWakeLock.acquire();
- try {
- onPollNetworkTimeUnderWakeLock(event);
- } finally {
- mWakeLock.release();
- }
- }
-
- private void onPollNetworkTimeUnderWakeLock(int event) {
- // Force an NTP fix when outdated
- if (mTime.getCacheAge() >= mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
- mTime.forceRefresh();
- }
-
- if (mTime.getCacheAge() < mPollingIntervalMs) {
- // Obtained fresh fix; schedule next normal update
- resetAlarm(mPollingIntervalMs);
- if (isAutomaticTimeRequested()) {
- updateSystemClock(event);
- }
-
- } else {
- // No fresh fix; schedule retry
- mTryAgainCounter++;
- if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
- resetAlarm(mPollingIntervalShorterMs);
- } else {
- // Try much later
- mTryAgainCounter = 0;
- resetAlarm(mPollingIntervalMs);
- }
- }
- }
-
- private long getNitzAge() {
- if (mNitzTimeSetTime == NOT_SET) {
- return Long.MAX_VALUE;
- } else {
- return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
- }
- }
-
- /**
- * Consider updating system clock based on current NTP fix, if requested by
- * user, significant enough delta, and we don't have a recent NITZ.
- */
- private void updateSystemClock(int event) {
- final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
- if (!forceUpdate) {
- if (getNitzAge() < mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
- return;
- }
-
- final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
- if (skew < mTimeErrorThresholdMs) {
- if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
- return;
- }
- }
-
- SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
- }
-
- /**
- * Cancel old alarm and starts a new one for the specified interval.
- *
- * @param interval when to trigger the alarm, starting from now.
- */
- private void resetAlarm(long interval) {
- mAlarmManager.cancel(mPendingPollIntent);
- long now = SystemClock.elapsedRealtime();
- long next = now + interval;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
- }
-
- /**
- * Checks if the user prefers to automatically set the time.
- */
- private boolean isAutomaticTimeRequested() {
- return Settings.Global.getInt(
- mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
- }
-
- /** Receiver for Nitz time events */
- private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (DBG) Log.d(TAG, "Received " + action);
- if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
- mNitzTimeSetTime = SystemClock.elapsedRealtime();
- }
- }
- };
-
- /** Handler to do the network accesses on */
- private class MyHandler extends Handler {
-
- public MyHandler(Looper l) {
- super(l);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_AUTO_TIME_CHANGED:
- case EVENT_POLL_NETWORK_TIME:
- case EVENT_NETWORK_CHANGED:
- onPollNetworkTime(msg.what);
- break;
- }
- }
- }
-
- private class NetworkTimeUpdateCallback extends NetworkCallback {
- @Override
- public void onAvailable(Network network) {
- Log.d(TAG, String.format("New default network %s; checking time.", network));
- mDefaultNetwork = network;
- // Running on mHandler so invoke directly.
- onPollNetworkTime(EVENT_NETWORK_CHANGED);
- }
-
- @Override
- public void onLost(Network network) {
- if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
- }
- }
-
- /** Observer to watch for changes to the AUTO_TIME setting */
- private static class SettingsObserver extends ContentObserver {
-
- private int mMsg;
- private Handler mHandler;
-
- SettingsObserver(Handler handler, int msg) {
- super(handler);
- mHandler = handler;
- mMsg = msg;
- }
-
- void observe(Context context) {
- ContentResolver resolver = context.getContentResolver();
- resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
- false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- mHandler.obtainMessage(mMsg).sendToTarget();
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- pw.print("PollingIntervalMs: ");
- TimeUtils.formatDuration(mPollingIntervalMs, pw);
- pw.print("\nPollingIntervalShorterMs: ");
- TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
- pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
- pw.print("TimeErrorThresholdMs: ");
- TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
- pw.println("\nTryAgainCounter: " + mTryAgainCounter);
- pw.println("NTP cache age: " + mTime.getCacheAge());
- pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
- pw.println();
- }
-}
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
new file mode 100644
index 0000000..bb3b9be
--- /dev/null
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import android.annotation.Nullable;
+import android.compat.annotation.EnabledAfter;
+import android.content.pm.ApplicationInfo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents the state of a single compatibility change.
+ *
+ * <p>A compatibility change has a default setting, determined by the {@code enableAfterTargetSdk}
+ * and {@code disabled} constructor parameters. If a change is {@code disabled}, this overrides any
+ * target SDK criteria set. These settings can be overridden for a specific package using
+ * {@link #addPackageOverride(String, boolean)}.
+ *
+ * <p>Note, this class is not thread safe so callers must ensure thread safety.
+ */
+public final class CompatChange {
+
+ private final long mChangeId;
+ @Nullable private final String mName;
+ private final int mEnableAfterTargetSdk;
+ private final boolean mDisabled;
+ private Map<String, Boolean> mPackageOverrides;
+
+ public CompatChange(long changeId) {
+ this(changeId, null, -1, false);
+ }
+
+ /**
+ * @param changeId Unique ID for the change. See {@link android.compat.Compatibility}.
+ * @param name Short descriptive name.
+ * @param enableAfterTargetSdk {@code targetSdkVersion} restriction. See {@link EnabledAfter};
+ * -1 if the change is always enabled.
+ * @param disabled If {@code true}, overrides any {@code enableAfterTargetSdk} set.
+ */
+ public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk,
+ boolean disabled) {
+ mChangeId = changeId;
+ mName = name;
+ mEnableAfterTargetSdk = enableAfterTargetSdk;
+ mDisabled = disabled;
+ }
+
+ long getId() {
+ return mChangeId;
+ }
+
+ @Nullable
+ String getName() {
+ return mName;
+ }
+
+ /**
+ * Force the enabled state of this change for a given package name. The change will only take
+ * effect after that packages process is killed and restarted.
+ *
+ * <p>Note, this method is not thread safe so callers must ensure thread safety.
+ *
+ * @param pname Package name to enable the change for.
+ * @param enabled Whether or not to enable the change.
+ */
+ void addPackageOverride(String pname, boolean enabled) {
+ if (mPackageOverrides == null) {
+ mPackageOverrides = new HashMap<>();
+ }
+ mPackageOverrides.put(pname, enabled);
+ }
+
+ /**
+ * Remove any package override for the given package name, restoring the default behaviour.
+ *
+ * <p>Note, this method is not thread safe so callers must ensure thread safety.
+ *
+ * @param pname Package name to reset to defaults for.
+ */
+ void removePackageOverride(String pname) {
+ if (mPackageOverrides != null) {
+ mPackageOverrides.remove(pname);
+ }
+ }
+
+ /**
+ * Find if this change is enabled for the given package, taking into account any overrides that
+ * exist.
+ *
+ * @param app Info about the app in question
+ * @return {@code true} if the change should be enabled for the package.
+ */
+ boolean isEnabled(ApplicationInfo app) {
+ if (mPackageOverrides != null && mPackageOverrides.containsKey(app.packageName)) {
+ return mPackageOverrides.get(app.packageName);
+ }
+ if (mDisabled) {
+ return false;
+ }
+ if (mEnableAfterTargetSdk != -1) {
+ return app.targetSdkVersion > mEnableAfterTargetSdk;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("ChangeId(")
+ .append(mChangeId);
+ if (mName != null) {
+ sb.append("; name=").append(mName);
+ }
+ if (mEnableAfterTargetSdk != -1) {
+ sb.append("; enableAfterTargetSdk=").append(mEnableAfterTargetSdk);
+ }
+ if (mDisabled) {
+ sb.append("; disabled");
+ }
+ if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
+ sb.append("; packageOverrides=").append(mPackageOverrides);
+ }
+ return sb.append(")").toString();
+ }
+}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
new file mode 100644
index 0000000..fea5d83
--- /dev/null
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import android.content.pm.ApplicationInfo;
+import android.text.TextUtils;
+import android.util.LongArray;
+import android.util.LongSparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * This class maintains state relating to platform compatibility changes.
+ *
+ * <p>It stores the default configuration for each change, and any per-package overrides that have
+ * been configured.
+ */
+public final class CompatConfig {
+
+ private static final CompatConfig sInstance = new CompatConfig();
+
+ @GuardedBy("mChanges")
+ private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
+
+ @VisibleForTesting
+ public CompatConfig() {
+ }
+
+ /**
+ * @return The static instance of this class to be used within the system server.
+ */
+ public static CompatConfig get() {
+ return sInstance;
+ }
+
+ /**
+ * Add a change. This is intended to be used by code that reads change config from the
+ * filesystem. This should be done at system startup time.
+ *
+ * @param change The change to add. Any change with the same ID will be overwritten.
+ */
+ public void addChange(CompatChange change) {
+ synchronized (mChanges) {
+ mChanges.put(change.getId(), change);
+ }
+ }
+
+ /**
+ * Retrieves the set of disabled changes for a given app. Any change ID not in the returned
+ * array is by default enabled for the app.
+ *
+ * @param app The app in question
+ * @return A sorted long array of change IDs. We use a primitive array to minimize memory
+ * footprint: Every app process will store this array statically so we aim to reduce
+ * overhead as much as possible.
+ */
+ public long[] getDisabledChanges(ApplicationInfo app) {
+ LongArray disabled = new LongArray();
+ synchronized (mChanges) {
+ for (int i = 0; i < mChanges.size(); ++i) {
+ CompatChange c = mChanges.valueAt(i);
+ if (!c.isEnabled(app)) {
+ disabled.add(c.getId());
+ }
+ }
+ }
+ // Note: we don't need to explicitly sort the array, as the behaviour of LongSparseArray
+ // (mChanges) ensures it's already sorted.
+ return disabled.toArray();
+ }
+
+ /**
+ * Look up a change ID by name.
+ *
+ * @param name Name of the change to look up
+ * @return The change ID, or {@code -1} if no change with that name exists.
+ */
+ public long lookupChangeId(String name) {
+ synchronized (mChanges) {
+ for (int i = 0; i < mChanges.size(); ++i) {
+ if (TextUtils.equals(mChanges.valueAt(i).getName(), name)) {
+ return mChanges.keyAt(i);
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Find if a given change is enabled for a given application.
+ *
+ * @param changeId The ID of the change in question
+ * @param app App to check for
+ * @return {@code true} if the change is enabled for this app. Also returns {@code true} if the
+ * change ID is not known, as unknown changes are enabled by default.
+ */
+ public boolean isChangeEnabled(long changeId, ApplicationInfo app) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ // we know nothing about this change: default behaviour is enabled.
+ return true;
+ }
+ return c.isEnabled(app);
+ }
+ }
+
+ /**
+ * Overrides the enabled state for a given change and app. This method is intended to be used
+ * *only* for debugging purposes, ultimately invoked either by an adb command, or from some
+ * developer settings UI.
+ *
+ * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+ *
+ * @param changeId The ID of the change to be overridden. Note, this call will succeed even if
+ * this change is not known; it will only have any affect if any code in the
+ * platform is gated on the ID given.
+ * @param packageName The app package name to override the change for.
+ * @param enabled If the change should be enabled or disabled.
+ */
+ public void addOverride(long changeId, String packageName, boolean enabled) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ c = new CompatChange(changeId);
+ addChange(c);
+ }
+ c.addPackageOverride(packageName, enabled);
+ }
+ }
+
+ /**
+ * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
+ * restores the default behaviour for the given change and app, once any app processes have been
+ * restarted.
+ *
+ * @param changeId The ID of the change that was overridden.
+ * @param packageName The app package name that was overridden.
+ */
+ public void removeOverride(long changeId, String packageName) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c != null) {
+ c.removePackageOverride(packageName);
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
new file mode 100644
index 0000000..456d15e
--- /dev/null
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import android.content.pm.ApplicationInfo;
+import android.util.Slog;
+
+/**
+ * System server internal API for gating and reporting compatibility changes.
+ */
+public class PlatformCompat {
+
+ private static final String TAG = "Compatibility";
+
+ /**
+ * Reports that a compatibility change is affecting an app process now.
+ *
+ * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
+ * you do not need to call this API directly. The change will be reported for you in the case
+ * that {@link #isChangeEnabled(long, ApplicationInfo)} returns {@code true}.
+ *
+ * @param changeId The ID of the compatibility change taking effect.
+ * @param appInfo Representing the affected app.
+ */
+ public static void reportChange(long changeId, ApplicationInfo appInfo) {
+ Slog.d(TAG, "Compat change reported: " + changeId + "; UID " + appInfo.uid);
+ // TODO log via StatsLog
+ }
+
+ /**
+ * Query if a given compatibility change is enabled for an app process. This method should
+ * be called when implementing functionality on behalf of the affected app.
+ *
+ * <p>If this method returns {@code true}, the calling code should implement the compatibility
+ * change, resulting in differing behaviour compared to earlier releases. If this method returns
+ * {@code false}, the calling code should behave as it did in earlier releases.
+ *
+ * <p>When this method returns {@code true}, it will also report the change as
+ * {@link #reportChange(long, ApplicationInfo)} would, so there is no need to call that method
+ * directly.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @param appInfo Representing the app in question.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ public static boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
+ if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
+ reportChange(changeId, appInfo);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 33c84d1..4957eed 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -44,6 +44,7 @@
import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.server.ConnectivityService.SHORT_ARG;
@@ -89,6 +90,8 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -97,7 +100,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
@@ -182,12 +184,13 @@
// into a single coherent structure.
private final HashSet<IpServer> mForwardedDownstreams;
private final VersionedBroadcastListener mCarrierConfigChange;
- private final VersionedBroadcastListener mDefaultSubscriptionChange;
private final TetheringDependencies mDeps;
private final EntitlementManager mEntitlementMgr;
private final Handler mHandler;
private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
new RemoteCallbackList<>();
+ private final PhoneStateListener mPhoneStateListener;
+ private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
private volatile TetheringConfiguration mConfig;
private InterfaceSet mCurrentUpstreamIfaceSet;
@@ -238,7 +241,6 @@
stopTethering(downstream);
});
mEntitlementMgr.setTetheringConfigurationFetcher(() -> {
- maybeDefaultDataSubChanged();
return mConfig;
});
@@ -250,22 +252,26 @@
mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
});
- filter = new IntentFilter();
- filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
- mDefaultSubscriptionChange = new VersionedBroadcastListener(
- "DefaultSubscriptionChangeListener", mContext, mHandler, filter,
- (Intent ignored) -> {
- mLog.log("OBSERVED default data subscription change");
- maybeDefaultDataSubChanged();
- // To avoid launch unexpected provisioning checks, ignore re-provisioning when
- // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be
- // triggered again when CarrierConfig is loaded.
- if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
- mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
- } else {
- mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded");
- }
- });
+ mPhoneStateListener = new PhoneStateListener(mLooper) {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId
+ + " to " + subId);
+ if (subId == mActiveDataSubId) return;
+
+ mActiveDataSubId = subId;
+ updateConfiguration();
+ // To avoid launching unexpected provisioning checks, ignore re-provisioning when
+ // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be
+ // triggered again when CarrierConfig is loaded.
+ if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
+ mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
+ } else {
+ mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded");
+ }
+ }
+ };
+
mStateReceiver = new StateReceiver();
// Load tethering configuration.
@@ -276,7 +282,8 @@
private void startStateMachineUpdaters(Handler handler) {
mCarrierConfigChange.startListening();
- mDefaultSubscriptionChange.startListening();
+ TelephonyManager.from(mContext).listen(mPhoneStateListener,
+ PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_STATE);
@@ -304,27 +311,17 @@
// NOTE: This is always invoked on the mLooper thread.
private void updateConfiguration() {
- final int subId = mDeps.getDefaultDataSubscriptionId();
- updateConfiguration(subId);
- }
-
- private void updateConfiguration(final int subId) {
- mConfig = new TetheringConfiguration(mContext, mLog, subId);
+ mConfig = mDeps.generateTetheringConfiguration(mContext, mLog, mActiveDataSubId);
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
}
private void maybeDunSettingChanged() {
- final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext);
+ final boolean isDunRequired = TetheringConfiguration.checkDunRequired(
+ mContext, mActiveDataSubId);
if (isDunRequired == mConfig.isDunRequired) return;
updateConfiguration();
}
- private void maybeDefaultDataSubChanged() {
- final int subId = mDeps.getDefaultDataSubscriptionId();
- if (subId == mConfig.subId) return;
- updateConfiguration(subId);
- }
-
@Override
public void interfaceStatusChanged(String iface, boolean up) {
// Never called directly: only called from interfaceLinkStateChanged.
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 8427b6e..1907892 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -112,7 +112,7 @@
tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs);
- isDunRequired = checkDunRequired(ctx);
+ isDunRequired = checkDunRequired(ctx, subId);
chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic);
preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired);
@@ -228,9 +228,9 @@
}
/** Check whether dun is required. */
- public static boolean checkDunRequired(Context ctx) {
+ public static boolean checkDunRequired(Context ctx, int id) {
final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
- return (tm != null) ? tm.getTetherApnRequired() : false;
+ return (tm != null) ? tm.getTetherApnRequired(id) : false;
}
private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index a0aad7c..4ad7ac4 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -21,7 +21,6 @@
import android.net.ip.IpServer;
import android.net.util.SharedLog;
import android.os.Handler;
-import android.telephony.SubscriptionManager;
import com.android.internal.util.StateMachine;
import com.android.server.connectivity.MockableSystemProperties;
@@ -88,9 +87,10 @@
}
/**
- * Get default data subscription id to build TetheringConfiguration.
+ * Generate a new TetheringConfiguration according to input sub Id.
*/
- public int getDefaultDataSubscriptionId() {
- return SubscriptionManager.getDefaultDataSubscriptionId();
+ public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
+ int subId) {
+ return new TetheringConfiguration(ctx, log, subId);
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4f4377d..90dc700 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1180,14 +1180,22 @@
}
}
- // Traffic occurring on stacked interfaces is usually clatd,
- // which is already accounted against its final egress interface
- // by the kernel. Thus, we only need to collect stacked
- // interface stats at the UID level.
+ // Traffic occurring on stacked interfaces is usually clatd.
+ // UID stats are always counted on the stacked interface and never
+ // on the base interface, because the packets on the base interface
+ // do not actually match application sockets until they are translated.
+ //
+ // Interface stats are more complicated. Packets subject to BPF offload
+ // never appear on the base interface and only appear on the stacked
+ // interface, so to ensure those packets increment interface stats, interface
+ // stats from stacked interfaces must be collected.
final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
for (LinkProperties stackedLink : stackedLinks) {
final String stackedIface = stackedLink.getInterfaceName();
if (stackedIface != null) {
+ if (mUseBpfTrafficStats) {
+ findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident);
+ }
findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
if (isMobile) {
mobileIfaces.add(stackedIface);
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index d6ab5f7..2b33ace 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -27,24 +27,30 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.os.BatteryManager;
import android.os.Environment;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.util.ArraySet;
import android.util.Log;
+import android.util.StatsLog;
-import com.android.server.pm.dex.DexManager;
+import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
+import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import java.io.File;
+import java.nio.file.Paths;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
/**
* {@hide}
@@ -52,7 +58,7 @@
public class BackgroundDexOptService extends JobService {
private static final String TAG = "BackgroundDexOptService";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final int JOB_IDLE_OPTIMIZE = 800;
private static final int JOB_POST_BOOT_UPDATE = 801;
@@ -97,7 +103,6 @@
private final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false);
private final File mDataDir = Environment.getDataDirectory();
-
private static final long mDowngradeUnusedAppsThresholdInMillis =
getDowngradeUnusedAppsThresholdInMillis();
@@ -249,9 +254,16 @@
@Override
public void run() {
int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this);
- if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+ if (result == OPTIMIZE_PROCESSED) {
+ Log.i(TAG, "Idle optimizations completed.");
+ } else if (result == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
Log.w(TAG, "Idle optimizations aborted because of space constraints.");
- // If we didn't abort we ran to completion (or stopped because of space).
+ } else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+ Log.w(TAG, "Idle optimizations aborted by job scheduler.");
+ } else {
+ Log.w(TAG, "Idle optimizations ended with unexpected code: " + result);
+ }
+ if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
// Abandon our timeslice and do not reschedule.
jobFinished(jobParams, /* reschedule */ false);
}
@@ -270,106 +282,147 @@
long lowStorageThreshold = getLowStorageThreshold(context);
// Optimize primary apks.
- int result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ true,
- sFailedPackageNamesPrimary);
-
+ int result = optimizePackages(pm, pkgs, lowStorageThreshold,
+ /*isForPrimaryDex=*/ true);
if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
return result;
}
-
- if (SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false)) {
+ if (supportSecondaryDex()) {
result = reconcileSecondaryDexFiles(pm.getDexManager());
if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
return result;
}
-
- result = optimizePackages(pm, pkgs, lowStorageThreshold, /*is_for_primary_dex*/ false,
- sFailedPackageNamesSecondary);
+ result = optimizePackages(pm, pkgs, lowStorageThreshold,
+ /*isForPrimaryDex=*/ false);
}
return result;
}
+ /**
+ * Get the size of the directory. It uses recursion to go over all files.
+ * @param f
+ * @return
+ */
+ private long getDirectorySize(File f) {
+ long size = 0;
+ if (f.isDirectory()) {
+ for (File file: f.listFiles()) {
+ size += getDirectorySize(file);
+ }
+ } else {
+ size = f.length();
+ }
+ return size;
+ }
+
+ /**
+ * Get the size of a package.
+ * @param pkg
+ */
+ private long getPackageSize(PackageManagerService pm, String pkg) {
+ PackageInfo info = pm.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+ long size = 0;
+ if (info != null && info.applicationInfo != null) {
+ File path = Paths.get(info.applicationInfo.sourceDir).toFile();
+ if (path.isFile()) {
+ path = path.getParentFile();
+ }
+ size += getDirectorySize(path);
+ if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
+ for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
+ path = Paths.get(splitSourceDir).toFile();
+ if (path.isFile()) {
+ path = path.getParentFile();
+ }
+ size += getDirectorySize(path);
+ }
+ }
+ return size;
+ }
+ return 0;
+ }
+
private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
- long lowStorageThreshold, boolean is_for_primary_dex,
- ArraySet<String> failedPackageNames) {
+ long lowStorageThreshold, boolean isForPrimaryDex) {
ArraySet<String> updatedPackages = new ArraySet<>();
Set<String> unusedPackages = pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
+ boolean hadSomeLowSpaceFailure = false;
+ Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
// Only downgrade apps when space is low on device.
// Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
// up disk before user hits the actual lowStorageThreshold.
final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE *
lowStorageThreshold;
boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade);
+ Log.d(TAG, "Should Downgrade " + shouldDowngrade);
+ boolean dex_opt_performed = false;
for (String pkg : pkgs) {
int abort_code = abortIdleOptimizations(lowStorageThreshold);
if (abort_code == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
return abort_code;
}
-
- synchronized (failedPackageNames) {
- if (failedPackageNames.contains(pkg)) {
- // Skip previously failing package
- continue;
- }
- }
-
- int reason;
- boolean downgrade;
// Downgrade unused packages.
if (unusedPackages.contains(pkg) && shouldDowngrade) {
- // This applies for system apps or if packages location is not a directory, i.e.
- // monolithic install.
- if (is_for_primary_dex && !pm.canHaveOatDir(pkg)) {
- // For apps that don't have the oat directory, instead of downgrading,
- // remove their compiler artifacts from dalvik cache.
- pm.deleteOatArtifactsOfPackage(pkg);
+ dex_opt_performed = downgradePackage(pm, pkg, isForPrimaryDex);
+ } else {
+ if (abort_code == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
+ // can't dexopt because of low space.
+ hadSomeLowSpaceFailure = true;
continue;
- } else {
- reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
- downgrade = true;
}
- } else if (abort_code != OPTIMIZE_ABORT_NO_SPACE_LEFT) {
- reason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
- downgrade = false;
- } else {
- // can't dexopt because of low space.
- continue;
+ dex_opt_performed = optimizePackage(pm, pkg, isForPrimaryDex);
}
-
- synchronized (failedPackageNames) {
- // Conservatively add package to the list of failing ones in case
- // performDexOpt never returns.
- failedPackageNames.add(pkg);
- }
-
- // Optimize package if needed. Note that there can be no race between
- // concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
- boolean success;
- int dexoptFlags =
- DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES |
- DexoptOptions.DEXOPT_BOOT_COMPLETE |
- (downgrade ? DexoptOptions.DEXOPT_DOWNGRADE : 0) |
- DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB;
- if (is_for_primary_dex) {
- int result = pm.performDexOptWithStatus(new DexoptOptions(pkg, reason,
- dexoptFlags));
- success = result != PackageDexOptimizer.DEX_OPT_FAILED;
- if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
- updatedPackages.add(pkg);
- }
- } else {
- success = pm.performDexOpt(new DexoptOptions(pkg,
- reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX));
- }
- if (success) {
- // Dexopt succeeded, remove package from the list of failing ones.
- synchronized (failedPackageNames) {
- failedPackageNames.remove(pkg);
- }
+ if (dex_opt_performed) {
+ updatedPackages.add(pkg);
}
}
+
notifyPinService(updatedPackages);
- return OPTIMIZE_PROCESSED;
+ return hadSomeLowSpaceFailure ? OPTIMIZE_ABORT_NO_SPACE_LEFT : OPTIMIZE_PROCESSED;
+ }
+
+
+ /**
+ * Try to downgrade the package to a smaller compilation filter.
+ * eg. if the package is in speed-profile the package will be downgraded to verify.
+ * @param pm PackageManagerService
+ * @param pkg The package to be downgraded.
+ * @param isForPrimaryDex. Apps can have several dex file, primary and secondary.
+ * @return true if the package was downgraded.
+ */
+ private boolean downgradePackage(PackageManagerService pm, String pkg,
+ boolean isForPrimaryDex) {
+ Log.d(TAG, "Downgrading " + pkg);
+ boolean dex_opt_performed = false;
+ int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE;
+ int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE
+ | DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB
+ | DexoptOptions.DEXOPT_DOWNGRADE;
+ long package_size_before = getPackageSize(pm, pkg);
+
+ if (isForPrimaryDex) {
+ // This applies for system apps or if packages location is not a directory, i.e.
+ // monolithic install.
+ if (!pm.canHaveOatDir(pkg)) {
+ // For apps that don't have the oat directory, instead of downgrading,
+ // remove their compiler artifacts from dalvik cache.
+ pm.deleteOatArtifactsOfPackage(pkg);
+ } else {
+ dex_opt_performed = performDexOptPrimary(pm, pkg, reason, dexoptFlags);
+ }
+ } else {
+ dex_opt_performed = performDexOptSecondary(pm, pkg, reason, dexoptFlags);
+ }
+
+ if (dex_opt_performed) {
+ StatsLog.write(StatsLog.APP_DOWNGRADED, pkg, package_size_before,
+ getPackageSize(pm, pkg), /*aggressive=*/ false);
+ }
+ return dex_opt_performed;
+ }
+
+ private boolean supportSecondaryDex() {
+ return (SystemProperties.getBoolean("dalvik.vm.dexopt.secondary", false));
}
private int reconcileSecondaryDexFiles(DexManager dm) {
@@ -383,6 +436,73 @@
return OPTIMIZE_PROCESSED;
}
+ /**
+ *
+ * Optimize package if needed. Note that there can be no race between
+ * concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
+ * @param pm An instance of PackageManagerService
+ * @param pkg The package to be downgraded.
+ * @param isForPrimaryDex. Apps can have several dex file, primary and secondary.
+ * @return true if the package was downgraded.
+ */
+ private boolean optimizePackage(PackageManagerService pm, String pkg,
+ boolean isForPrimaryDex) {
+ int reason = PackageManagerService.REASON_BACKGROUND_DEXOPT;
+ int dexoptFlags = DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES
+ | DexoptOptions.DEXOPT_BOOT_COMPLETE
+ | DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB;
+
+ return isForPrimaryDex
+ ? performDexOptPrimary(pm, pkg, reason, dexoptFlags)
+ : performDexOptSecondary(pm, pkg, reason, dexoptFlags);
+ }
+
+ private boolean performDexOptPrimary(PackageManagerService pm, String pkg, int reason,
+ int dexoptFlags) {
+ int result = trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ false,
+ () -> pm.performDexOptWithStatus(new DexoptOptions(pkg, reason, dexoptFlags)));
+ return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
+ }
+
+ private boolean performDexOptSecondary(PackageManagerService pm, String pkg, int reason,
+ int dexoptFlags) {
+ DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason,
+ dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX);
+ int result = trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ true,
+ () -> pm.performDexOpt(dexoptOptions)
+ ? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED
+ );
+ return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
+ }
+
+ /**
+ * Execute the dexopt wrapper and make sure that if performDexOpt wrapper fails
+ * the package is added to the list of failed packages.
+ * Return one of following result:
+ * {@link PackageDexOptimizer#DEX_OPT_SKIPPED}
+ * {@link PackageDexOptimizer#DEX_OPT_PERFORMED}
+ * {@link PackageDexOptimizer#DEX_OPT_FAILED}
+ */
+ private int trackPerformDexOpt(String pkg, boolean isForPrimaryDex,
+ Supplier<Integer> performDexOptWrapper) {
+ ArraySet<String> sFailedPackageNames =
+ isForPrimaryDex ? sFailedPackageNamesPrimary : sFailedPackageNamesSecondary;
+ synchronized (sFailedPackageNames) {
+ if (sFailedPackageNames.contains(pkg)) {
+ // Skip previously failing package
+ return PackageDexOptimizer.DEX_OPT_SKIPPED;
+ }
+ sFailedPackageNames.add(pkg);
+ }
+ int result = performDexOptWrapper.get();
+ if (result != PackageDexOptimizer.DEX_OPT_FAILED) {
+ synchronized (sFailedPackageNames) {
+ sFailedPackageNames.remove(pkg);
+ }
+ }
+ return result;
+ }
+
// Evaluate whether or not idle optimizations should continue.
private int abortIdleOptimizations(long lowStorageThreshold) {
if (mAbortIdleOptimization.get()) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 57deb3f..fa570b8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -115,6 +115,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -959,7 +960,7 @@
try {
IApexService apex = IApexService.Stub.asInterface(
ServiceManager.getService("apexservice"));
- apex.stagePackage(mResolvedBaseFile.toString());
+ apex.stagePackages(Collections.singletonList(mResolvedBaseFile.toString()));
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f938b65..aac8dad 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9004,6 +9004,20 @@
}
}
+ /**
+ * Enforces that only the system UID or root's UID or shell's UID can call
+ * a method exposed via Binder.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or shell
+ */
+ private static void enforceSystemOrRootOrShell(String message) {
+ final int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID && uid != Process.ROOT_UID && uid != Process.SHELL_UID) {
+ throw new SecurityException(message);
+ }
+ }
+
@Override
public void performFstrimIfNeeded() {
enforceSystemOrRoot("Only the system can request fstrim");
@@ -9498,7 +9512,13 @@
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
}
- return BackgroundDexOptService.runIdleOptimizationsNow(this, mContext, packageNames);
+ enforceSystemOrRootOrShell("runBackgroundDexoptJob");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return BackgroundDexOptService.runIdleOptimizationsNow(this, mContext, packageNames);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e1c1302..242f9c3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1334,6 +1334,7 @@
}
boolean result = mInterface.runBackgroundDexoptJob(packageNames.isEmpty() ? null :
packageNames);
+ getOutPrintWriter().println(result ? "Success" : "Failure");
return result ? 0 : -1;
}
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index f7cc443..2700f9d 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -24,7 +24,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.net.TrafficStats;
import android.os.Binder;
import android.os.Environment;
import android.os.FileObserver;
@@ -42,13 +41,13 @@
import android.util.ArrayMap;
import android.util.DataUnit;
import android.util.Slog;
+import android.util.StatsLog;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
-import com.android.server.IoThread;
import com.android.server.SystemService;
import com.android.server.pm.InstructionSets;
import com.android.server.pm.PackageManagerService;
@@ -499,9 +498,15 @@
notification.flags |= Notification.FLAG_NO_CLEAR;
mNotifManager.notifyAsUser(uuid.toString(), SystemMessage.NOTE_LOW_STORAGE,
notification, UserHandle.ALL);
+ StatsLog.write(StatsLog.LOW_STORAGE_STATE_CHANGED,
+ Objects.toString(vol.getDescription()),
+ StatsLog.LOW_STORAGE_STATE_CHANGED__STATE__ON);
} else if (State.isLeaving(State.LEVEL_LOW, oldLevel, newLevel)) {
mNotifManager.cancelAsUser(uuid.toString(), SystemMessage.NOTE_LOW_STORAGE,
UserHandle.ALL);
+ StatsLog.write(StatsLog.LOW_STORAGE_STATE_CHANGED,
+ Objects.toString(vol.getDescription()),
+ StatsLog.LOW_STORAGE_STATE_CHANGED__STATE__OFF);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 1c9782f..f2560b3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -15,7 +15,6 @@
*/
package com.android.server.devicepolicy;
-import android.annotation.UserIdInt;
import android.app.admin.IDevicePolicyManager;
import android.content.ComponentName;
import android.os.PersistableBundle;
@@ -159,4 +158,9 @@
@Override
public void setDefaultSmsApplication(ComponentName admin, String packageName) {
}
+
+ @Override
+ public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d3b25fd..d1128af 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -60,7 +60,6 @@
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
-
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
@@ -69,11 +68,10 @@
.PROVISIONING_ENTRY_POINT_ADB;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker
.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
-
-import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_DEVICE_OWNER;
-import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER;
-
-
+import static com.android.server.devicepolicy.TransferOwnershipMetadataManager
+ .ADMIN_TYPE_DEVICE_OWNER;
+import static com.android.server.devicepolicy.TransferOwnershipMetadataManager
+ .ADMIN_TYPE_PROFILE_OWNER;
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -219,11 +217,11 @@
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.StatLogger;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
-import com.android.internal.util.StatLogger;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
@@ -5188,7 +5186,8 @@
@Override
public void enforceCanManageCaCerts(ComponentName who, String callerPackage) {
if (who == null) {
- if (!isCallerDelegate(callerPackage, DELEGATION_CERT_INSTALL)) {
+ if (!isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(),
+ DELEGATION_CERT_INSTALL)) {
mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
}
} else {
@@ -5364,7 +5363,8 @@
if (UserHandle.getUserId(callerUid) != mOwners.getDeviceOwnerUserId()) {
throw new SecurityException("Caller not from device owner user");
}
- if (!isCallerDelegate(callerPackage, DELEGATION_CERT_INSTALL)) {
+ if (!isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(),
+ DELEGATION_CERT_INSTALL)) {
throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid() +
"has no permission to generate keys.");
}
@@ -5766,15 +5766,14 @@
* @param scope the delegation scope to be checked.
* @return {@code true} if the calling process is a delegate of {@code scope}.
*/
- private boolean isCallerDelegate(String callerPackage, String scope) {
+ private boolean isCallerDelegate(String callerPackage, int callerUid, String scope) {
Preconditions.checkNotNull(callerPackage, "callerPackage is null");
if (!Arrays.asList(DELEGATIONS).contains(scope)) {
throw new IllegalArgumentException("Unexpected delegation scope: " + scope);
}
// Retrieve the UID and user ID of the calling process.
- final int callingUid = mInjector.binderGetCallingUid();
- final int userId = UserHandle.getUserId(callingUid);
+ final int userId = UserHandle.getUserId(callerUid);
synchronized (getLockObject()) {
// Retrieve user policy data.
final DevicePolicyData policy = getUserData(userId);
@@ -5787,7 +5786,7 @@
final int uid = mInjector.getPackageManager()
.getPackageUidAsUser(callerPackage, userId);
// Return true if the caller is actually callerPackage.
- return uid == callingUid;
+ return uid == callerUid;
} catch (NameNotFoundException e) {
// Ignore.
}
@@ -5818,7 +5817,7 @@
getActiveAdminForCallerLocked(who, reqPolicy);
}
// If no ComponentName is given ensure calling process has scope delegation.
- } else if (!isCallerDelegate(callerPackage, scope)) {
+ } else if (!isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(), scope)) {
throw new SecurityException("Caller with uid " + mInjector.binderGetCallingUid()
+ " is not a delegate of scope " + scope + ".");
}
@@ -7783,6 +7782,13 @@
}
@Override
+ public ComponentName getProfileOwnerAsUser(int userHandle) {
+ enforceCrossUsersPermission(userHandle);
+
+ return getProfileOwner(userHandle);
+ }
+
+ @Override
public ComponentName getProfileOwner(int userHandle) {
if (!mHasFeature) {
return null;
@@ -7825,6 +7831,68 @@
return getApplicationLabel(profileOwner.getPackageName(), userHandle);
}
+ @Override
+ public boolean checkDeviceIdentifierAccess(String packageName, int pid, int uid) {
+ // If the caller is not a system app then it should only be able to check its own device
+ // identifier access.
+ int callingUid = mInjector.binderGetCallingUid();
+ int callingPid = mInjector.binderGetCallingPid();
+ if (UserHandle.getAppId(callingUid) >= Process.FIRST_APPLICATION_UID
+ && (callingUid != uid || callingPid != pid)) {
+ String message = String.format(
+ "Calling uid %d, pid %d cannot check device identifier access for package %s "
+ + "(uid=%d, pid=%d)", callingUid, callingPid, packageName, uid, pid);
+ Log.w(LOG_TAG, message);
+ throw new SecurityException(message);
+ }
+ // Verify that the specified packages matches the provided uid.
+ int userId = UserHandle.getUserId(uid);
+ try {
+ ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(packageName, 0, userId);
+ // Since this call goes directly to PackageManagerService a NameNotFoundException is not
+ // thrown but null data can be returned; if the appInfo for the specified package cannot
+ // be found then return false to prevent crashing the app.
+ if (appInfo == null) {
+ Log.w(LOG_TAG,
+ String.format("appInfo could not be found for package %s", packageName));
+ return false;
+ } else if (uid != appInfo.uid) {
+ String message = String.format("Package %s (uid=%d) does not match provided uid %d",
+ packageName, appInfo.uid, uid);
+ Log.w(LOG_TAG, message);
+ throw new SecurityException(message);
+ }
+ } catch (RemoteException e) {
+ // If an exception is caught obtaining the appInfo just return false to prevent crashing
+ // apps due to an internal error.
+ Log.e(LOG_TAG, "Exception caught obtaining appInfo for package " + packageName, e);
+ return false;
+ }
+ // A device or profile owner must also have the READ_PHONE_STATE permission to access device
+ // identifiers. If the package being checked does not have this permission then deny access.
+ if (mContext.checkPermission(android.Manifest.permission.READ_PHONE_STATE, pid, uid)
+ != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+
+ // Allow access to the device owner or delegate cert installer.
+ ComponentName deviceOwner = getDeviceOwnerComponent(true);
+ if (deviceOwner != null && (deviceOwner.getPackageName().equals(packageName)
+ || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
+ return true;
+ }
+ // Allow access to the profile owner for the specified user, or delegate cert installer
+ ComponentName profileOwner = getProfileOwnerAsUser(userId);
+ if (profileOwner != null && (profileOwner.getPackageName().equals(packageName)
+ || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
+ return true;
+ }
+
+ Log.w(LOG_TAG, String.format("Package %s (uid=%d, pid=%d) cannot access Device IDs",
+ packageName, uid, pid));
+ return false;
+ }
+
/**
* Canonical name for a given package.
*/
@@ -8266,7 +8334,8 @@
@Override
public boolean isCallerApplicationRestrictionsManagingPackage(String callerPackage) {
- return isCallerDelegate(callerPackage, DELEGATION_APP_RESTRICTIONS);
+ return isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(),
+ DELEGATION_APP_RESTRICTIONS);
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f0292aa..83ae0fc 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1303,16 +1303,13 @@
}
traceEnd();
- final boolean useNewTimeServices = true;
- if (useNewTimeServices) {
- traceBeginAndSlog("StartTimeDetectorService");
- try {
- mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting StartTimeDetectorService service", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartTimeDetectorService");
+ try {
+ mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting StartTimeDetectorService service", e);
}
+ traceEnd();
if (!isWatch) {
traceBeginAndSlog("StartSearchManagerService");
@@ -1487,12 +1484,7 @@
if (!isWatch) {
traceBeginAndSlog("StartNetworkTimeUpdateService");
try {
- if (useNewTimeServices) {
- networkTimeUpdater = new NewNetworkTimeUpdateService(context);
- } else {
- networkTimeUpdater = new OldNetworkTimeUpdateService(context);
- }
- Slog.d(TAG, "Using networkTimeUpdater class=" + networkTimeUpdater.getClass());
+ networkTimeUpdater = new NetworkTimeUpdateServiceImpl(context);
ServiceManager.addService("network_time_update_service", networkTimeUpdater);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
new file mode 100644
index 0000000..e6c484a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.pm.ApplicationInfo;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CompatConfigTest {
+
+ private ApplicationInfo makeAppInfo(String pName, int targetSdkVersion) {
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = pName;
+ ai.targetSdkVersion = targetSdkVersion;
+ return ai;
+ }
+
+ @Test
+ public void testUnknownChangeEnabled() {
+ CompatConfig pc = new CompatConfig();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ }
+
+ @Test
+ public void testDisabledChangeDisabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true));
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
+ }
+
+ @Test
+ public void testTargetSdkChangeDisabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false));
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ }
+
+ @Test
+ public void testTargetSdkChangeEnabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false));
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
+ }
+
+ @Test
+ public void testDisabledOverrideTargetSdkChange() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true));
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse();
+ }
+
+ @Test
+ public void testGetDisabledChanges() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true));
+ pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false));
+ assertThat(pc.getDisabledChanges(
+ makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L);
+ }
+
+ @Test
+ public void testGetDisabledChangesSorted() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true));
+ pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true));
+ pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true));
+ assertThat(pc.getDisabledChanges(
+ makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L);
+ }
+
+ @Test
+ public void testPackageOverrideEnabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true)); // disabled
+ pc.addOverride(1234L, "com.some.package", true);
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse();
+ }
+
+ @Test
+ public void testPackageOverrideDisabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+ pc.addOverride(1234L, "com.some.package", false);
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ }
+
+ @Test
+ public void testPackageOverrideUnknownPackage() {
+ CompatConfig pc = new CompatConfig();
+ pc.addOverride(1234L, "com.some.package", false);
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ }
+
+ @Test
+ public void testPackageOverrideUnknownChange() {
+ CompatConfig pc = new CompatConfig();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ }
+
+ @Test
+ public void testRemovePackageOverride() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+ pc.addOverride(1234L, "com.some.package", false);
+ pc.removeOverride(1234L, "com.some.package");
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
+ }
+
+ @Test
+ public void testLookupChangeId() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+ pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false));
+ assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
+ }
+
+ @Test
+ public void testLookupChangeIdNotPresent() {
+ CompatConfig pc = new CompatConfig();
+ assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
+ }
+}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 12422c6..6557886 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -791,6 +791,14 @@
public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
/**
+ * IMSI (International Mobile Subscriber Identity).
+ * <P>Type: TEXT </P>
+ * @hide
+ */
+ //TODO: add @SystemApi
+ public static final String IMSI = "imsi";
+
+ /**
* Broadcast Action: The user has changed one of the default subs related to
* data, phone calls, or sms</p>
*
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 73d49dd..2d66427 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -19,17 +19,28 @@
import android.Manifest;
import android.app.AppOpsManager;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.util.StatsLog;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
import java.util.function.Supplier;
/** Utility class for Telephony permission enforcement. */
@@ -41,6 +52,20 @@
private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
+ /**
+ * Whether to disable the new device identifier access restrictions.
+ */
+ private static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED =
+ "device_identifier_access_restrictions_disabled";
+
+ // Contains a mapping of packages that did not meet the new requirements to access device
+ // identifiers and the methods they were attempting to invoke; used to prevent duplicate
+ // reporting of packages / methods.
+ private static final Map<String, Set<String>> sReportedDeviceIDPackages;
+ static {
+ sReportedDeviceIDPackages = new HashMap<>();
+ }
+
private TelephonyPermissions() {}
/**
@@ -112,6 +137,19 @@
context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, message);
}
+ /**
+ * Check whether the calling packages has carrier privileges for the passing subscription.
+ * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
+ */
+ public static boolean checkCarrierPrivilegeForSubId(int subId) {
+ if (SubscriptionManager.isValidSubscriptionId(subId)
+ && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid())
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ return false;
+ }
+
@VisibleForTesting
public static boolean checkReadPhoneState(
Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
@@ -179,18 +217,9 @@
context.enforcePermission(
android.Manifest.permission.READ_PHONE_STATE, pid, uid, message);
} catch (SecurityException phoneStateException) {
- SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
- Context.TELEPHONY_SUBSCRIPTION_SERVICE);
- int[] activeSubIds = sm.getActiveSubscriptionIdList();
- for (int activeSubId : activeSubIds) {
- // If we don't have the runtime permission, but do have carrier privileges, that
- // suffices for reading phone state.
- if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
- == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
- return true;
- }
- }
- return false;
+ // If we don't have the runtime permission, but do have carrier privileges, that
+ // suffices for reading phone state.
+ return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid);
}
}
@@ -202,6 +231,182 @@
}
/**
+ * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
+ *
+ * <p>This method behaves in one of the following ways:
+ * <ul>
+ * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+ * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+ * access check, or the calling package has carrier privileges.
+ * <li>throw SecurityException: if the caller does not meet any of the requirements and is
+ * targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+ * <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+ * permission. In this case the caller would expect to have access to the device
+ * identifiers so false is returned instead of throwing a SecurityException to indicate
+ * the calling function should return dummy data.
+ * </ul>
+ */
+ public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context,
+ String callingPackage, String message) {
+ return checkCallingOrSelfReadDeviceIdentifiers(context,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message);
+ }
+
+ /**
+ * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
+ *
+ * <p>This method behaves in one of the following ways:
+ * <ul>
+ * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+ * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+ * access check, or the calling package has carrier privileges.
+ * <li>throw SecurityException: if the caller does not meet any of the requirements and is
+ * targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
+ * or carrier privileges.
+ * <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+ * permission or carrier privileges. In this case the caller would expect to have access
+ * to the device identifiers so false is returned instead of throwing a SecurityException
+ * to indicate the calling function should return dummy data.
+ * </ul>
+ */
+ public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
+ String callingPackage, String message) {
+ return checkReadDeviceIdentifiers(context, TELEPHONY_SUPPLIER, subId,
+ Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message);
+ }
+
+ /**
+ * Check whether the caller (or self, if not processing an IPC) can read subscriber identifiers.
+ *
+ * <p>This method behaves in one of the following ways:
+ * <ul>
+ * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+ * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+ * access check, or the calling package has carrier privileges.
+ * <li>throw SecurityException: if the caller does not meet any of the requirements and is
+ * targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+ * <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+ * permission. In this case the caller would expect to have access to the device
+ * identifiers so false is returned instead of throwing a SecurityException to indicate
+ * the calling function should return dummy data.
+ * </ul>
+ */
+ public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
+ String callingPackage, String message) {
+ return checkReadDeviceIdentifiers(context, TELEPHONY_SUPPLIER, subId,
+ Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message);
+ }
+
+ /**
+ * Checks whether the app with the given pid/uid can read device identifiers.
+ *
+ * @returns true if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the calling
+ * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier access
+ * check.
+ */
+ @VisibleForTesting
+ public static boolean checkReadDeviceIdentifiers(Context context,
+ Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+ String callingPackage, String message) {
+ // Allow system and root access to the device identifiers.
+ final int appId = UserHandle.getAppId(uid);
+ if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
+ return true;
+ }
+ // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission.
+ if (context.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid,
+ uid) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ // If the calling package has carrier privileges for any subscription then allow access.
+ if (checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid)) {
+ return true;
+ }
+ // if the calling package is not null then perform the DevicePolicyManager device /
+ // profile owner and Appop checks.
+ if (callingPackage != null) {
+ // Allow access to a device / profile owner app.
+ DevicePolicyManager devicePolicyManager =
+ (DevicePolicyManager) context.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ if (devicePolicyManager != null && devicePolicyManager.checkDeviceIdentifierAccess(
+ callingPackage, pid, uid)) {
+ return true;
+ }
+ }
+ return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
+ message);
+ }
+
+ /**
+ * Reports a failure when the app with the given pid/uid cannot access the requested identifier.
+ *
+ * @returns false if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+ * permission or carrier privileges.
+ * @throws SecurityException if the caller does not meet any of the requirements for the
+ * requested identifier and is targeting Q or is targeting pre-Q
+ * and does not have the READ_PHONE_STATE permission or carrier
+ * privileges.
+ */
+ private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
+ int uid, String callingPackage, String message) {
+ boolean isPreinstalled = false;
+ boolean isPrivApp = false;
+ ApplicationInfo callingPackageInfo = null;
+ try {
+ callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
+ callingPackage, 0, UserHandle.getUserId(uid));
+ if (callingPackageInfo != null) {
+ if (callingPackageInfo.isSystemApp()) {
+ isPreinstalled = true;
+ if (callingPackageInfo.isPrivilegedApp()) {
+ isPrivApp = true;
+ }
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // If the application info for the calling package could not be found then assume the
+ // calling app is a non-preinstalled app to detect any issues with the check
+ Log.e(LOG_TAG, "Exception caught obtaining package info for package " + callingPackage,
+ e);
+ }
+ // The current package should only be reported in StatsLog if it has not previously been
+ // reported for the currently invoked device identifier method.
+ boolean packageReported = sReportedDeviceIDPackages.containsKey(callingPackage);
+ if (!packageReported || !sReportedDeviceIDPackages.get(callingPackage).contains(
+ message)) {
+ Set invokedMethods;
+ if (!packageReported) {
+ invokedMethods = new HashSet<String>();
+ sReportedDeviceIDPackages.put(callingPackage, invokedMethods);
+ } else {
+ invokedMethods = sReportedDeviceIDPackages.get(callingPackage);
+ }
+ invokedMethods.add(message);
+ StatsLog.write(StatsLog.DEVICE_IDENTIFIER_ACCESS_DENIED, callingPackage, message,
+ isPreinstalled, isPrivApp);
+ }
+ Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
+ + ":isPreinstalled=" + isPreinstalled + ":isPrivApp=" + isPrivApp);
+ // if the target SDK is pre-Q then check if the calling package would have previously
+ // had access to device identifiers.
+ if (callingPackageInfo != null && (
+ callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
+ if (context.checkPermission(
+ android.Manifest.permission.READ_PHONE_STATE,
+ pid,
+ uid) == PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ if (checkCarrierPrivilegeForSubId(subId)) {
+ return false;
+ }
+ }
+ throw new SecurityException(message + ": The user " + uid
+ + " does not meet the requirements to access device identifiers.");
+ }
+
+ /**
* Check whether the app with the given pid/uid can read the call log.
* @return {@code true} if the specified app has the read call log permission and AppOpp granted
* to it, {@code false} otherwise.
@@ -383,6 +588,26 @@
}
}
+ /**
+ * Returns whether the provided uid has carrier privileges for any active subscription ID.
+ */
+ private static boolean checkCarrierPrivilegeForAnySubId(Context context,
+ Supplier<ITelephony> telephonySupplier, int uid) {
+ SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ int[] activeSubIds = sm.getActiveSubscriptionIdList();
+ if (activeSubIds != null) {
+ for (int activeSubId : activeSubIds) {
+ if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
private static int getCarrierPrivilegeStatus(
Supplier<ITelephony> telephonySupplier, int subId, int uid) {
ITelephony telephony = telephonySupplier.get();
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.bp b/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
index 036f845..a85d129 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
+++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
@@ -17,7 +17,7 @@
android_test {
name: "BackgroundDexOptServiceIntegrationTests",
srcs: ["src/**/*.java"],
- static_libs: ["android-support-test"],
+ static_libs: ["androidx.test.rules"],
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml
index afae155..aec9f77 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml
+++ b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml
@@ -34,7 +34,7 @@
</application>
<instrumentation
- android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.bgdexopttest"
android:label="Integration test for BackgroundDexOptService" />
</manifest>
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml b/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml
index 9bb1e28..a532422 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml
+++ b/tests/BackgroundDexOptServiceIntegrationTests/AndroidTest.xml
@@ -50,6 +50,6 @@
<option name="test-tag" value="BackgroundDexOptServiceIntegrationTests"/>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.frameworks.bgdexopttest"/>
- <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
</test>
</configuration>
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
index e247951..7d826f7 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
+++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java
@@ -19,13 +19,14 @@
import android.app.AlarmManager;
import android.content.Context;
import android.os.Environment;
+import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.os.storage.StorageManager;
-import android.support.test.InstrumentationRegistry;
import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -34,6 +35,7 @@
import org.junit.runners.JUnit4;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -141,27 +143,19 @@
// Run the command and return the stdout.
private static String runShellCommand(String cmd) throws IOException {
Log.i(TAG, String.format("running command: '%s'", cmd));
- long startTime = System.nanoTime();
- Process p = Runtime.getRuntime().exec(cmd);
- int res;
- try {
- res = p.waitFor();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
+ ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .executeShellCommand(cmd);
+ byte[] buf = new byte[512];
+ int bytesRead;
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ StringBuilder stdout = new StringBuilder();
+ while ((bytesRead = fis.read(buf)) != -1) {
+ stdout.append(new String(buf, 0, bytesRead));
}
- String stdout = inputStreamToString(p.getInputStream());
- String stderr = inputStreamToString(p.getErrorStream());
- long elapsedTime = System.nanoTime() - startTime;
- Log.i(TAG, String.format("ran command: '%s' in %d ms with return code %d", cmd,
- TimeUnit.NANOSECONDS.toMillis(elapsedTime), res));
+ fis.close();
Log.i(TAG, "stdout");
- Log.i(TAG, stdout);
- Log.i(TAG, "stderr");
- Log.i(TAG, stderr);
- if (res != 0) {
- throw new RuntimeException(String.format("failed command: '%s'", cmd));
- }
- return stdout;
+ Log.i(TAG, stdout.toString());
+ return stdout.toString();
}
// Run the command and return the stdout split by lines.
@@ -209,7 +203,10 @@
// TODO(aeubanks): figure out how to get scheduled bg-dexopt to run
private static void runBackgroundDexOpt() throws IOException {
- runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
+ String result = runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME);
+ if (!result.trim().equals("Success")) {
+ throw new IllegalStateException("Expected command success, received >" + result + "<");
+ }
}
// Set the time ahead of the last use time of the test app in days.
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 135bf90..5260b30 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -3,22 +3,6 @@
//########################################################################
java_defaults {
name: "FrameworksNetTests-jni-defaults",
- static_libs: [
- "FrameworksNetCommonTests",
- "frameworks-base-testutils",
- "framework-protos",
- "androidx.test.rules",
- "mockito-target-minus-junit4",
- "net-tests-utils",
- "platform-test-annotations",
- "services.core",
- "services.net",
- ],
- libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
- ],
jni_libs: [
"ld-android",
"libartbase",
@@ -44,20 +28,20 @@
"libnativehelper",
"libnetdbpf",
"libnetdutils",
+ "libnetworkstatsfactorytestjni",
"libpackagelistparser",
"libpcre2",
"libprocessgroup",
"libselinux",
- "libui",
- "libutils",
- "libvndksupport",
"libtinyxml2",
+ "libui",
"libunwindstack",
+ "libutils",
"libutilscallstack",
+ "libvndksupport",
"libziparchive",
"libz",
"netd_aidl_interface-V2-cpp",
- "libnetworkstatsfactorytestjni",
],
}
@@ -68,4 +52,20 @@
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "FrameworksNetCommonTests",
+ "frameworks-base-testutils",
+ "framework-protos",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "platform-test-annotations",
+ "services.core",
+ "services.net",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 4b86c82..e08cb16 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -208,6 +208,8 @@
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.testutils.ExceptionUtils;
import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.RecorderCallback.CallbackRecord;
+import com.android.testutils.TestableNetworkCallback;
import org.junit.After;
import org.junit.Before;
@@ -234,7 +236,6 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -243,7 +244,8 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Predicate;
+
+import kotlin.reflect.KClass;
/**
* Tests for {@link ConnectivityService}.
@@ -467,7 +469,7 @@
fail("expected race condition at least once in " + attempts + " attempts");
}
- private class MockNetworkAgent {
+ private class MockNetworkAgent implements TestableNetworkCallback.HasNetwork {
private static final int VALIDATION_RESULT_BASE = NETWORK_VALIDATION_PROBE_DNS
| NETWORK_VALIDATION_PROBE_HTTP
| NETWORK_VALIDATION_PROBE_HTTPS;
@@ -1703,281 +1705,33 @@
mCm.getDefaultRequest().networkCapabilities));
}
- enum CallbackState {
- NONE,
- AVAILABLE,
- NETWORK_CAPABILITIES,
- LINK_PROPERTIES,
- SUSPENDED,
- RESUMED,
- LOSING,
- LOST,
- UNAVAILABLE,
- BLOCKED_STATUS
- }
-
- private static class CallbackInfo {
- public final CallbackState state;
- public final Network network;
- public final Object arg;
- public CallbackInfo(CallbackState s, Network n, Object o) {
- state = s; network = n; arg = o;
- }
- public String toString() {
- return String.format("%s (%s) (%s)", state, network, arg);
- }
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof CallbackInfo)) return false;
- // Ignore timeMs, since it's unpredictable.
- CallbackInfo other = (CallbackInfo) o;
- return (state == other.state) && Objects.equals(network, other.network);
- }
- @Override
- public int hashCode() {
- return Objects.hash(state, network);
- }
- }
-
/**
* Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
* this class receives, by calling expectCallback() exactly once each time a callback is
* received. assertNoCallback may be called at any time.
*/
- private class TestNetworkCallback extends NetworkCallback {
- private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
- private Network mLastAvailableNetwork;
-
- protected void setLastCallback(CallbackState state, Network network, Object o) {
- mCallbacks.offer(new CallbackInfo(state, network, o));
+ private class TestNetworkCallback extends TestableNetworkCallback {
+ @Override
+ public void assertNoCallback() {
+ // TODO: better support this use case in TestableNetworkCallback
+ waitForIdle();
+ assertNoCallback(0 /* timeout */);
}
@Override
- public void onAvailable(Network network) {
- mLastAvailableNetwork = network;
- setLastCallback(CallbackState.AVAILABLE, network, null);
- }
-
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
- setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
- setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
- }
-
- @Override
- public void onUnavailable() {
- setLastCallback(CallbackState.UNAVAILABLE, null, null);
- }
-
- @Override
- public void onNetworkSuspended(Network network) {
- setLastCallback(CallbackState.SUSPENDED, network, null);
- }
-
- @Override
- public void onNetworkResumed(Network network) {
- setLastCallback(CallbackState.RESUMED, network, null);
- }
-
- @Override
- public void onLosing(Network network, int maxMsToLive) {
- setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
- }
-
- @Override
- public void onLost(Network network) {
- mLastAvailableNetwork = null;
- setLastCallback(CallbackState.LOST, network, null);
- }
-
- @Override
- public void onBlockedStatusChanged(Network network, boolean blocked) {
- setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked);
- }
-
- public Network getLastAvailableNetwork() {
- return mLastAvailableNetwork;
- }
-
- CallbackInfo nextCallback(int timeoutMs) throws InterruptedException {
- CallbackInfo cb = null;
- cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
- if (cb == null) {
- // LinkedBlockingQueue.poll() returns null if it timeouts.
- fail("Did not receive callback after " + timeoutMs + "ms");
- }
- return cb;
- }
-
- CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs)
- throws Exception {
- final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
- CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
- CallbackInfo actual = nextCallback(timeoutMs);
- assertEquals("Unexpected callback:", expected, actual);
-
- if (state == CallbackState.LOSING) {
+ public <T extends CallbackRecord> T expectCallback(final KClass<T> type, final HasNetwork n,
+ final long timeoutMs) {
+ final T callback = super.expectCallback(type, n, timeoutMs);
+ if (callback instanceof CallbackRecord.Losing) {
+ // TODO : move this to the specific test(s) needing this rather than here.
+ final CallbackRecord.Losing losing = (CallbackRecord.Losing) callback;
+ final int maxMsToLive = losing.getMaxMsToLive();
String msg = String.format(
"Invalid linger time value %d, must be between %d and %d",
- actual.arg, 0, mService.mLingerDelayMs);
- int maxMsToLive = (Integer) actual.arg;
+ maxMsToLive, 0, mService.mLingerDelayMs);
assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= mService.mLingerDelayMs);
}
-
- return actual;
- }
-
- CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) throws Exception {
- return expectCallback(state, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn) throws Exception {
- return expectCallbackLike(fn, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn, int timeoutMs)
- throws Exception {
- int timeLeft = timeoutMs;
- while (timeLeft > 0) {
- long start = SystemClock.elapsedRealtime();
- CallbackInfo info = nextCallback(timeLeft);
- if (fn.test(info)) {
- return info;
- }
- timeLeft -= (SystemClock.elapsedRealtime() - start);
- }
- fail("Did not receive expected callback after " + timeoutMs + "ms");
- return null;
- }
-
- // Expects onAvailable and the callbacks that follow it. These are:
- // - onSuspended, iff the network was suspended when the callbacks fire.
- // - onCapabilitiesChanged.
- // - onLinkPropertiesChanged.
- // - onBlockedStatusChanged.
- //
- // @param agent the network to expect the callbacks on.
- // @param expectSuspended whether to expect a SUSPENDED callback.
- // @param expectValidated the expected value of the VALIDATED capability in the
- // onCapabilitiesChanged callback.
- // @param timeoutMs how long to wait for the callbacks.
- void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended,
- boolean expectValidated, boolean expectBlocked, int timeoutMs) throws Exception {
- expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
- if (expectSuspended) {
- expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
- }
- if (expectValidated) {
- expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
- } else {
- expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
- }
- expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
- expectBlockedStatusCallback(expectBlocked, agent);
- }
-
- // Expects the available callbacks (validated), plus onSuspended.
- void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent, boolean expectValidated)
- throws Exception {
- expectAvailableCallbacks(agent, true, expectValidated, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksValidated(MockNetworkAgent agent)
- throws Exception {
- expectAvailableCallbacks(agent, false, true, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksValidatedAndBlocked(MockNetworkAgent agent) throws Exception {
- expectAvailableCallbacks(agent, false, true, true, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksUnvalidated(MockNetworkAgent agent) throws Exception {
- expectAvailableCallbacks(agent, false, false, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksUnvalidatedAndBlocked(MockNetworkAgent agent)
- throws Exception {
- expectAvailableCallbacks(agent, false, false, true, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- // Expects the available callbacks (where the onCapabilitiesChanged must contain the
- // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the
- // one we just sent.
- // TODO: this is likely a bug. Fix it and remove this method.
- void expectAvailableDoubleValidatedCallbacks(MockNetworkAgent agent) throws Exception {
- expectCallback(CallbackState.AVAILABLE, agent, TEST_CALLBACK_TIMEOUT_MS);
- NetworkCapabilities nc1 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- expectCallback(CallbackState.LINK_PROPERTIES, agent, TEST_CALLBACK_TIMEOUT_MS);
- // Implicitly check the network is allowed to use.
- // TODO: should we need to consider if network is in blocked status in this case?
- expectBlockedStatusCallback(false, agent);
- NetworkCapabilities nc2 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- assertEquals(nc1, nc2);
- }
-
- // Expects the available callbacks where the onCapabilitiesChanged must not have validated,
- // then expects another onCapabilitiesChanged that has the validated bit set. This is used
- // when a network connects and satisfies a callback, and then immediately validates.
- void expectAvailableThenValidatedCallbacks(MockNetworkAgent agent) throws Exception {
- expectAvailableCallbacksUnvalidated(agent);
- expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- }
-
- NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent)
- throws Exception {
- return expectCapabilitiesWith(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent,
- int timeoutMs) throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
- NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
- assertTrue(nc.hasCapability(capability));
- return nc;
- }
-
- NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent)
- throws Exception {
- return expectCapabilitiesWithout(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent,
- int timeoutMs) throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
- NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
- assertFalse(nc.hasCapability(capability));
- return nc;
- }
-
- void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent)
- throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
- assertTrue("Received capabilities don't match expectations : " + cbi.arg,
- fn.test((NetworkCapabilities) cbi.arg));
- }
-
- void expectLinkPropertiesLike(Predicate<LinkProperties> fn, MockNetworkAgent agent)
- throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.LINK_PROPERTIES, agent);
- assertTrue("Received LinkProperties don't match expectations : " + cbi.arg,
- fn.test((LinkProperties) cbi.arg));
- }
-
- void expectBlockedStatusCallback(boolean expectBlocked, MockNetworkAgent agent)
- throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.BLOCKED_STATUS, agent);
- boolean actualBlocked = (boolean) cbi.arg;
- assertEquals(expectBlocked, actualBlocked);
- }
-
- void assertNoCallback() {
- waitForIdle();
- CallbackInfo c = mCallbacks.peek();
- assertNull("Unexpected callback: " + c, c);
+ return callback;
}
}
@@ -2031,16 +1785,16 @@
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
cellNetworkCallback.assertNoCallback();
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -2061,21 +1815,21 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
}
@@ -2115,7 +1869,7 @@
// We then get LOSING when wifi validates and cell is outscored.
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -2124,15 +1878,15 @@
mEthernetNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2148,7 +1902,7 @@
newNetwork = mWiFiNetworkAgent;
}
- callback.expectCallback(CallbackState.LOSING, oldNetwork);
+ callback.expectCallback(CallbackRecord.LOSING, oldNetwork);
// TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
// longer lingering?
defaultCallback.expectAvailableCallbacksValidated(newNetwork);
@@ -2162,7 +1916,7 @@
// We expect a notification about the capabilities change, and nothing else.
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
defaultCallback.assertNoCallback();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Wifi no longer satisfies our listen, which is for an unmetered network.
@@ -2171,11 +1925,11 @@
// Disconnect our test networks.
mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
@@ -2206,8 +1960,8 @@
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2218,15 +1972,15 @@
mWiFiNetworkAgent.adjustScore(50);
mWiFiNetworkAgent.connect(false); // Score: 70
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2237,19 +1991,19 @@
mWiFiNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
@@ -2264,7 +2018,7 @@
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2275,13 +2029,13 @@
// TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer
// lingering?
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Similar to the above: lingering can start even after the lingered request is removed.
// Disconnect wifi and switch to cell.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2300,12 +2054,12 @@
callback.assertNoCallback();
// Now unregister cellRequest and expect cell to start lingering.
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Let linger run its course.
callback.assertNoCallback();
final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent, lingerTimeoutMs);
// Register a TRACK_DEFAULT request and check that it does not affect lingering.
TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
@@ -2314,20 +2068,20 @@
mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
mEthernetNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Let linger run its course.
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
// Clean up.
mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- trackDefaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ trackDefaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(defaultCallback);
@@ -2357,7 +2111,7 @@
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// File a request for cellular, then release it.
@@ -2366,7 +2120,7 @@
NetworkCallback noopCallback = new NetworkCallback();
mCm.requestNetwork(cellRequest, noopCallback);
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Let linger run its course.
callback.assertNoCallback();
@@ -2410,12 +2164,12 @@
// If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to
// wifi even though it's unvalidated.
mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Disconnect wifi, and then reconnect, again with explicitlySelected=true.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.explicitlySelected(true, false);
mWiFiNetworkAgent.connect(false);
@@ -2424,14 +2178,14 @@
// If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
// network to disconnect.
mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false);
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Reconnect, again with explicitlySelected=true, but this time validate.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.explicitlySelected(true, false);
mWiFiNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -2447,20 +2201,20 @@
// (i.e., with explicitlySelected=true and acceptUnvalidated=true). Expect to switch to
// wifi immediately.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.explicitlySelected(true, true);
mWiFiNetworkAgent.connect(false);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mEthernetNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
// Disconnect and reconnect with explicitlySelected=false and acceptUnvalidated=true.
// Check that the network is not scored specially and that the device prefers cell data.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.explicitlySelected(false, true);
mWiFiNetworkAgent.connect(false);
@@ -2471,8 +2225,8 @@
mWiFiNetworkAgent.disconnect();
mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
}
private int[] makeIntArray(final int size, final int value) {
@@ -2721,7 +2475,7 @@
// Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
// validated.
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED,
mWiFiNetworkAgent);
assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
@@ -2729,7 +2483,7 @@
// Disconnect and reconnect wifi with partial connectivity again.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connectWithPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2741,7 +2495,7 @@
// If the user chooses no, disconnect wifi immediately.
mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), false/* accept */,
false /* always */);
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// If user accepted partial connectivity before, and device reconnects to that network
// again, but now the network has full connectivity. The network shouldn't contain
@@ -2758,14 +2512,14 @@
waitForIdle();
verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
// Wifi should be the default network.
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// The user accepted partial connectivity and selected "don't ask again". Now the user
// reconnects to the partial connectivity network. Switch to wifi as soon as partial
@@ -2780,7 +2534,7 @@
waitForIdle();
verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
mWiFiNetworkAgent.setNetworkValid();
@@ -2790,7 +2544,7 @@
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// If the user accepted partial connectivity, and the device auto-reconnects to the partial
// connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED.
@@ -2805,11 +2559,11 @@
waitForIdle();
verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(
NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
}
@Test
@@ -2851,7 +2605,7 @@
false /* always */);
waitForIdle();
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
NetworkCapabilities nc =
validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
@@ -2884,7 +2638,7 @@
// Take down network.
// Expect onLost callback.
mWiFiNetworkAgent.disconnect();
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Bring up a network with a captive portal.
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
@@ -2898,7 +2652,7 @@
// Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
mWiFiNetworkAgent.setNetworkValid();
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -2910,7 +2664,7 @@
// Expect NET_CAPABILITY_VALIDATED onLost callback.
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
- validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
}
@Test
@@ -2942,7 +2696,7 @@
mWiFiNetworkAgent.setNetworkPortal("http://example.com");
mCm.reportNetworkConnectivity(wifiNetwork, false);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
mCm.startCaptivePortalApp(wifiNetwork);
@@ -2963,7 +2717,7 @@
mWiFiNetworkAgent.setNetworkValid();
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
verify(mNotificationManager, times(1)).notifyAsUser(anyString(),
eq(NotificationType.LOGGED_IN.eventId), any(), eq(UserHandle.ALL));
@@ -3103,24 +2857,24 @@
mWiFiNetworkAgent.setNetworkSpecifier(nsFoo);
cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo),
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
}
- cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo),
- mWiFiNetworkAgent);
+ cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
assertEquals(nsFoo,
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cFoo.assertNoCallback();
mWiFiNetworkAgent.setNetworkSpecifier(nsBar);
- cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ cFoo.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar),
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsBar));
}
- cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar),
- mWiFiNetworkAgent);
+ cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsBar));
assertEquals(nsBar,
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cBar.assertNoCallback();
@@ -3128,23 +2882,23 @@
mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier());
cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c : emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
}
- cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
- cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
+ cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
+ cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
assertNull(
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cFoo.assertNoCallback();
cBar.assertNoCallback();
mWiFiNetworkAgent.setNetworkSpecifier(null);
- cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ cFoo.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ cBar.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+ c.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, mWiFiNetworkAgent);
}
assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
@@ -3287,7 +3041,7 @@
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -3302,11 +3056,11 @@
// followed by AVAILABLE cell.
mWiFiNetworkAgent.disconnect();
cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
@@ -3322,7 +3076,7 @@
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
vpnNetworkAgent.disconnect();
- defaultNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
}
@@ -3350,14 +3104,15 @@
lp.setInterfaceName("foonet_data0");
mCellNetworkAgent.sendLinkProperties(lp);
// We should get onLinkPropertiesChanged().
- cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
+ mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Suspend the network.
mCellNetworkAgent.suspend();
cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.SUSPENDED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Register a garden variety default network request.
@@ -3372,7 +3127,7 @@
mCellNetworkAgent.resume();
cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.RESUMED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.RESUMED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback = new TestNetworkCallback();
@@ -3435,10 +3190,10 @@
// When wifi connects, cell lingers.
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -3446,7 +3201,7 @@
// When lingering is complete, cell is still there but is now in the background.
waitForIdle();
int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
+ fgCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent, timeoutMs);
// Expect a network capabilities update sans FOREGROUND.
callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
@@ -3472,7 +3227,7 @@
// Release the request. The network immediately goes into the background, since it was not
// lingering.
mCm.unregisterNetworkCallback(cellCallback);
- fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
// Expect a network capabilities update sans FOREGROUND.
callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
@@ -3480,8 +3235,8 @@
// Disconnect wifi and check that cell is foreground again.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
@@ -3618,7 +3373,7 @@
testFactory.waitForNetworkRequests(1);
// ... and cell data to be torn down.
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
assertLength(1, mCm.getAllNetworks());
testFactory.unregister();
@@ -3709,7 +3464,7 @@
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(wifiNetwork, false);
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedWifiCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Because avoid bad wifi is off, we don't switch to cellular.
defaultCallback.assertNoCallback();
@@ -3753,7 +3508,7 @@
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(wifiNetwork, false);
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedWifiCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
@@ -3780,7 +3535,7 @@
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
validatedWifiCallback.assertNoCallback();
@@ -3845,7 +3600,7 @@
networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
TEST_CALLBACK_TIMEOUT_MS);
mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
@@ -3865,7 +3620,7 @@
mCm.requestNetwork(nr, networkCallback, timeoutMs);
// pass timeout and validate that UNAVAILABLE is called
- networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+ networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null);
// create a network satisfying request - validate that request not triggered
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -3956,7 +3711,7 @@
// Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
testFactory.triggerUnfulfillable(requests.get(newRequestId));
- networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+ networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null);
testFactory.waitForRequests();
// unregister network callback - a no-op (since already freed by the
@@ -4797,7 +4552,7 @@
// Disconnect wifi aware network.
wifiAware.disconnect();
- callback.expectCallbackLike((info) -> info.state == CallbackState.LOST, TIMEOUT_MS);
+ callback.expectCallbackThat(TIMEOUT_MS, (info) -> info instanceof CallbackRecord.Lost);
mCm.unregisterNetworkCallback(callback);
verifyNoNetwork();
@@ -4846,14 +4601,15 @@
// ConnectivityService.
MockNetworkAgent networkAgent = new MockNetworkAgent(TRANSPORT_WIFI, lp);
networkAgent.connect(true);
- networkCallback.expectCallback(CallbackState.AVAILABLE, networkAgent);
- networkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, networkAgent);
- CallbackInfo cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ networkCallback.expectCallback(CallbackRecord.AVAILABLE, networkAgent);
+ networkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, networkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi =
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
networkAgent);
- networkCallback.expectCallback(CallbackState.BLOCKED_STATUS, networkAgent);
+ networkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, networkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.arg, Arrays.asList(myIpv4Address),
+ checkDirectlyConnectedRoutes(cbi.getLp(), Arrays.asList(myIpv4Address),
Arrays.asList(myIpv4DefaultRoute));
checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
@@ -4865,9 +4621,9 @@
newLp.addLinkAddress(myIpv6Address1);
newLp.addLinkAddress(myIpv6Address2);
networkAgent.sendLinkProperties(newLp);
- cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, networkAgent);
+ cbi = networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, networkAgent);
networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.arg,
+ checkDirectlyConnectedRoutes(cbi.getLp(),
Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
Arrays.asList(myIpv4DefaultRoute));
mCm.unregisterNetworkCallback(networkCallback);
@@ -5071,15 +4827,15 @@
assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
new String[] { "2001:db8::1", "192.0.2.1" }));
reset(mMockDnsResolver);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
+ cellNetworkCallback.expectCallback(CallbackRecord.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED,
mCellNetworkAgent);
- CallbackInfo cbi = cellNetworkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.BLOCKED_STATUS, mCellNetworkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
verify(mMockDnsResolver, times(1)).setResolverConfiguration(
@@ -5107,11 +4863,11 @@
setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
// Can't test dns configuration for strict mode without properly mocking
// out the DNS lookups, but can test that LinkProperties is updated.
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertEquals("strict.example.com", ((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
}
@Test
@@ -5130,17 +4886,17 @@
mCellNetworkAgent.sendLinkProperties(lp);
mCellNetworkAgent.connect(false);
waitForIdle();
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
+ cellNetworkCallback.expectCallback(CallbackRecord.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED,
mCellNetworkAgent);
- CallbackInfo cbi = cellNetworkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.BLOCKED_STATUS, mCellNetworkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
Set<InetAddress> dnsServers = new HashSet<>();
- checkDnsServers(cbi.arg, dnsServers);
+ checkDnsServers(cbi.getLp(), dnsServers);
// Send a validation event for a server that is not part of the current
// resolver config. The validation event should be ignored.
@@ -5152,13 +4908,13 @@
LinkProperties lp2 = new LinkProperties(lp);
lp2.addDnsServer(InetAddress.getByName("145.100.185.16"));
mCellNetworkAgent.sendLinkProperties(lp2);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
dnsServers.add(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.arg, dnsServers);
+ checkDnsServers(cbi.getLp(), dnsServers);
// Send a validation event containing a hostname that is not part of
// the current resolver config. The validation event should be ignored.
@@ -5176,39 +4932,39 @@
// private dns fields should be sent.
mService.mNetdEventCallback.onPrivateDnsValidationEvent(
mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
- checkDnsServers(cbi.arg, dnsServers);
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
+ checkDnsServers(cbi.getLp(), dnsServers);
// The private dns fields in LinkProperties should be preserved when
// the network agent sends unrelated changes.
LinkProperties lp3 = new LinkProperties(lp2);
lp3.setMtu(1300);
mCellNetworkAgent.sendLinkProperties(lp3);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
- checkDnsServers(cbi.arg, dnsServers);
- assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
+ checkDnsServers(cbi.getLp(), dnsServers);
+ assertEquals(1300, cbi.getLp().getMtu());
// Removing the only validated server should affect the private dns
// fields in LinkProperties.
LinkProperties lp4 = new LinkProperties(lp3);
lp4.removeDnsServer(InetAddress.getByName("145.100.185.16"));
mCellNetworkAgent.sendLinkProperties(lp4);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
dnsServers.remove(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.arg, dnsServers);
- assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
+ checkDnsServers(cbi.getLp(), dnsServers);
+ assertEquals(1300, cbi.getLp().getMtu());
}
private void checkDirectlyConnectedRoutes(Object callbackObj,
@@ -5290,19 +5046,19 @@
defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent, nc -> null == nc.getUids());
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
ranges.clear();
vpnNetworkAgent.setUids(ranges);
- genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
// TODO : The default network callback should actually get a LOST call here (also see the
// comment below for AVAILABLE). This is because ConnectivityService does not look at UID
@@ -5310,7 +5066,7 @@
// can't currently update their UIDs without disconnecting, so this does not matter too
// much, but that is the reason the test here has to check for an update to the
// capabilities instead of the expected LOST then AVAILABLE.
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
ranges.add(new UidRange(uid, uid));
mMockVpn.setUids(ranges);
@@ -5322,23 +5078,23 @@
vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
// TODO : Here like above, AVAILABLE would be correct, but because this can't actually
// happen outside of the test, ConnectivityService does not rematch callbacks.
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ genericNotVpnNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(genericNetworkCallback);
@@ -5402,7 +5158,7 @@
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
vpnNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
mCm.unregisterNetworkCallback(defaultCallback);
@@ -5432,7 +5188,7 @@
// Even though the VPN is unvalidated, it becomes the default network for our app.
callback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
// TODO: this looks like a spurious callback.
- callback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ callback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
callback.assertNoCallback();
assertTrue(vpnNetworkAgent.getScore() > mEthernetNetworkAgent.getScore());
@@ -5456,7 +5212,7 @@
callback.assertNoCallback();
vpnNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent);
}
@@ -5496,10 +5252,10 @@
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
@@ -5508,52 +5264,52 @@
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Don't disconnect, but note the VPN is not using wifi any more.
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Use Wifi but not cell. Note the VPN is now unmetered.
mService.setUnderlyingNetworksForVpn(
new Network[] { mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Use both again.
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect cell. Receive update without even removing the dead network from the
// underlying networks – it's dead anyway. Not metered any more.
mCellNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect wifi too. No underlying networks means this is now metered.
mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
mMockVpn.disconnect();
}
@@ -5592,20 +5348,20 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Connect to WiFi; WiFi is the new default.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect Cell. The default network did not change, so there shouldn't be any changes in
// the capabilities.
@@ -5614,10 +5370,10 @@
// Disconnect wifi too. Now we have no default network.
mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
mMockVpn.disconnect();
}
@@ -5893,7 +5649,7 @@
// Switch to METERED network. Restrict the use of the network.
mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellNetworkAgent);
// Network becomes NOT_METERED.
@@ -5907,7 +5663,7 @@
defaultCallback.assertNoCallback();
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultCallback.assertNoCallback();
mCm.unregisterNetworkCallback(defaultCallback);
@@ -5983,7 +5739,7 @@
// the NAT64 prefix was removed because one was never discovered.
cellLp.addLinkAddress(myIpv4);
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
@@ -5996,7 +5752,7 @@
cellLp.removeLinkAddress(myIpv4);
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
// When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
@@ -6004,15 +5760,15 @@
assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
kNat64PrefixString, 96);
- LinkProperties lpBeforeClat = (LinkProperties) networkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent).arg;
+ LinkProperties lpBeforeClat = networkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
assertEquals(0, lpBeforeClat.getStackedLinks().size());
assertEquals(kNat64Prefix, lpBeforeClat.getNat64Prefix());
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
.getStackedLinks();
assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
@@ -6020,7 +5776,7 @@
// Change trivial linkproperties and see if stacked link is preserved.
cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
List<LinkProperties> stackedLpsAfterChange =
mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
@@ -6038,12 +5794,12 @@
cellLp.addLinkAddress(myIpv4);
cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
// As soon as stop is called, the linkproperties lose the stacked interface.
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
LinkProperties expected = new LinkProperties(cellLp);
expected.setNat64Prefix(kNat64Prefix);
@@ -6062,41 +5818,39 @@
// Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
kNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesLike((lp) -> lp.getNat64Prefix() == null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getNat64Prefix() == null);
// Remove IPv4 address and expect prefix discovery and clatd to be started again.
cellLp.removeLinkAddress(myIpv4);
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
kNat64PrefixString, 96);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesLike(
- (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
// NAT64 prefix is removed. Expect that clat is stopped.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
kNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesLike(
- (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- networkCallback.expectLinkPropertiesLike((lp) -> lp.getStackedLinks().size() == 0,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 0);
// Clean up.
mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
networkCallback.assertNoCallback();
mCm.unregisterNetworkCallback(networkCallback);
}
@@ -6128,7 +5882,7 @@
reset(mNetworkManagementService);
mWiFiNetworkAgent.connect(true);
networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(),
eq(ConnectivityManager.TYPE_WIFI));
@@ -6137,7 +5891,7 @@
// Disconnect wifi and switch back to cell
reset(mNetworkManagementService);
mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertNoCallbacks(networkCallback);
verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
@@ -6149,14 +5903,14 @@
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
mWiFiNetworkAgent.connect(true);
networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// Disconnect cell
reset(mNetworkManagementService);
reset(mMockNetd);
mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
// LOST callback is triggered earlier than removing idle timer. Broadcast should also be
// sent as network being switched. Ensure rule removal for cell will not be triggered
// unexpectedly before network being removed.
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 6c42ac3..8c522f4 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -100,6 +100,8 @@
import android.os.test.TestLooper;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
import androidx.test.filters.SmallTest;
@@ -111,6 +113,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.OffloadHardwareInterface;
+import com.android.server.connectivity.tethering.TetheringConfiguration;
import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
@@ -118,6 +121,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -147,6 +151,7 @@
@Mock private MockableSystemProperties mSystemProperties;
@Mock private OffloadHardwareInterface mOffloadHardwareInterface;
@Mock private Resources mResources;
+ @Mock private TelephonyManager mTelephonyManager;
@Mock private UsbManager mUsbManager;
@Mock private WifiManager mWifiManager;
@Mock private CarrierConfigManager mCarrierConfigManager;
@@ -171,6 +176,7 @@
private MockContentResolver mContentResolver;
private BroadcastReceiver mBroadcastReceiver;
private Tethering mTethering;
+ private PhoneStateListener mPhoneStateListener;
private class MockContext extends BroadcastInterceptingContext {
MockContext(Context base) {
@@ -193,6 +199,7 @@
public Object getSystemService(String name) {
if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
if (Context.USB_SERVICE.equals(name)) return mUsbManager;
+ if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
return super.getSystemService(name);
}
}
@@ -234,6 +241,17 @@
}
}
+ private class MockTetheringConfiguration extends TetheringConfiguration {
+ MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
+ super(ctx, log, id);
+ }
+
+ @Override
+ protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
+ return mResources;
+ }
+ }
+
public class MockTetheringDependencies extends TetheringDependencies {
StateMachine upstreamNetworkMonitorMasterSM;
ArrayList<IpServer> ipv6CoordinatorNotifyList;
@@ -276,8 +294,9 @@
}
@Override
- public int getDefaultDataSubscriptionId() {
- return INVALID_SUBSCRIPTION_ID;
+ public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
+ int subId) {
+ return new MockTetheringConfiguration(ctx, log, subId);
}
}
@@ -372,6 +391,11 @@
mTetheringDependencies.reset();
mTethering = makeTethering();
verify(mNMService).registerTetheringStatsProvider(any(), anyString());
+ final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
+ ArgumentCaptor.forClass(PhoneStateListener.class);
+ verify(mTelephonyManager).listen(phoneListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE));
+ mPhoneStateListener = phoneListenerCaptor.getValue();
}
private Tethering makeTethering() {
@@ -982,6 +1006,17 @@
callback2.expectUpstreamChanged(upstreamState.network);
}
+ @Test
+ public void testMultiSimAware() throws Exception {
+ final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration();
+ assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.subId);
+
+ final int fakeSubId = 1234;
+ mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
+ final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration();
+ assertEquals(fakeSubId, newConfig.subId);
+ }
+
// TODO: Test that a request for hotspot mode doesn't interfere with an
// already operating tethering mode interface.
}
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 2140322..e282963 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -29,6 +29,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
@@ -141,7 +142,7 @@
@Test
public void testDunFromTelephonyManagerMeansDun() {
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(true);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(true);
final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
@@ -165,7 +166,7 @@
@Test
public void testDunNotRequiredFromTelephonyManagerMeansNoDun() {
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
@@ -208,7 +209,7 @@
@Test
public void testNoDefinedUpstreamTypesAddsEthernet() {
when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{});
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -231,7 +232,7 @@
public void testDefinedUpstreamTypesSansEthernetAddsEthernet() {
when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(
new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI});
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -249,7 +250,7 @@
public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() {
when(mResources.getIntArray(config_tether_upstream_types))
.thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI});
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp
index ef1ad2c..84ae2b5 100644
--- a/tests/net/smoketest/Android.bp
+++ b/tests/net/smoketest/Android.bp
@@ -14,4 +14,9 @@
defaults: ["FrameworksNetTests-jni-defaults"],
srcs: ["java/SmokeTest.java"],
test_suites: ["device-tests"],
-}
+ static_libs: [
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "services.core",
+ ],
+}
\ No newline at end of file