Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common
Submodule common updated 32 files
+15 −0 LabApiUtilities/build.gradle
+8 −0 changelog.txt
+15 −0 common/build.gradle
+15 −1 common/src/main/java/com/microsoft/identity/common/adal/internal/AuthenticationConstants.java
+1 −0 common/src/main/java/com/microsoft/identity/common/internal/broker/ipc/BrokerOperationBundle.java
+187 −0 common/src/main/java/com/microsoft/identity/common/internal/cache/WebAppsAccountIdRegistry.kt
+63 −0 common/src/main/java/com/microsoft/identity/common/internal/controllers/BrokerMsalController.java
+4 −0 common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/AuthorizationActivityFactory.kt
+3 −1 ...on/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/AuthorizationActivityParameters.kt
+7 −1 common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/WebViewAuthorizationFragment.java
+18 −0 common/src/main/java/com/microsoft/identity/common/internal/request/MsalBrokerRequestAdapter.java
+7 −0 common/src/main/java/com/microsoft/identity/common/internal/result/AdalBrokerResultAdapter.java
+4 −0 common/src/main/java/com/microsoft/identity/common/internal/result/IBrokerResultAdapter.java
+8 −0 common/src/main/java/com/microsoft/identity/common/internal/result/MsalBrokerResultAdapter.java
+2 −1 common/src/main/java/com/microsoft/identity/common/internal/ui/browser/BrowserAuthorizationStrategy.java
+10 −4 common/src/main/java/com/microsoft/identity/common/internal/ui/webview/AzureActiveDirectoryWebViewClient.java
+145 −0 common/src/test/java/com/microsoft/identity/common/internal/cache/WebAppsAccountIdRegistryTest.kt
+56 −8 .../src/test/java/com/microsoft/identity/common/internal/ui/webview/AzureActiveDirectoryWebViewClientTest.java
+21 −0 common4j/build.gradle
+74 −0 common4j/src/main/com/microsoft/identity/common/java/commands/AcquirePrtSsoTokenBatchResult.java
+6 −0 common4j/src/main/com/microsoft/identity/common/java/commands/AcquirePrtSsoTokenResult.java
+6 −0 common4j/src/main/com/microsoft/identity/common/java/commands/SilentTokenCommand.java
+9 −0 common4j/src/main/com/microsoft/identity/common/java/controllers/CommandDispatcher.java
+183 −0 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/BenchmarkSpan.kt
+423 −0 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/DefaultBenchmarkSpanPrinter.kt
+96 −0 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/DefaultOTelSpanFactory.kt
+36 −0 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/IBenchmarkSpanPrinter.kt
+56 −0 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/IOTelSpanFactory.kt
+119 −0 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/OTelBenchmarkSpanFactory.kt
+0 −143 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/OTelUtility.java
+118 −0 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/OTelUtility.kt
+1 −1 common4j/src/main/com/microsoft/identity/common/java/opentelemetry/SpanName.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
Expand Down Expand Up @@ -122,6 +123,15 @@ public class AcquireTokenFragment extends Fragment {
private MsalWrapper mMsalWrapper;
private List<IAccount> mLoadedAccounts = new ArrayList<>();

// Concurrent execution UI elements
private EditText mConcurrentCount;
private EditText mConcurrentTotalCount;
private Button mRunConcurrent;
private Button mStopConcurrent;
private LinearLayout mThreadProgressContainer;
private List<TextView> mThreadProgressViews = new ArrayList<>();
private List<ConcurrentAcquireTokenExecutor> mRunningExecutors = new ArrayList<>();

private IClientActiveBrokerCache mCache;
public AcquireTokenFragment() {
// left empty
Expand Down Expand Up @@ -434,6 +444,27 @@ public void onCheckedChanged(CompoundButton v, boolean debugBrokers) {
mMsalWrapper.getPreferredAuthMethod()
));

// Initialize concurrent execution UI elements
mConcurrentCount = view.findViewById(R.id.concurrent_count);
mConcurrentTotalCount = view.findViewById(R.id.concurrent_total_count);
mRunConcurrent = view.findViewById(R.id.btn_run_concurrent);
mStopConcurrent = view.findViewById(R.id.btn_stop_concurrent);
mThreadProgressContainer = view.findViewById(R.id.concurrent_thread_progress_container);

mRunConcurrent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
runConcurrentAcquireTokenSilent();
}
});

mStopConcurrent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopConcurrentExecutors();
}
});

return view;
}

Expand Down Expand Up @@ -694,6 +725,80 @@ public void run() {
});
}

/**
* Concurrent AcquireTokenSilent
* Note: In order for this to work, the build config shouldSkipSilentTokenCommandCacheForStressTest must be set to true.
*/
private void runConcurrentAcquireTokenSilent() {
try {
final int concurrency = Integer.parseInt(mConcurrentCount.getText().toString());
final int totalCount = Integer.parseInt(mConcurrentTotalCount.getText().toString());

if (concurrency <= 0 || totalCount <= 0) {
showMessage("Concurrency and total count must be greater than 0");
return;
}

// Calculate requests per thread
final int requestsPerThread = totalCount / concurrency;
final int remainder = totalCount % concurrency;

// Reset progress
mThreadProgressContainer.removeAllViews();
mThreadProgressViews.clear();

// Create per-thread progress views
for (int i = 0; i < concurrency; i++) {
TextView threadProgress = new TextView(getContext());
threadProgress.setText("Thread " + i + ": 0/0");
threadProgress.setTextSize(12);
threadProgress.setPadding(0, 5, 0, 5);
mThreadProgressContainer.addView(threadProgress);
mThreadProgressViews.add(threadProgress);
}

// Create and start one executor per thread
for (int i = 0; i < concurrency; i++) {
final int threadId = i;
final int countForThisThread = requestsPerThread + (i < remainder ? 1 : 0);

final ConcurrentAcquireTokenExecutor executor =
new ConcurrentAcquireTokenExecutor(threadId, countForThisThread);

executor.execute(
getContext(),
getCurrentRequestOptions(),
new ConcurrentAcquireTokenExecutor.IUIUpdateCallback() {
@Override
public void updateProgress(final int tid, final int successCount, final int completedCount) {
if (tid >= 0 && tid < mThreadProgressViews.size()) {
mThreadProgressViews.get(tid).setText(
String.format(Locale.US,
"Thread %d: %d/%d", tid, successCount, completedCount));
}
}

@Override
public void onStopped(final int tid) {
}
}
);

mRunningExecutors.add(executor);
}
} catch (NumberFormatException e) {
showMessage("Please enter valid numbers for concurrency and total count");
}
}

