Merge "Brightness mirror - fix multi-touch issue"
diff --git a/api/current.txt b/api/current.txt
index 21fe3e2..21ff787 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -62850,7 +62850,10 @@
method public java.lang.String getComment();
method public long getCompressedSize();
method public long getCrc();
+ method public java.nio.file.attribute.FileTime getCreationTime();
method public byte[] getExtra();
+ method public java.nio.file.attribute.FileTime getLastAccessTime();
+ method public java.nio.file.attribute.FileTime getLastModifiedTime();
method public int getMethod();
method public java.lang.String getName();
method public long getSize();
@@ -62859,7 +62862,10 @@
method public void setComment(java.lang.String);
method public void setCompressedSize(long);
method public void setCrc(long);
+ method public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime);
method public void setExtra(byte[]);
+ method public java.util.zip.ZipEntry setLastAccessTime(java.nio.file.attribute.FileTime);
+ method public java.util.zip.ZipEntry setLastModifiedTime(java.nio.file.attribute.FileTime);
method public void setMethod(int);
method public void setSize(long);
method public void setTime(long);
@@ -62930,6 +62936,7 @@
method public java.io.InputStream getInputStream(java.util.zip.ZipEntry) throws java.io.IOException;
method public java.lang.String getName();
method public int size();
+ method public java.util.stream.Stream<? extends java.util.zip.ZipEntry> stream();
field public static final int CENATT = 36; // 0x24
field public static final int CENATX = 38; // 0x26
field public static final int CENCOM = 32; // 0x20
diff --git a/api/system-current.txt b/api/system-current.txt
index 974db45..6645d53 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -66207,7 +66207,10 @@
method public java.lang.String getComment();
method public long getCompressedSize();
method public long getCrc();
+ method public java.nio.file.attribute.FileTime getCreationTime();
method public byte[] getExtra();
+ method public java.nio.file.attribute.FileTime getLastAccessTime();
+ method public java.nio.file.attribute.FileTime getLastModifiedTime();
method public int getMethod();
method public java.lang.String getName();
method public long getSize();
@@ -66216,7 +66219,10 @@
method public void setComment(java.lang.String);
method public void setCompressedSize(long);
method public void setCrc(long);
+ method public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime);
method public void setExtra(byte[]);
+ method public java.util.zip.ZipEntry setLastAccessTime(java.nio.file.attribute.FileTime);
+ method public java.util.zip.ZipEntry setLastModifiedTime(java.nio.file.attribute.FileTime);
method public void setMethod(int);
method public void setSize(long);
method public void setTime(long);
@@ -66287,6 +66293,7 @@
method public java.io.InputStream getInputStream(java.util.zip.ZipEntry) throws java.io.IOException;
method public java.lang.String getName();
method public int size();
+ method public java.util.stream.Stream<? extends java.util.zip.ZipEntry> stream();
field public static final int CENATT = 36; // 0x24
field public static final int CENATX = 38; // 0x26
field public static final int CENCOM = 32; // 0x20
diff --git a/api/test-current.txt b/api/test-current.txt
index 29de7a5..5301443 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -62930,7 +62930,10 @@
method public java.lang.String getComment();
method public long getCompressedSize();
method public long getCrc();
+ method public java.nio.file.attribute.FileTime getCreationTime();
method public byte[] getExtra();
+ method public java.nio.file.attribute.FileTime getLastAccessTime();
+ method public java.nio.file.attribute.FileTime getLastModifiedTime();
method public int getMethod();
method public java.lang.String getName();
method public long getSize();
@@ -62939,7 +62942,10 @@
method public void setComment(java.lang.String);
method public void setCompressedSize(long);
method public void setCrc(long);
+ method public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime);
method public void setExtra(byte[]);
+ method public java.util.zip.ZipEntry setLastAccessTime(java.nio.file.attribute.FileTime);
+ method public java.util.zip.ZipEntry setLastModifiedTime(java.nio.file.attribute.FileTime);
method public void setMethod(int);
method public void setSize(long);
method public void setTime(long);
@@ -63010,6 +63016,7 @@
method public java.io.InputStream getInputStream(java.util.zip.ZipEntry) throws java.io.IOException;
method public java.lang.String getName();
method public int size();
+ method public java.util.stream.Stream<? extends java.util.zip.ZipEntry> stream();
field public static final int CENATT = 36; // 0x24
field public static final int CENATX = 38; // 0x26
field public static final int CENCOM = 32; // 0x20
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index a6ef25f..4dcb05e 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -50,7 +50,7 @@
IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService(
Context.USB_SERVICE));
try {
- usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null));
+ usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), false);
} catch (RemoteException e) {
System.err.println("Error communicating with UsbManager: " + e);
}
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 6e4c9de..00b0bff 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -87,15 +87,13 @@
/* Returns true if the specified USB function is enabled. */
boolean isFunctionEnabled(String function);
- /* Sets the current USB function. */
- void setCurrentFunction(String function);
-
- /* Sets whether USB data (for example, MTP exposed pictures) should be made
- * available on the USB connection. Unlocking data should only be done with
- * user involvement, since exposing pictures or other data could leak sensitive
- * user information.
+ /* Sets the current USB function as well as whether USB data
+ * (for example, MTP exposed pictures) should be made available
+ * on the USB connection. Unlocking data should only be done with
+ * user involvement, since exposing pictures or other data could
+ * leak sensitive user information.
*/
- void setUsbDataUnlocked(boolean unlock);
+ void setCurrentFunction(String function, boolean usbDataUnlocked);
/* Allow USB debugging from the attached host. If alwaysAllow is true, add the
* the public key to list of host keys that the user has approved.
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f9a7d19..6341cbc 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -509,33 +509,23 @@
* {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP},
* or {@link #USB_FUNCTION_RNDIS}.
* </p><p>
+ * Also sets whether USB data (for example, MTP exposed pictures) should be made available
+ * on the USB connection when in device mode. Unlocking usb data should only be done with
+ * user involvement, since exposing pictures or other data could leak sensitive
+ * user information.
+ * </p><p>
* Note: This function is asynchronous and may fail silently without applying
* the requested changes.
* </p>
*
* @param function name of the USB function, or null to restore the default function
+ * @param usbDataUnlocked whether user data is accessible
*
* {@hide}
*/
- public void setCurrentFunction(String function) {
+ public void setCurrentFunction(String function, boolean usbDataUnlocked) {
try {
- mService.setCurrentFunction(function);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Sets whether USB data (for example, MTP exposed pictures) should be made available
- * on the USB connection when in device mode. Unlocking usb data should only be done with
- * user involvement, since exposing pictures or other data could leak sensitive
- * user information.
- *
- * {@hide}
- */
- public void setUsbDataUnlocked(boolean unlocked) {
- try {
- mService.setUsbDataUnlocked(unlocked);
+ mService.setCurrentFunction(function, usbDataUnlocked);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/CountDownTimer.java b/core/java/android/os/CountDownTimer.java
index 58acbcf..c7bf0fd 100644
--- a/core/java/android/os/CountDownTimer.java
+++ b/core/java/android/os/CountDownTimer.java
@@ -125,19 +125,28 @@
if (millisLeft <= 0) {
onFinish();
- } else if (millisLeft < mCountdownInterval) {
- // no tick, just delay until done
- sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
long lastTickStart = SystemClock.elapsedRealtime();
onTick(millisLeft);
// take into account user's onTick taking time to execute
- long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
+ long lastTickDuration = SystemClock.elapsedRealtime() - lastTickStart;
+ long delay;
- // special case: user's onTick took more than interval to
- // complete, skip to next interval
- while (delay < 0) delay += mCountdownInterval;
+ if (millisLeft < mCountdownInterval) {
+ // just delay until done
+ delay = millisLeft - lastTickDuration;
+
+ // special case: user's onTick took more than interval to
+ // complete, trigger onFinish without delay
+ if (delay < 0) delay = 0;
+ } else {
+ delay = mCountdownInterval - lastTickDuration;
+
+ // special case: user's onTick took more than interval to
+ // complete, skip to next interval
+ while (delay < 0) delay += mCountdownInterval;
+ }
sendMessageDelayed(obtainMessage(MSG), delay);
}
diff --git a/core/jni/android_os_HwBlob.h b/core/jni/android_os_HwBlob.h
index 6bd82e9..0920488 100644
--- a/core/jni/android_os_HwBlob.h
+++ b/core/jni/android_os_HwBlob.h
@@ -20,6 +20,7 @@
#include <android-base/macros.h>
#include <jni.h>
#include <hidl/HidlSupport.h>
+#include <hwbinder/Parcel.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 1a67cee..a10d807 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -26,6 +26,7 @@
#include <JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
+#include <hidl/HidlTransportSupport.h>
#include <hidl/Status.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -383,7 +384,7 @@
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
- status_t err = status.writeToParcel(parcel);
+ status_t err = ::android::hardware::writeToParcel(status, parcel);
signalExceptionForError(env, err);
}
@@ -394,7 +395,7 @@
JHwParcel::GetNativeContext(env, thiz)->getParcel();
Status status;
- status_t err = status.readFromParcel(*parcel);
+ status_t err = ::android::hardware::readFromParcel(&status, *parcel);
signalExceptionForError(env, err);
}
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
index 9e45d09..d7b38e8 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.mk
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -19,8 +19,7 @@
LOCAL_SRC_FILES := \
com_android_frameworks_coretests_JNITest.cpp
-LOCAL_SHARED_LIBRARIES := \
- libnativehelper
+LOCAL_SDK_VERSION := 16
LOCAL_CFLAGS += -Wall -Werror
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
index 8d91192..0cf3a84 100644
--- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -14,41 +14,23 @@
* limitations under the License.
*/
-#include "nativehelper/JNIHelp.h"
+#include <jni.h>
-namespace android {
-
-static jint checkFunction(JNIEnv*, jclass) {
+extern "C" JNIEXPORT
+jint JNICALL Java_com_android_frameworks_coretests_JNITests_checkFunction(JNIEnv*, jclass) {
return 1;
}
-static const JNINativeMethod sMethods[] = {
- /* name, signature, funcPtr */
- { "checkFunction", "()I", (void*) checkFunction },
-};
-
-int register_com_android_frameworks_coretests_JNITests(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/frameworks/coretests/JNITests", sMethods,
- NELEM(sMethods));
-}
-
-}
-
/*
* JNI Initialization
*/
jint JNI_OnLoad(JavaVM *jvm, void */* reserved */) {
JNIEnv *e;
- int status;
// Check JNI version
if (jvm->GetEnv((void **) &e, JNI_VERSION_1_6)) {
return JNI_ERR;
}
- if ((status = android::register_com_android_frameworks_coretests_JNITests(e)) < 0) {
- return JNI_ERR;
- }
-
return JNI_VERSION_1_6;
}
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 3c1c0bc..0d9ede0 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -20,6 +20,7 @@
#include "CanvasContext.h"
#include "EglManager.h"
#include "RenderProxy.h"
+#include "utils/FatVector.h"
#include <gui/DisplayEventReceiver.h>
#include <gui/ISurfaceComposer.h>
@@ -282,10 +283,18 @@
"RenderThread Looper POLL_ERROR!");
nsecs_t nextWakeup;
- // Process our queue, if we have anything
- while (RenderTask* task = nextTask(&nextWakeup)) {
- task->run();
- // task may have deleted itself, do not reference it again
+ {
+ FatVector<RenderTask*, 10> workQueue;
+ // Process our queue, if we have anything. By first acquiring
+ // all the pending events then processing them we avoid vsync
+ // starvation if more tasks are queued while we are processing tasks.
+ while (RenderTask* task = nextTask(&nextWakeup)) {
+ workQueue.push_back(task);
+ }
+ for (auto task : workQueue) {
+ task->run();
+ // task may have deleted itself, do not reference it again
+ }
}
if (nextWakeup == LLONG_MAX) {
timeoutMillis = -1;
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index 84ef9c2..362890b 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -113,7 +113,7 @@
void BM_FrameBuilder_defer_scene(benchmark::State& state) {
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
- const char* sceneName = *(SCENES.begin() + state.range_x());
+ const char* sceneName = *(SCENES.begin() + state.range(0));
state.SetLabel(sceneName);
auto node = getSyncedSceneNode(sceneName);
while (state.KeepRunning()) {
@@ -129,7 +129,7 @@
void BM_FrameBuilder_deferAndRender_scene(benchmark::State& state) {
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
- const char* sceneName = *(SCENES.begin() + state.range_x());
+ const char* sceneName = *(SCENES.begin() + state.range(0));
state.SetLabel(sceneName);
auto node = getSyncedSceneNode(sceneName);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 9608daa..24ede16 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -116,6 +116,10 @@
List<BluetoothDevice> sinks = getConnectedDevices();
if (sinks != null) {
for (BluetoothDevice sink : sinks) {
+ if (sink.equals(device)) {
+ Log.w(TAG, "Connecting to device " + device + " : disconnect skipped");
+ continue;
+ }
mService.disconnect(sink);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b59f468..0f54d23 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6351,13 +6351,18 @@
removeLruProcessLocked(app);
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
Slog.w(TAG, "Unattached app died before backup, skipping");
- try {
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentDisconnected(app.info.packageName);
- } catch (RemoteException e) {
- // Can't happen; the backup manager is local
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run(){
+ try {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ bm.agentDisconnected(app.info.packageName);
+ } catch (RemoteException e) {
+ // Can't happen; the backup manager is local
+ }
+ }
+ });
}
if (isPendingBroadcastProcessLocked(pid)) {
Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
@@ -16766,13 +16771,18 @@
if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
+ mBackupTarget.appInfo + " died during backup");
- try {
- IBackupManager bm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentDisconnected(app.info.packageName);
- } catch (RemoteException e) {
- // can't happen; backup manager is local
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run(){
+ try {
+ IBackupManager bm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ bm.agentDisconnected(app.info.packageName);
+ } catch (RemoteException e) {
+ // can't happen; backup manager is local
+ }
+ }
+ });
}
for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index e888faa..cec4141 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -900,7 +900,7 @@
}
} else {
mUsbTetherRequested = true;
- usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS);
+ usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
}
} else {
final long ident = Binder.clearCallingIdentity();
@@ -910,7 +910,7 @@
Binder.restoreCallingIdentity(ident);
}
if (mRndisEnabled) {
- usbManager.setCurrentFunction(null);
+ usbManager.setCurrentFunction(null, false);
}
mUsbTetherRequested = false;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index dfd6dfe..99a6979 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1410,7 +1410,6 @@
VersionInfo ver = mVersion.get(volumeUuid);
if (ver == null) {
ver = new VersionInfo();
- ver.forceCurrent();
mVersion.put(volumeUuid, ver);
}
return ver;
@@ -2795,8 +2794,8 @@
"No settings file; creating initial state");
// It's enough to just touch version details to create them
// with default values
- findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL);
- findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL);
+ findOrCreateVersion(StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
+ findOrCreateVersion(StorageManager.UUID_PRIMARY_PHYSICAL).forceCurrent();
return false;
}
str = new FileInputStream(mSettingsFilename);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index df9242d..43b8fa5 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -108,9 +108,8 @@
private static final int MSG_SYSTEM_READY = 3;
private static final int MSG_BOOT_COMPLETED = 4;
private static final int MSG_USER_SWITCHED = 5;
- private static final int MSG_SET_USB_DATA_UNLOCKED = 6;
- private static final int MSG_UPDATE_USER_RESTRICTIONS = 7;
- private static final int MSG_UPDATE_HOST_STATE = 8;
+ private static final int MSG_UPDATE_USER_RESTRICTIONS = 6;
+ private static final int MSG_UPDATE_HOST_STATE = 7;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -287,7 +286,7 @@
if (functions != null) {
mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
- setCurrentFunctions(functions);
+ setCurrentFunctions(functions, false);
}
}
@@ -335,14 +334,22 @@
// Restore default functions.
mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
UsbManager.USB_FUNCTION_NONE);
- if (UsbManager.USB_FUNCTION_NONE.equals(mCurrentFunctions)) {
- mCurrentFunctions = UsbManager.USB_FUNCTION_MTP;
- }
mCurrentFunctionsApplied = mCurrentFunctions.equals(
SystemProperties.get(USB_STATE_PROPERTY));
mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(),
UsbManager.USB_FUNCTION_ADB);
- setEnabledFunctions(null, false);
+
+ /**
+ * Remove MTP from persistent config, to bring usb to a good state
+ * after fixes to b/31814300. This block can be removed after the update
+ */
+ String persisted = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY);
+ if (UsbManager.containsFunction(persisted, UsbManager.USB_FUNCTION_MTP)) {
+ SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY,
+ UsbManager.removeFunction(persisted, UsbManager.USB_FUNCTION_MTP));
+ }
+
+ setEnabledFunctions(null, false, false);
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
@@ -374,6 +381,14 @@
sendMessage(m);
}
+ public void sendMessage(int what, Object arg, boolean arg1) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.obj = arg;
+ m.arg1 = (arg1 ? 1 : 0);
+ sendMessage(m);
+ }
+
public void updateState(String state) {
int connected, configured;
@@ -427,29 +442,24 @@
return waitForState(config);
}
- private void setUsbDataUnlocked(boolean enable) {
- if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked: " + enable);
- mUsbDataUnlocked = enable;
- updateUsbNotification();
- updateUsbStateBroadcastIfNeeded();
- setEnabledFunctions(mCurrentFunctions, true);
- }
-
private void setAdbEnabled(boolean enable) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable != mAdbEnabled) {
mAdbEnabled = enable;
+ String oldFunctions = mCurrentFunctions;
- // Due to the persist.sys.usb.config property trigger, changing adb state requires
- // persisting default function
- String oldFunctions = getDefaultFunctions();
- String newFunctions = applyAdbFunction(oldFunctions);
- if (!oldFunctions.equals(newFunctions)) {
- SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunctions);
+ // Persist the adb setting
+ String newFunction = applyAdbFunction(SystemProperties.get(
+ USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE));
+ SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunction);
+
+ // Remove mtp from the config if file transfer is not enabled
+ if (oldFunctions.equals(UsbManager.USB_FUNCTION_MTP) &&
+ !mUsbDataUnlocked && enable) {
+ oldFunctions = UsbManager.USB_FUNCTION_NONE;
}
- // After persisting them use the lock-down aware function set
- setEnabledFunctions(mCurrentFunctions, false);
+ setEnabledFunctions(oldFunctions, true, mUsbDataUnlocked);
updateAdbNotification();
}
@@ -461,10 +471,17 @@
/**
* Evaluates USB function policies and applies the change accordingly.
*/
- private void setEnabledFunctions(String functions, boolean forceRestart) {
+ private void setEnabledFunctions(String functions, boolean forceRestart,
+ boolean usbDataUnlocked) {
if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+ "forceRestart=" + forceRestart);
+ if (usbDataUnlocked != mUsbDataUnlocked) {
+ mUsbDataUnlocked = usbDataUnlocked;
+ updateUsbNotification();
+ forceRestart = true;
+ }
+
// Try to set the enabled functions.
final String oldFunctions = mCurrentFunctions;
final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
@@ -501,7 +518,8 @@
}
private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
- if (functions == null) {
+ if (functions == null || applyAdbFunction(functions)
+ .equals(UsbManager.USB_FUNCTION_NONE)) {
functions = getDefaultFunctions();
}
functions = applyAdbFunction(functions);
@@ -566,7 +584,7 @@
// make sure accessory mode is off
// and restore default functions
Slog.d(TAG, "exited USB accessory mode");
- setEnabledFunctions(null, false);
+ setEnabledFunctions(null, false, false);
if (mCurrentAccessory != null) {
if (mBootCompleted) {
@@ -583,10 +601,6 @@
if (mBroadcastedIntent == null) {
for (String key : keySet) {
if (intent.getBooleanExtra(key, false)) {
- // MTP function is enabled by default.
- if (UsbManager.USB_FUNCTION_MTP.equals(key)) {
- continue;
- }
return true;
}
}
@@ -699,10 +713,7 @@
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
- if (!mConnected) {
- // When a disconnect occurs, relock access to sensitive user data
- mUsbDataUnlocked = false;
- }
+
updateUsbNotification();
updateAdbNotification();
if (UsbManager.containsFunction(mCurrentFunctions,
@@ -710,7 +721,7 @@
updateCurrentAccessory();
} else if (!mConnected) {
// restore defaults when USB is disconnected
- setEnabledFunctions(null, false);
+ setEnabledFunctions(null, false, false);
}
if (mBootCompleted) {
updateUsbStateBroadcastIfNeeded();
@@ -730,13 +741,10 @@
break;
case MSG_SET_CURRENT_FUNCTIONS:
String functions = (String)msg.obj;
- setEnabledFunctions(functions, false);
+ setEnabledFunctions(functions, false, msg.arg1 == 1);
break;
case MSG_UPDATE_USER_RESTRICTIONS:
- setEnabledFunctions(mCurrentFunctions, false);
- break;
- case MSG_SET_USB_DATA_UNLOCKED:
- setUsbDataUnlocked(msg.arg1 == 1);
+ setEnabledFunctions(mCurrentFunctions, false, mUsbDataUnlocked);
break;
case MSG_SYSTEM_READY:
updateUsbNotification();
@@ -764,8 +772,7 @@
Slog.v(TAG, "Current user switched to " + mCurrentUser
+ "; resetting USB host stack for MTP or PTP");
// avoid leaking sensitive data from previous user
- mUsbDataUnlocked = false;
- setEnabledFunctions(mCurrentFunctions, true);
+ setEnabledFunctions(mCurrentFunctions, true, false);
}
mCurrentUser = msg.arg1;
}
@@ -944,14 +951,10 @@
return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
}
- public void setCurrentFunctions(String functions) {
- if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
- mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
- }
-
- public void setUsbDataUnlocked(boolean unlocked) {
- if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")");
- mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked);
+ public void setCurrentFunctions(String functions, boolean usbDataUnlocked) {
+ if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ", " +
+ usbDataUnlocked + ")");
+ mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked);
}
private void readOemUsbOverrideConfig() {
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index d6dbe90..daccc00 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -287,7 +287,7 @@
}
@Override
- public void setCurrentFunction(String function) {
+ public void setCurrentFunction(String function, boolean usbDataUnlocked) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
if (!isSupportedCurrentFunction(function)) {
@@ -297,7 +297,7 @@
}
if (mDeviceManager != null) {
- mDeviceManager.setCurrentFunctions(function);
+ mDeviceManager.setCurrentFunctions(function, usbDataUnlocked);
} else {
throw new IllegalStateException("USB device mode not supported");
}
@@ -320,12 +320,6 @@
}
@Override
- public void setUsbDataUnlocked(boolean unlocked) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- mDeviceManager.setUsbDataUnlocked(unlocked);
- }
-
- @Override
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 66d704b..f177a41 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -515,9 +515,12 @@
final boolean isUnknown = args.argi2 == 1;
if (!mAreAccountsInitialized) {
Log.d(this, "Enqueueing pre-init request %s", id);
- mPreInitializationConnectionRequests.add(new Runnable() {
+ mPreInitializationConnectionRequests.add(
+ new android.telecom.Logging.Runnable(
+ SESSION_HANDLER + SESSION_CREATE_CONN + ".pICR",
+ null /*lock*/) {
@Override
- public void run() {
+ public void loggedRun() {
createConnection(
connectionManagerPhoneAccount,
id,
@@ -525,7 +528,7 @@
isIncoming,
isUnknown);
}
- });
+ }.prepare());
} else {
createConnection(
connectionManagerPhoneAccount,
@@ -1378,9 +1381,9 @@
public void onResult(
final List<ComponentName> componentNames,
final List<IBinder> services) {
- mHandler.post(new Runnable() {
+ mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oR", null /*lock*/) {
@Override
- public void run() {
+ public void loggedRun() {
for (int i = 0; i < componentNames.size() && i < services.size(); i++) {
mRemoteConnectionManager.addConnectionService(
componentNames.get(i),
@@ -1389,17 +1392,17 @@
onAccountsInitialized();
Log.d(this, "remote connection services found: " + services);
}
- });
+ }.prepare());
}
@Override
public void onError() {
- mHandler.post(new Runnable() {
+ mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oE", null /*lock*/) {
@Override
- public void run() {
+ public void loggedRun() {
mAreAccountsInitialized = true;
}
- });
+ }.prepare());
}
});
}
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 446bbbb..ced6627 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -48,13 +48,13 @@
// Generic tag for all Telecom logging
@VisibleForTesting
public static String TAG = "TelecomFramework";
+ public static boolean DEBUG = isLoggable(android.util.Log.DEBUG);
+ public static boolean INFO = isLoggable(android.util.Log.INFO);
+ public static boolean VERBOSE = isLoggable(android.util.Log.VERBOSE);
+ public static boolean WARN = isLoggable(android.util.Log.WARN);
+ public static boolean ERROR = isLoggable(android.util.Log.ERROR);
private static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */
- public static final boolean DEBUG = isLoggable(android.util.Log.DEBUG);
- public static final boolean INFO = isLoggable(android.util.Log.INFO);
- public static final boolean VERBOSE = isLoggable(android.util.Log.VERBOSE);
- public static final boolean WARN = isLoggable(android.util.Log.WARN);
- public static final boolean ERROR = isLoggable(android.util.Log.ERROR);
// Used to synchronize singleton logging lazy initialization
private static final Object sSingletonSync = new Object();
@@ -340,6 +340,11 @@
public static void setTag(String tag) {
TAG = tag;
+ DEBUG = isLoggable(android.util.Log.DEBUG);
+ INFO = isLoggable(android.util.Log.INFO);
+ VERBOSE = isLoggable(android.util.Log.VERBOSE);
+ WARN = isLoggable(android.util.Log.WARN);
+ ERROR = isLoggable(android.util.Log.ERROR);
}
/**
diff --git a/telecomm/java/android/telecom/Logging/Runnable.java b/telecomm/java/android/telecom/Logging/Runnable.java
index 56c52bf..6e81053 100644
--- a/telecomm/java/android/telecom/Logging/Runnable.java
+++ b/telecomm/java/android/telecom/Logging/Runnable.java
@@ -27,7 +27,7 @@
private Session mSubsession;
private final String mSubsessionName;
- private final Object mLock = new Object();
+ private final Object mLock;
private final java.lang.Runnable mRunnable = new java.lang.Runnable() {
@Override
public void run() {
@@ -45,7 +45,18 @@
}
};
- public Runnable(String subsessionName) {
+ /**
+ * Creates a new Telecom Runnable that incorporates Session Logging into it. Useful for carrying
+ * Logging Sessions through different threads as well as through handlers.
+ * @param subsessionName The name that will be used in the Logs to mark this Session
+ * @param lock The synchronization lock that will be used to lock loggedRun().
+ */
+ public Runnable(String subsessionName, Object lock) {
+ if (lock == null) {
+ mLock = new Object();
+ } else {
+ mLock = lock;
+ }
mSubsessionName = subsessionName;
}
@@ -85,4 +96,4 @@
*/
abstract public void loggedRun();
-}
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java
index 3a7b8c0..c45bd6b 100644
--- a/telecomm/java/android/telecom/Logging/Session.java
+++ b/telecomm/java/android/telecom/Logging/Session.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telecom.Log;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -26,20 +27,23 @@
import java.util.ArrayList;
/**
- * The session that stores information about a thread's point of entry into the Telecom code that
- * persists until the thread exits Telecom.
+ * Stores information about a thread's point of entry into that should persist until that thread
+ * exits.
* @hide
*/
public class Session {
public static final String START_SESSION = "START_SESSION";
+ public static final String START_EXTERNAL_SESSION = "START_EXTERNAL_SESSION";
public static final String CREATE_SUBSESSION = "CREATE_SUBSESSION";
public static final String CONTINUE_SUBSESSION = "CONTINUE_SUBSESSION";
public static final String END_SUBSESSION = "END_SUBSESSION";
public static final String END_SESSION = "END_SESSION";
public static final String SUBSESSION_SEPARATION_CHAR = "->";
+ public static final String SESSION_SEPARATION_CHAR_CHILD = "_";
public static final String EXTERNAL_INDICATOR = "E-";
+ public static final String TRUNCATE_STRING = "...";
/**
* Initial value of mExecutionEndTimeMs and the final value of {@link #getLocalExecutionTime()}
@@ -49,15 +53,19 @@
public static class Info implements Parcelable {
public final String sessionId;
- public final String shortMethodName;
+ public final String methodPath;
- private Info(String id, String methodName) {
+ private Info(String id, String path) {
sessionId = id;
- shortMethodName = methodName;
+ methodPath = path;
}
public static Info getInfo (Session s) {
- return new Info(s.getFullSessionId(), s.getShortMethodName());
+ // Create Info based on the truncated method path if the session is external, so we do
+ // not get multiple stacking external sessions (unless we have DEBUG level logging or
+ // lower).
+ return new Info(s.getFullSessionId(), s.getFullMethodPath(
+ !Log.DEBUG && s.isSessionExternal()));
}
/** Responsible for creating Info objects for deserialized Parcels. */
@@ -86,7 +94,7 @@
@Override
public void writeToParcel(Parcel destination, int flags) {
destination.writeString(sessionId);
- destination.writeString(shortMethodName);
+ destination.writeString(methodPath);
}
}
@@ -226,7 +234,15 @@
if (parentSession == null) {
return mSessionId;
} else {
- return parentSession.getFullSessionId() + "_" + mSessionId;
+ if (Log.VERBOSE) {
+ return parentSession.getFullSessionId() +
+ // Append "_X" to subsession to show subsession designation.
+ SESSION_SEPARATION_CHAR_CHILD + mSessionId;
+ } else {
+ // Only worry about the base ID at the top of the tree.
+ return parentSession.getFullSessionId();
+ }
+
}
}
@@ -259,16 +275,18 @@
}
// Recursively concatenate mShortMethodName with the parent Sessions to create full method
- // path. Caches this string so that multiple calls for the path will be quick.
- public String getFullMethodPath() {
+ // path. if truncatePath is set to true, all other external sessions (except for the most
+ // recent) will be truncated to "..."
+ public String getFullMethodPath(boolean truncatePath) {
StringBuilder sb = new StringBuilder();
- getFullMethodPath(sb);
+ getFullMethodPath(sb, truncatePath);
return sb.toString();
}
- private synchronized void getFullMethodPath(StringBuilder sb) {
- // Don't calculate if we have already figured it out!
- if (!TextUtils.isEmpty(mFullMethodPathCache)) {
+ private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath) {
+ // Return cached value for method path. When returning the truncated path, recalculate the
+ // full path without using the cached value.
+ if (!TextUtils.isEmpty(mFullMethodPathCache) && !truncatePath) {
sb.append(mFullMethodPathCache);
return;
}
@@ -278,25 +296,37 @@
// Check to see if the session has been renamed yet. If it has not, then the session
// has not been continued.
isSessionStarted = !mShortMethodName.equals(parentSession.mShortMethodName);
- parentSession.getFullMethodPath(sb);
+ parentSession.getFullMethodPath(sb, truncatePath);
sb.append(SUBSESSION_SEPARATION_CHAR);
}
// Encapsulate the external session's method name so it is obvious what part of the session
- // is external.
+ // is external or truncate it if we do not want the entire history.
if (isExternal()) {
- sb.append("(");
- sb.append(mShortMethodName);
- sb.append(")");
+ if (truncatePath) {
+ sb.append(TRUNCATE_STRING);
+ } else {
+ sb.append("(");
+ sb.append(mShortMethodName);
+ sb.append(")");
+ }
} else {
sb.append(mShortMethodName);
}
-
- if(isSessionStarted) {
+ // If we are returning the truncated path, do not save that path as the full path.
+ if (isSessionStarted && !truncatePath) {
// Cache this value so that we do not have to do this work next time!
// We do not cache the value if the session being evaluated hasn't been continued yet.
mFullMethodPathCache = sb.toString();
}
}
+ // Recursively move to the top of the tree to see if the parent session is external.
+ private boolean isSessionExternal() {
+ if (getParentSession() == null) {
+ return isExternal();
+ } else {
+ return getParentSession().isSessionExternal();
+ }
+ }
@Override
public int hashCode() {
@@ -350,7 +380,7 @@
return mParentSession.toString();
} else {
StringBuilder methodName = new StringBuilder();
- methodName.append(getFullMethodPath());
+ methodName.append(getFullMethodPath(false /*truncatePath*/));
if (mOwnerInfo != null && !mOwnerInfo.isEmpty()) {
methodName.append("(InCall package: ");
methodName.append(mOwnerInfo);
diff --git a/telecomm/java/android/telecom/Logging/SessionManager.java b/telecomm/java/android/telecom/Logging/SessionManager.java
index 8ced7f81..949f7b7 100644
--- a/telecomm/java/android/telecom/Logging/SessionManager.java
+++ b/telecomm/java/android/telecom/Logging/SessionManager.java
@@ -177,8 +177,9 @@
}
// Create Session from Info and add to the sessionMapper under this ID.
+ Log.d(LOGGING_TAG, Session.START_EXTERNAL_SESSION);
Session externalSession = new Session(Session.EXTERNAL_INDICATOR + sessionInfo.sessionId,
- sessionInfo.shortMethodName, System.currentTimeMillis(),
+ sessionInfo.methodPath, System.currentTimeMillis(),
false /*isStartedFromActiveSession*/, null);
externalSession.setIsExternal(true);
// Mark the external session as already completed, since we have no way of knowing when
@@ -190,8 +191,6 @@
// Create a subsession from this external Session parent node
Session childSession = createSubsession();
continueSession(childSession, shortMethodName);
-
- Log.d(LOGGING_TAG, Session.START_SESSION);
}
/**
diff --git a/tools/preload2/Android.mk b/tools/preload2/Android.mk
index ce877b3..09d95ff 100644
--- a/tools/preload2/Android.mk
+++ b/tools/preload2/Android.mk
@@ -5,7 +5,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under,src)
# To connect to devices (and take hprof dumps).
-LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt
+LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt tools-common-prebuilt
# To process hprof dumps.
LOCAL_STATIC_JAVA_LIBRARIES += perflib-prebuilt trove-prebuilt guavalib
diff --git a/wifi/java/android/net/wifi/EAPConstants.java b/wifi/java/android/net/wifi/EAPConstants.java
new file mode 100644
index 0000000..b5f7c94
--- /dev/null
+++ b/wifi/java/android/net/wifi/EAPConstants.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/**
+ * Utility class containing EAP (Extensible Authentication Protocol) Related constants.
+ *
+ * @hide
+ */
+public final class EAPConstants {
+ // Constant definition for EAP types. Refer to
+ // http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml for more info.
+ public static final int EAP_MD5 = 4;
+ public static final int EAP_OTP = 5;
+ public static final int EAP_RSA = 9;
+ public static final int EAP_KEA = 11;
+ public static final int EAP_KEA_VALIDATE = 12;
+ public static final int EAP_TLS = 13;
+ public static final int EAP_LEAP = 17;
+ public static final int EAP_SIM = 18;
+ public static final int EAP_TTLS = 21;
+ public static final int EAP_AKA = 23;
+ public static final int EAP_3Com = 24;
+ public static final int EAP_MSCHAPv2 = 26;
+ public static final int EAP_PEAP = 29;
+ public static final int EAP_POTP = 32;
+ public static final int EAP_ActiontecWireless = 35;
+ public static final int EAP_HTTPDigest = 38;
+ public static final int EAP_SPEKE = 41;
+ public static final int EAP_MOBAC = 42;
+ public static final int EAP_FAST = 43;
+ public static final int EAP_ZLXEAP = 44;
+ public static final int EAP_Link = 45;
+ public static final int EAP_PAX = 46;
+ public static final int EAP_PSK = 47;
+ public static final int EAP_SAKE = 48;
+ public static final int EAP_IKEv2 = 49;
+ public static final int EAP_AKA_PRIME = 50;
+ public static final int EAP_GPSK = 51;
+ public static final int EAP_PWD = 52;
+ public static final int EAP_EKE = 53;
+ public static final int EAP_TEAP = 55;
+}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 465addf..da87135 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -66,6 +66,93 @@
* supported by the access point.
*/
public String capabilities;
+
+ /**
+ * @hide
+ * No security protocol.
+ */
+ public static final int PROTOCOL_NONE = 0;
+ /**
+ * @hide
+ * Security protocol type: WPA version 1.
+ */
+ public static final int PROTOCOL_WPA = 1;
+ /**
+ * @hide
+ * Security protocol type: WPA version 2, also called RSN.
+ */
+ public static final int PROTOCOL_WPA2 = 2;
+ /**
+ * @hide
+ * Security protocol type:
+ * OSU Server-only authenticated layer 2 Encryption Network.
+ * Used for Hotspot 2.0.
+ */
+ public static final int PROTOCOL_OSEN = 3;
+
+ /**
+ * @hide
+ * No security key management scheme.
+ */
+ public static final int KEY_MGMT_NONE = 0;
+ /**
+ * @hide
+ * Security key management scheme: PSK.
+ */
+ public static final int KEY_MGMT_PSK = 1;
+ /**
+ * @hide
+ * Security key management scheme: EAP.
+ */
+ public static final int KEY_MGMT_EAP = 2;
+ /**
+ * @hide
+ * Security key management scheme: FT_PSK.
+ */
+ public static final int KEY_MGMT_FT_PSK = 3;
+ /**
+ * @hide
+ * Security key management scheme: FT_EAP.
+ */
+ public static final int KEY_MGMT_FT_EAP = 4;
+ /**
+ * @hide
+ * Security key management scheme: PSK_SHA256
+ */
+ public static final int KEY_MGMT_PSK_SHA256 = 5;
+ /**
+ * @hide
+ * Security key management scheme: EAP_SHA256.
+ */
+ public static final int KEY_MGMT_EAP_SHA256 = 6;
+ /**
+ * @hide
+ * Security key management scheme: OSEN.
+ * Used for Hotspot 2.0.
+ */
+ public static final int KEY_MGMT_OSEN = 7;
+
+ /**
+ * @hide
+ * No cipher suite.
+ */
+ public static final int CIPHER_NONE = 0;
+ /**
+ * @hide
+ * No group addressed, only used for group data cipher.
+ */
+ public static final int CIPHER_NO_GROUP_ADDRESSED = 1;
+ /**
+ * @hide
+ * Cipher suite: TKIP
+ */
+ public static final int CIPHER_TKIP = 2;
+ /**
+ * @hide
+ * Cipher suite: CCMP
+ */
+ public static final int CIPHER_CCMP = 3;
+
/**
* The detected signal level in dBm, also known as the RSSI.
*
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 18aae53..a62a0fb 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -61,6 +61,21 @@
credential.equals(that.credential));
}
+ /**
+ * Validate the configuration data.
+ *
+ * @return true on success or false on failure
+ */
+ public boolean validate() {
+ if (homeSp == null || !homeSp.validate()) {
+ return false;
+ }
+ if (credential == null || !credential.validate()) {
+ return false;
+ }
+ return true;
+ }
+
public static final Creator<PasspointConfiguration> CREATOR =
new Creator<PasspointConfiguration>() {
@Override
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 92dbd8a..57e65eb 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -16,15 +16,21 @@
package android.net.wifi.hotspot2.pps;
+import android.net.wifi.EAPConstants;
import android.net.wifi.ParcelUtil;
import android.os.Parcelable;
import android.os.Parcel;
import android.text.TextUtils;
+import android.util.Log;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
/**
* Class representing Credential subtree in the PerProviderSubscription (PPS)
@@ -40,6 +46,14 @@
* @hide
*/
public final class Credential implements Parcelable {
+ private static final String TAG = "Credential";
+
+ /**
+ * Max string length for realm. Refer to Credential/Realm node in Hotspot 2.0 Release 2
+ * Technical Specification Section 9.1 for more info.
+ */
+ private static final int MAX_REALM_LENGTH = 253;
+
/**
* The realm associated with this credential. It will be used to determine
* if this credential can be used to authenticate with a given hotspot by
@@ -53,6 +67,26 @@
*/
public static final class UserCredential implements Parcelable {
/**
+ * Maximum string length for username. Refer to Credential/UsernamePassword/Username
+ * node in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info.
+ */
+ private static final int MAX_USERNAME_LENGTH = 63;
+
+ /**
+ * Maximum string length for password. Refer to Credential/UsernamePassword/Password
+ * in Hotspot 2.0 Release 2 Technical Specification Section 9.1 for more info.
+ */
+ private static final int MAX_PASSWORD_LENGTH = 255;
+
+ /**
+ * Supported Non-EAP inner methods. Refer to
+ * Credential/UsernamePassword/EAPMethod/InnerEAPType in Hotspot 2.0 Release 2 Technical
+ * Specification Section 9.1 for more info.
+ */
+ private static final Set<String> SUPPORTED_AUTH =
+ new HashSet<String>(Arrays.asList("PAP", "CHAP", "MS-CHAP", "MS-CHAP-V2"));
+
+ /**
* Username of the credential.
*/
public String username = null;
@@ -104,6 +138,44 @@
TextUtils.equals(nonEapInnerMethod, that.nonEapInnerMethod);
}
+ /**
+ * Validate the configuration data.
+ *
+ * @return true on success or false on failure
+ */
+ public boolean validate() {
+ if (TextUtils.isEmpty(username)) {
+ Log.d(TAG, "Missing username");
+ return false;
+ }
+ if (username.length() > MAX_USERNAME_LENGTH) {
+ Log.d(TAG, "username exceeding maximum length: " + username.length());
+ return false;
+ }
+
+ if (TextUtils.isEmpty(password)) {
+ Log.d(TAG, "Missing password");
+ return false;
+ }
+ if (password.length() > MAX_PASSWORD_LENGTH) {
+ Log.d(TAG, "password exceeding maximum length: " + password.length());
+ return false;
+ }
+
+ // Only supports EAP-TTLS for user credential.
+ if (eapType != EAPConstants.EAP_TTLS) {
+ Log.d(TAG, "Invalid EAP Type for user credential: " + eapType);
+ return false;
+ }
+
+ // Verify Non-EAP inner method for EAP-TTLS.
+ if (!SUPPORTED_AUTH.contains(nonEapInnerMethod)) {
+ Log.d(TAG, "Invalid non-EAP inner method for EAP-TTLS: " + nonEapInnerMethod);
+ return false;
+ }
+ return true;
+ }
+
public static final Creator<UserCredential> CREATOR =
new Creator<UserCredential>() {
@Override
@@ -125,12 +197,22 @@
public UserCredential userCredential = null;
/**
- * Certificate based credential.
+ * Certificate based credential. This is used for EAP-TLS.
* Contains fields under PerProviderSubscription/Credential/DigitalCertificate subtree.
*/
public static final class CertificateCredential implements Parcelable {
/**
- * Certificate type. Valid values are "802.1ar" and "x509v3".
+ * Supported certificate types.
+ */
+ private static final String CERT_TYPE_X509V3 = "x509v3";
+
+ /**
+ * Certificate SHA-256 fingerprint length.
+ */
+ private static final int CERT_SHA256_FINGER_PRINT_LENGTH = 32;
+
+ /**
+ * Certificate type.
*/
public String certType = null;
@@ -164,6 +246,24 @@
Arrays.equals(certSha256FingerPrint, that.certSha256FingerPrint);
}
+ /**
+ * Validate the configuration data.
+ *
+ * @return true on success or false on failure
+ */
+ public boolean validate() {
+ if (!TextUtils.equals(CERT_TYPE_X509V3, certType)) {
+ Log.d(TAG, "Unsupported certificate type: " + certType);
+ return false;
+ }
+ if (certSha256FingerPrint == null ||
+ certSha256FingerPrint.length != CERT_SHA256_FINGER_PRINT_LENGTH) {
+ Log.d(TAG, "Invalid SHA-256 fingerprint");
+ return false;
+ }
+ return true;
+ }
+
public static final Creator<CertificateCredential> CREATOR =
new Creator<CertificateCredential>() {
@Override
@@ -188,7 +288,14 @@
*/
public static final class SimCredential implements Parcelable {
/**
- * International Mobile device Subscriber Identity.
+ * Maximum string length for IMSI.
+ */
+ public static final int MAX_IMSI_LENGTH = 15;
+
+ /**
+ * International Mobile Subscriber Identity, is used to identify the user
+ * of a cellular network and is a unique identification associated with all
+ * cellular networks
*/
public String imsi = null;
@@ -225,6 +332,26 @@
dest.writeInt(eapType);
}
+ /**
+ * Validate the configuration data.
+ *
+ * @return true on success or false on failure
+ */
+ public boolean validate() {
+ // Note: this only validate the format of IMSI string itself. Additional verification
+ // will be done by WifiService at the time of provisioning to verify against the IMSI
+ // of the SIM card installed in the device.
+ if (!verifyImsi()) {
+ return false;
+ }
+ if (eapType != EAPConstants.EAP_SIM && eapType != EAPConstants.EAP_AKA &&
+ eapType != EAPConstants.EAP_AKA_PRIME) {
+ Log.d(TAG, "Invalid EAP Type for SIM credential: " + eapType);
+ return false;
+ }
+ return true;
+ }
+
public static final Creator<SimCredential> CREATOR =
new Creator<SimCredential>() {
@Override
@@ -240,6 +367,43 @@
return new SimCredential[size];
}
};
+
+ /**
+ * Verify the IMSI (International Mobile Subscriber Identity) string. The string
+ * should contain zero or more numeric digits, and might ends with a "*" for prefix
+ * matching.
+ *
+ * @return true if IMSI is valid, false otherwise.
+ */
+ private boolean verifyImsi() {
+ if (TextUtils.isEmpty(imsi)) {
+ Log.d(TAG, "Missing IMSI");
+ return false;
+ }
+ if (imsi.length() > MAX_IMSI_LENGTH) {
+ Log.d(TAG, "IMSI exceeding maximum length: " + imsi.length());
+ return false;
+ }
+
+ // Locate the first non-digit character.
+ int nonDigit;
+ char stopChar = '\0';
+ for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) {
+ stopChar = imsi.charAt(nonDigit);
+ if (stopChar < '0' || stopChar > '9') {
+ break;
+ }
+ }
+
+ if (nonDigit == imsi.length()) {
+ return true;
+ }
+ else if (nonDigit == imsi.length()-1 && stopChar == '*') {
+ // Prefix matching.
+ return true;
+ }
+ return false;
+ }
}
public SimCredential simCredential = null;
@@ -296,6 +460,42 @@
isPrivateKeyEquals(clientPrivateKey, that.clientPrivateKey);
}
+ /**
+ * Validate the configuration data.
+ *
+ * @return true on success or false on failure
+ */
+ public boolean validate() {
+ if (TextUtils.isEmpty(realm)) {
+ Log.d(TAG, "Missing realm");
+ return false;
+ }
+ if (realm.length() > MAX_REALM_LENGTH) {
+ Log.d(TAG, "realm exceeding maximum length: " + realm.length());
+ return false;
+ }
+
+ // Verify the credential.
+ if (userCredential != null) {
+ if (!verifyUserCredential()) {
+ return false;
+ }
+ } else if (certCredential != null) {
+ if (!verifyCertCredential()) {
+ return false;
+ }
+ } else if (simCredential != null) {
+ if (!verifySimCredential()) {
+ return false;
+ }
+ } else {
+ Log.d(TAG, "Missing required credential");
+ return false;
+ }
+
+ return true;
+ }
+
public static final Creator<Credential> CREATOR =
new Creator<Credential>() {
@Override
@@ -317,6 +517,91 @@
}
};
+ /**
+ * Verify user credential.
+ *
+ * @return true if user credential is valid, false otherwise.
+ */
+ private boolean verifyUserCredential() {
+ if (userCredential == null) {
+ Log.d(TAG, "Missing user credential");
+ return false;
+ }
+ if (certCredential != null || simCredential != null) {
+ Log.d(TAG, "Contained more than one type of credential");
+ return false;
+ }
+ if (!userCredential.validate()) {
+ return false;
+ }
+ if (caCertificate == null) {
+ Log.d(TAG, "Missing CA Certificate for user credential");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Verify certificate credential, which is used for EAP-TLS. This will verify
+ * that the necessary client key and certificates are provided.
+ *
+ * @return true if certificate credential is valid, false otherwise.
+ */
+ private boolean verifyCertCredential() {
+ if (certCredential == null) {
+ Log.d(TAG, "Missing certificate credential");
+ return false;
+ }
+ if (userCredential != null || simCredential != null) {
+ Log.d(TAG, "Contained more than one type of credential");
+ return false;
+ }
+
+ if (!certCredential.validate()) {
+ return false;
+ }
+
+ // Verify required key and certificates for certificate credential.
+ if (caCertificate == null) {
+ Log.d(TAG, "Missing CA Certificate for certificate credential");
+ return false;
+ }
+ if (clientPrivateKey == null) {
+ Log.d(TAG, "Missing client private key for certificate credential");
+ return false;
+ }
+ try {
+ // Verify SHA-256 fingerprint for client certificate.
+ if (!verifySha256Fingerprint(clientCertificateChain,
+ certCredential.certSha256FingerPrint)) {
+ Log.d(TAG, "SHA-256 fingerprint mismatch");
+ return false;
+ }
+ } catch (NoSuchAlgorithmException | CertificateEncodingException e) {
+ Log.d(TAG, "Failed to verify SHA-256 fingerprint: " + e.getMessage());
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Verify SIM credential.
+ *
+ * @return true if SIM credential is valid, false otherwise.
+ */
+ private boolean verifySimCredential() {
+ if (simCredential == null) {
+ Log.d(TAG, "Missing SIM credential");
+ return false;
+ }
+ if (userCredential != null || certCredential != null) {
+ Log.d(TAG, "Contained more than one type of credential");
+ return false;
+ }
+ return simCredential.validate();
+ }
+
private static boolean isPrivateKeyEquals(PrivateKey key1, PrivateKey key2) {
if (key1 == null && key2 == null) {
return true;
@@ -373,4 +658,31 @@
return true;
}
+
+ /**
+ * Verify that the digest for a certificate in the certificate chain matches expected
+ * fingerprint. The certificate that matches the fingerprint is the client certificate.
+ *
+ * @param certChain Chain of certificates
+ * @param expectedFingerprint The expected SHA-256 digest of the client certificate
+ * @return true if the certificate chain contains a matching certificate, false otherwise
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateEncodingException
+ */
+ private static boolean verifySha256Fingerprint(X509Certificate[] certChain,
+ byte[] expectedFingerprint)
+ throws NoSuchAlgorithmException, CertificateEncodingException {
+ if (certChain == null) {
+ return false;
+ }
+ MessageDigest digester = MessageDigest.getInstance("SHA-256");
+ for (X509Certificate certificate : certChain) {
+ digester.reset();
+ byte[] fingerprint = digester.digest(certificate.getEncoded());
+ if (Arrays.equals(expectedFingerprint, fingerprint)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
index 2acc8be..5837c06 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSP.java
@@ -19,6 +19,7 @@
import android.os.Parcelable;
import android.os.Parcel;
import android.text.TextUtils;
+import android.util.Log;
import java.util.Arrays;
@@ -34,6 +35,8 @@
* @hide
*/
public final class HomeSP implements Parcelable {
+ private static final String TAG = "HomeSP";
+
/**
* FQDN (Fully Qualified Domain Name) of this home service provider.
*/
@@ -77,6 +80,23 @@
Arrays.equals(roamingConsortiumOIs, that.roamingConsortiumOIs);
}
+ /**
+ * Validate HomeSP data.
+ *
+ * @return true on success or false on failure
+ */
+ public boolean validate() {
+ if (TextUtils.isEmpty(fqdn)) {
+ Log.d(TAG, "Missing FQDN");
+ return false;
+ }
+ if (TextUtils.isEmpty(friendlyName)) {
+ Log.d(TAG, "Missing friendly name");
+ return false;
+ }
+ return true;
+ }
+
public static final Creator<HomeSP> CREATOR =
new Creator<HomeSP>() {
@Override
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index be11f0e..b4a3acf 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -16,8 +16,10 @@
package android.net.wifi.hotspot2;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.net.wifi.EAPConstants;
import android.net.wifi.hotspot2.pps.Credential;
import android.net.wifi.hotspot2.pps.HomeSP;
import android.os.Parcel;
@@ -44,7 +46,9 @@
cred.realm = "realm";
cred.userCredential = null;
cred.certCredential = null;
- cred.simCredential = null;
+ cred.simCredential = new Credential.SimCredential();
+ cred.simCredential.imsi = "1234*";
+ cred.simCredential.eapType = EAPConstants.EAP_SIM;
cred.caCertificate = null;
cred.clientCertificateChain = null;
cred.clientPrivateKey = null;
@@ -61,11 +65,20 @@
assertTrue(readConfig.equals(writeConfig));
}
+ /**
+ * Verify parcel read/write for a default configuration.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithDefault() throws Exception {
verifyParcel(new PasspointConfiguration());
}
+ /**
+ * Verify parcel read/write for a configuration that contained both HomeSP and Credential.
+ * @throws Exception
+ */
@Test
public void verifyParcelWithHomeSPAndCredential() throws Exception {
PasspointConfiguration config = new PasspointConfiguration();
@@ -74,6 +87,11 @@
verifyParcel(config);
}
+ /**
+ * Verify parcel read/write for a configuration that contained only HomeSP.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithHomeSPOnly() throws Exception {
PasspointConfiguration config = new PasspointConfiguration();
@@ -81,10 +99,63 @@
verifyParcel(config);
}
+ /**
+ * Verify parcel read/write for a configuration that contained only Credential.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithCredentialOnly() throws Exception {
PasspointConfiguration config = new PasspointConfiguration();
config.credential = createCredential();
verifyParcel(config);
}
+
+ /**
+ * Verify that a default/empty configuration is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateDefaultConfig() throws Exception {
+ PasspointConfiguration config = new PasspointConfiguration();
+ assertFalse(config.validate());
+ }
+
+ /**
+ * Verify that a configuration without Credential is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithoutCredential() throws Exception {
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.homeSp = createHomeSp();
+ assertFalse(config.validate());
+ }
+
+ /**
+ * Verify that a a configuration without HomeSP is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateConfigWithoutHomeSp() throws Exception {
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.credential = createCredential();
+ assertFalse(config.validate());
+ }
+
+ /**
+ * Verify a valid configuration.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateValidConfig() throws Exception {
+ PasspointConfiguration config = new PasspointConfiguration();
+ config.homeSp = createHomeSp();
+ config.credential = createCredential();
+ assertTrue(config.validate());
+ }
}
\ No newline at end of file
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index 68ac4ef..223aa52 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -16,14 +16,19 @@
package android.net.wifi.hotspot2.pps;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.net.wifi.EAPConstants;
import android.net.wifi.FakeKeys;
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
import org.junit.Test;
@@ -52,15 +57,15 @@
private static Credential createCredentialWithCertificateCredential() {
Credential.CertificateCredential certCred = new Credential.CertificateCredential();
certCred.certType = "x509v3";
- certCred.certSha256FingerPrint = new byte[256];
+ certCred.certSha256FingerPrint = new byte[32];
return createCredential(null, certCred, null, FakeKeys.CA_CERT0,
new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
}
private static Credential createCredentialWithSimCredential() {
Credential.SimCredential simCred = new Credential.SimCredential();
- simCred.imsi = "imsi";
- simCred.eapType = 1;
+ simCred.imsi = "1234*";
+ simCred.eapType = EAPConstants.EAP_SIM;
return createCredential(null, null, simCred, null, null, null);
}
@@ -68,7 +73,7 @@
Credential.UserCredential userCred = new Credential.UserCredential();
userCred.username = "username";
userCred.password = "password";
- userCred.eapType = 1;
+ userCred.eapType = EAPConstants.EAP_TTLS;
userCred.nonEapInnerMethod = "MS-CHAP";
return createCredential(userCred, null, null, FakeKeys.CA_CERT0,
new X509Certificate[] {FakeKeys.CLIENT_CERT}, FakeKeys.RSA_KEY1);
@@ -83,23 +88,386 @@
assertTrue(readCred.equals(writeCred));
}
+ /**
+ * Verify parcel read/write for a default/empty credential.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithDefault() throws Exception {
verifyParcel(new Credential());
}
+ /**
+ * Verify parcel read/write for a certificate credential.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithCertificateCredential() throws Exception {
verifyParcel(createCredentialWithCertificateCredential());
}
+ /**
+ * Verify parcel read/write for a SIM credential.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithSimCredential() throws Exception {
verifyParcel(createCredentialWithSimCredential());
}
+ /**
+ * Verify parcel read/write for an user credential.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithUserCredential() throws Exception {
verifyParcel(createCredentialWithUserCredential());
}
-}
+
+ /**
+ * Verify a valid user credential.
+ * @throws Exception
+ */
+ @Test
+ public void validateUserCredential() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ cred.userCredential = new Credential.UserCredential();
+ cred.userCredential.username = "username";
+ cred.userCredential.password = "password";
+ cred.userCredential.eapType = EAPConstants.EAP_TTLS;
+ cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ assertTrue(cred.validate());
+ }
+
+ /**
+ * Verify that an user credential without CA Certificate is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUserCredentialWithoutCaCert() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ cred.userCredential = new Credential.UserCredential();
+ cred.userCredential.username = "username";
+ cred.userCredential.password = "password";
+ cred.userCredential.eapType = EAPConstants.EAP_TTLS;
+ cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that an user credential with EAP type other than EAP-TTLS is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUserCredentialWithEapTls() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ cred.userCredential = new Credential.UserCredential();
+ cred.userCredential.username = "username";
+ cred.userCredential.password = "password";
+ cred.userCredential.eapType = EAPConstants.EAP_TLS;
+ cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ assertFalse(cred.validate());
+ }
+
+
+ /**
+ * Verify that an user credential without realm is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUserCredentialWithoutRealm() throws Exception {
+ Credential cred = new Credential();
+ cred.userCredential = new Credential.UserCredential();
+ cred.userCredential.username = "username";
+ cred.userCredential.password = "password";
+ cred.userCredential.eapType = EAPConstants.EAP_TTLS;
+ cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that an user credential without username is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUserCredentialWithoutUsername() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ cred.userCredential = new Credential.UserCredential();
+ cred.userCredential.password = "password";
+ cred.userCredential.eapType = EAPConstants.EAP_TTLS;
+ cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that an user credential without password is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUserCredentialWithoutPassword() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ cred.userCredential = new Credential.UserCredential();
+ cred.userCredential.username = "username";
+ cred.userCredential.eapType = EAPConstants.EAP_TTLS;
+ cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that an user credential without auth methoh (non-EAP inner method) is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUserCredentialWithoutAuthMethod() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ cred.userCredential = new Credential.UserCredential();
+ cred.userCredential.username = "username";
+ cred.userCredential.password = "password";
+ cred.userCredential.eapType = EAPConstants.EAP_TTLS;
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify a certificate credential. CA Certificate, client certificate chain,
+ * and client private key are all required. Also the digest for client
+ * certificate must match the fingerprint specified in the certificate credential.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCertCredential() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup certificate credential.
+ cred.certCredential = new Credential.CertificateCredential();
+ cred.certCredential.certType = "x509v3";
+ cred.certCredential.certSha256FingerPrint =
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
+ // Setup certificates and private key.
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ assertTrue(cred.validate());
+ }
+
+ /**
+ * Verify that an certificate credential without CA Certificate is invalid.
+ *
+ * @throws Exception
+ */
+ public void validateCertCredentialWithoutCaCert() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup certificate credential.
+ cred.certCredential = new Credential.CertificateCredential();
+ cred.certCredential.certType = "x509v3";
+ cred.certCredential.certSha256FingerPrint =
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
+ // Setup certificates and private key.
+ cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that a certificate credential without client certificate chain is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCertCredentialWithoutClientCertChain() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup certificate credential.
+ cred.certCredential = new Credential.CertificateCredential();
+ cred.certCredential.certType = "x509v3";
+ cred.certCredential.certSha256FingerPrint =
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
+ // Setup certificates and private key.
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that a certificate credential without client private key is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCertCredentialWithoutClientPrivateKey() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup certificate credential.
+ cred.certCredential = new Credential.CertificateCredential();
+ cred.certCredential.certType = "x509v3";
+ cred.certCredential.certSha256FingerPrint =
+ MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded());
+ // Setup certificates and private key.
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that a certificate credential with mismatch client certificate fingerprint
+ * is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCertCredentialWithMismatchFingerprint() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup certificate credential.
+ cred.certCredential = new Credential.CertificateCredential();
+ cred.certCredential.certType = "x509v3";
+ cred.certCredential.certSha256FingerPrint = new byte[32];
+ Arrays.fill(cred.certCredential.certSha256FingerPrint, (byte)0);
+ // Setup certificates and private key.
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ cred.clientCertificateChain = new X509Certificate[] {FakeKeys.CLIENT_CERT};
+ cred.clientPrivateKey = FakeKeys.RSA_KEY1;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify a SIM credential using EAP-SIM.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateSimCredentialWithEapSim() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup SIM credential.
+ cred.simCredential = new Credential.SimCredential();
+ cred.simCredential.imsi = "1234*";
+ cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ assertTrue(cred.validate());
+ }
+
+ /**
+ * Verify a SIM credential using EAP-AKA.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateSimCredentialWithEapAka() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup SIM credential.
+ cred.simCredential = new Credential.SimCredential();
+ cred.simCredential.imsi = "1234*";
+ cred.simCredential.eapType = EAPConstants.EAP_AKA;
+ assertTrue(cred.validate());
+ }
+
+ /**
+ * Verify a SIM credential using EAP-AKA-PRIME.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateSimCredentialWithEapAkaPrime() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup SIM credential.
+ cred.simCredential = new Credential.SimCredential();
+ cred.simCredential.imsi = "1234*";
+ cred.simCredential.eapType = EAPConstants.EAP_AKA_PRIME;
+ assertTrue(cred.validate());
+ }
+
+ /**
+ * Verify that a SIM credential without IMSI is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateSimCredentialWithoutIMSI() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup SIM credential.
+ cred.simCredential = new Credential.SimCredential();
+ cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that a SIM credential with an invalid IMSI is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateSimCredentialWithInvalidIMSI() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup SIM credential.
+ cred.simCredential = new Credential.SimCredential();
+ cred.simCredential.imsi = "dummy";
+ cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that a SIM credential with invalid EAP type is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateSimCredentialWithEapTls() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup SIM credential.
+ cred.simCredential = new Credential.SimCredential();
+ cred.simCredential.imsi = "1234*";
+ cred.simCredential.eapType = EAPConstants.EAP_TLS;
+ assertFalse(cred.validate());
+ }
+
+ /**
+ * Verify that a credential contained both an user and a SIM credential is invalid.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateCredentialWithUserAndSimCredential() throws Exception {
+ Credential cred = new Credential();
+ cred.realm = "realm";
+ // Setup user credential with EAP-TTLS.
+ cred.userCredential = new Credential.UserCredential();
+ cred.userCredential.username = "username";
+ cred.userCredential.password = "password";
+ cred.userCredential.eapType = EAPConstants.EAP_TTLS;
+ cred.userCredential.nonEapInnerMethod = "MS-CHAP";
+ cred.caCertificate = FakeKeys.CA_CERT0;
+ // Setup SIM credential.
+ cred.simCredential = new Credential.SimCredential();
+ cred.simCredential.imsi = "1234*";
+ cred.simCredential.eapType = EAPConstants.EAP_SIM;
+ assertFalse(cred.validate());
+ }
+}
\ No newline at end of file
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
index 0d2da64..fff1477 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSPTest.java
@@ -16,13 +16,12 @@
package android.net.wifi.hotspot2.pps;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
-import java.util.HashMap;
-
import org.junit.Test;
/**
@@ -47,13 +46,76 @@
assertTrue(readHomeSp.equals(writeHomeSp));
}
+ /**
+ * Verify parcel read/write for an empty HomeSP.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithEmptyHomeSP() throws Exception {
verifyParcel(new HomeSP());
}
+ /**
+ * Verify parcel read/write for a valid HomeSP.
+ *
+ * @throws Exception
+ */
@Test
public void verifyParcelWithValidHomeSP() throws Exception {
verifyParcel(createHomeSp());
}
+
+ /**
+ * Verify that a HomeSP is valid when both FQDN and Friendly Name
+ * are provided.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateValidHomeSP() throws Exception {
+ HomeSP homeSp = new HomeSP();
+ homeSp.fqdn = "fqdn";
+ homeSp.friendlyName = "friendly name";
+ assertTrue(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSP is not valid when FQDN is not provided
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutFqdn() throws Exception {
+ HomeSP homeSp = new HomeSP();
+ homeSp.friendlyName = "friendly name";
+ assertFalse(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSP is not valid when Friendly Name is not provided
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithoutFriendlyName() throws Exception {
+ HomeSP homeSp = new HomeSP();
+ homeSp.fqdn = "fqdn";
+ assertFalse(homeSp.validate());
+ }
+
+ /**
+ * Verify that a HomeSP is valid when the optional Roaming Consortium OIs are
+ * provided.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateHomeSpWithRoamingConsoritums() throws Exception {
+ HomeSP homeSp = new HomeSP();
+ homeSp.fqdn = "fqdn";
+ homeSp.friendlyName = "friendly name";
+ homeSp.roamingConsortiumOIs = new long[] {0x55, 0x66};
+ assertTrue(homeSp.validate());
+ }
}