private void stopConcurrentExecutors() {
for (ConcurrentAcquireTokenExecutor executor : mRunningExecutors) {
executor.stop();
}
mRunningExecutors.clear();
showMessage("Stopped all running tasks");
}

public interface OnFragmentInteractionListener {
void onGetAuthResult(IAuthenticationResult result);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Copyright (c) Microsoft Corporation.
// All rights reserved.
//
// This code is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package com.microsoft.identity.client.testapp

import android.content.Context
import android.os.Handler
import android.os.Looper
import com.microsoft.identity.client.IAuthenticationResult
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean

class ConcurrentAcquireTokenExecutor(
val threadId: Int,
val totalCount: Int
) {

private val randomDelayInMs = (10..50).random().toLong()

// Flag to track if execution should stop
private val isStopped = AtomicBoolean(false)

// Use a dedicated executor for background work
private val executor: ExecutorService = Executors.newSingleThreadExecutor()

interface IUIUpdateCallback {
fun updateProgress(threadId: Int, successCount: Int, completedCount: Int)
fun onStopped(threadId: Int)
}

fun execute(context: Context,
requestOptions: RequestOptions,
uiCallback: IUIUpdateCallback){
// MsalWrapper.create callbacks run on main thread, so call it directly
MsalWrapper.create(
context.applicationContext,
Constants.getResourceIdFromConfigFile(requestOptions.configFile),
object : INotifyOperationResultCallback<MsalWrapper?> {
override fun onSuccess(result: MsalWrapper?) {
// Start the first iteration immediately (no initial sleep)
if (result != null) {
executeAcquireTokenSilent(result,
0,
0,
requestOptions,
uiCallback)
} else {
// Handle the null case appropriately, e.g., notify UI or log error
// For now, we'll notify the UI that the operation has stopped
uiCallback.onStopped(threadId)
}
}

override fun showMessage(message: String?) {
// do nothing.
}
}
)
}

/**
* Stop the executor and cancel any pending operations
*/
fun stop() {
if (isStopped.compareAndSet(false, true)) {
executor.shutdownNow()
}
}

private fun executeAcquireTokenSilent(msalWrapper: MsalWrapper,
successCount: Int,
completedCount: Int,
requestOptions: RequestOptions,
uiCallback: IUIUpdateCallback) {
msalWrapper.acquireTokenSilent(
requestOptions,
object : INotifyOperationResultCallback<IAuthenticationResult> {
override fun onSuccess(result: IAuthenticationResult) {
val newSuccessCount = successCount + 1
val newCompletedCount = completedCount + 1

// MSAL callbacks already run on main thread - update UI directly
uiCallback.updateProgress(threadId, newSuccessCount, newCompletedCount)
executeNext(
msalWrapper,
newSuccessCount,
newCompletedCount,
requestOptions,
uiCallback
)
}

override fun showMessage(message: String?) {
val newCompletedCount = completedCount + 1

// MSAL callbacks already run on main thread - update UI directly
uiCallback.updateProgress(threadId, successCount, newCompletedCount)

executeNext(
msalWrapper,
successCount,
newCompletedCount,
requestOptions,
uiCallback
)
}
}
)
}

private fun executeNext(
msalWrapper: MsalWrapper,
newSuccessCount: Int,
newCompletedCount: Int,
requestOptions: RequestOptions,
uiCallback: IUIUpdateCallback
) {
// Check if stopped
if (isStopped.get()) {
Handler(Looper.getMainLooper()).post {
uiCallback.onStopped(threadId)
}
return
}

if (newCompletedCount < totalCount) {
executor.execute {
try {
Thread.sleep(randomDelayInMs)

// Post back to main thread to call acquireTokenSilent
// (required since MSAL needs to be called from main thread)
Handler(Looper.getMainLooper()).post {
executeAcquireTokenSilent(
msalWrapper,
newSuccessCount,
newCompletedCount,
requestOptions,
uiCallback
)
}
} catch (e: InterruptedException) {
// Interrupted - likely due to stop request
Handler(Looper.getMainLooper()).post {
uiCallback.onStopped(threadId)
}
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
@Getter
@Accessors(prefix = "m")
@AllArgsConstructor
class RequestOptions {
public class RequestOptions {
private final Constants.ConfigFile mConfigFile;
private final String mLoginHint;
private final IAccount mAccount;
Expand All @@ -52,4 +52,8 @@ class RequestOptions {
private final String mPopResourceUrl;
private final String mPoPClientClaims;
private final boolean mAllowSignInFromOtherDevice;

public Constants.ConfigFile getConfigFile(){
return mConfigFile;
}
}
Loading