diff options
author | Xin Li <delphij@google.com> | 2022-02-11 06:57:37 +0000 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2022-02-11 06:57:37 +0000 |
commit | 866199c06013f19860a1e0adbd0d24726d41ba56 (patch) | |
tree | 1515668d6456daf9580af29ad35698a1bd98210b /src | |
parent | fcdb17103f024b99a9b79b9f9a7ac915993bd769 (diff) | |
parent | a6b5e3fc73aab189a20344ed5cf219fc0da338f5 (diff) | |
download | ims-866199c06013f19860a1e0adbd0d24726d41ba56.tar.gz |
Merge sc-v2-dev-plus-aosp-without-vendor@8084891
Bug: 214455710
Merged-In: I1e122c64450d5b504cfaa93197439182c21e0956
Change-Id: I80b403dd9a3cb5527edde81d3b04a87cd18ee040
Diffstat (limited to 'src')
9 files changed, 494 insertions, 24 deletions
diff --git a/src/java/com/android/ims/rcs/uce/UceController.java b/src/java/com/android/ims/rcs/uce/UceController.java index 60c80e65..6fb27b06 100644 --- a/src/java/com/android/ims/rcs/uce/UceController.java +++ b/src/java/com/android/ims/rcs/uce/UceController.java @@ -80,11 +80,23 @@ public class UceController { List<EabCapabilityResult> getCapabilitiesFromCache(@NonNull List<Uri> uris); /** + * Retrieve the capabilities associated with the given uris from the cache including + * expired capabilities. + */ + List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(@NonNull List<Uri> uris); + + /** * Retrieve the contact's capabilities from the availability cache. */ EabCapabilityResult getAvailabilityFromCache(@NonNull Uri uri); /** + * Retrieve the contact's capabilities from the availability cache including expired + * capabilities + */ + EabCapabilityResult getAvailabilityFromCacheIncludingExpired(@NonNull Uri uri); + + /** * Store the given capabilities to the cache. */ void saveCapabilities(List<RcsContactUceCapability> contactCapabilities); @@ -507,11 +519,21 @@ public class UceController { } @Override + public List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uris) { + return mEabController.getCapabilitiesIncludingExpired(uris); + } + + @Override public EabCapabilityResult getAvailabilityFromCache(Uri contactUri) { return mEabController.getAvailability(contactUri); } @Override + public EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri contactUri) { + return mEabController.getAvailabilityIncludingExpired(contactUri); + } + + @Override public void saveCapabilities(List<RcsContactUceCapability> contactCapabilities) { mEabController.saveCapabilities(contactCapabilities); } @@ -810,6 +832,7 @@ public class UceController { public void removeRequestDisallowedStatus() { logd("removeRequestDisallowedStatus"); mDeviceState.resetDeviceState(); + mRequestManager.resetThrottlingList(); } /** diff --git a/src/java/com/android/ims/rcs/uce/UceDeviceState.java b/src/java/com/android/ims/rcs/uce/UceDeviceState.java index 0d8842fa..857e25c8 100644 --- a/src/java/com/android/ims/rcs/uce/UceDeviceState.java +++ b/src/java/com/android/ims/rcs/uce/UceDeviceState.java @@ -258,14 +258,12 @@ public class UceDeviceState { if (requestType == UceController.REQUEST_TYPE_PUBLISH) { // Provisioning error for publish request. setDeviceState(DEVICE_STATE_PROVISION_ERROR); - } else { - setDeviceState(DEVICE_STATE_FORBIDDEN); + updateErrorCode(sipCode, reason, requestType); + // There is no request retry time for SIP code 403 + removeRequestRetryTime(); + // No timer to exit the forbidden state. + removeExitStateTimer(); } - updateErrorCode(sipCode, reason, requestType); - // There is no request retry time for SIP code 403 - removeRequestRetryTime(); - // No timer to exit the forbidden state. - removeExitStateTimer(); break; case NetworkSipCode.SIP_CODE_NOT_FOUND: // sip 404 diff --git a/src/java/com/android/ims/rcs/uce/eab/EabController.java b/src/java/com/android/ims/rcs/uce/eab/EabController.java index 903a19df..b03e4659 100644 --- a/src/java/com/android/ims/rcs/uce/eab/EabController.java +++ b/src/java/com/android/ims/rcs/uce/eab/EabController.java @@ -35,11 +35,23 @@ public interface EabController extends ControllerBase { @NonNull List<EabCapabilityResult> getCapabilities(@NonNull List<Uri> uris); /** + * Get contact capabilities from cache including expired capabilities. + * @param uris the uri list to get contact capabilities from cache. + * @return The contact capabilities of the given uri list. + */ + @NonNull List<EabCapabilityResult> getCapabilitiesIncludingExpired(@NonNull List<Uri> uris); + + /** * Retrieve the contact's capabilities from the availability cache. */ @NonNull EabCapabilityResult getAvailability(@NonNull Uri contactUri); /** + * Retrieve the contact's capabilities from the availability cache. + */ + @NonNull EabCapabilityResult getAvailabilityIncludingExpired(@NonNull Uri contactUri); + + /** * Save the capabilities to the EAB database. */ void saveCapabilities(@NonNull List<RcsContactUceCapability> contactCapabilities); diff --git a/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java b/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java index d3e8063e..7563f641 100644 --- a/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java +++ b/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java @@ -56,6 +56,7 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.function.Predicate; /** @@ -166,6 +167,29 @@ public class EabControllerImpl implements EabController { } /** + * Retrieve the contacts' capabilities from the EAB database including expired capabilities. + */ + @Override + public @NonNull List<EabCapabilityResult> getCapabilitiesIncludingExpired( + @NonNull List<Uri> uris) { + Objects.requireNonNull(uris); + if (mIsSetDestroyedFlag) { + Log.d(TAG, "EabController destroyed."); + return generateDestroyedResult(uris); + } + + Log.d(TAG, "getCapabilitiesIncludingExpired uri size=" + uris.size()); + List<EabCapabilityResult> capabilityResultList = new ArrayList(); + + for (Uri uri : uris) { + EabCapabilityResult result = generateEabResultIncludingExpired(uri, + this::isCapabilityExpired); + capabilityResultList.add(result); + } + return capabilityResultList; + } + + /** * Retrieve the contact's capabilities from the availability cache. */ @Override @@ -182,6 +206,23 @@ public class EabControllerImpl implements EabController { } /** + * Retrieve the contact's capabilities from the availability cache including expired + * capabilities. + */ + @Override + public @NonNull EabCapabilityResult getAvailabilityIncludingExpired(@NonNull Uri contactUri) { + Objects.requireNonNull(contactUri); + if (mIsSetDestroyedFlag) { + Log.d(TAG, "EabController destroyed."); + return new EabCapabilityResult( + contactUri, + EabCapabilityResult.EAB_CONTROLLER_DESTROYED_FAILURE, + null); + } + return generateEabResultIncludingExpired(contactUri, this::isAvailabilityExpired); + } + + /** * Update the availability catch and save the capabilities to the EAB database. */ @Override @@ -299,6 +340,52 @@ public class EabControllerImpl implements EabController { return result; } + private EabCapabilityResult generateEabResultIncludingExpired(Uri contactUri, + Predicate<Cursor> isExpiredMethod) { + RcsUceCapabilityBuilderWrapper builder = null; + EabCapabilityResult result; + Optional<Boolean> isExpired = Optional.empty(); + + // query EAB provider + Uri queryUri = Uri.withAppendedPath( + Uri.withAppendedPath(EabProvider.ALL_DATA_URI, String.valueOf(mSubId)), + getNumberFromUri(mContext, contactUri)); + Cursor cursor = mContext.getContentResolver().query(queryUri, null, null, null, null); + + if (cursor != null && cursor.getCount() != 0) { + while (cursor.moveToNext()) { + // Record whether it has expired. + if (!isExpired.isPresent()) { + isExpired = Optional.of(isExpiredMethod.test(cursor)); + } + if (builder == null) { + builder = createNewBuilder(contactUri, cursor); + } else { + updateCapability(contactUri, cursor, builder); + } + } + cursor.close(); + + // Determine the query result + int eabResult = EabCapabilityResult.EAB_QUERY_SUCCESSFUL; + if (isExpired.orElse(false)) { + eabResult = EabCapabilityResult.EAB_CONTACT_EXPIRED_FAILURE; + } + + if (builder.getMechanism() == CAPABILITY_MECHANISM_PRESENCE) { + PresenceBuilder presenceBuilder = builder.getPresenceBuilder(); + result = new EabCapabilityResult(contactUri, eabResult, presenceBuilder.build()); + } else { + OptionsBuilder optionsBuilder = builder.getOptionsBuilder(); + result = new EabCapabilityResult(contactUri, eabResult, optionsBuilder.build()); + } + } else { + result = new EabCapabilityResult(contactUri, + EabCapabilityResult.EAB_CONTACT_NOT_FOUND_FAILURE, null); + } + return result; + } + private void updateCapability(Uri contactUri, Cursor cursor, RcsUceCapabilityBuilderWrapper builderWrapper) { if (builderWrapper.getMechanism() == CAPABILITY_MECHANISM_PRESENCE) { diff --git a/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java b/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java index f7a4acc6..17cec90b 100644 --- a/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java +++ b/src/java/com/android/ims/rcs/uce/request/CapabilityRequest.java @@ -23,6 +23,7 @@ import android.util.Log; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; import com.android.ims.rcs.uce.eab.EabCapabilityResult; +import com.android.ims.rcs.uce.presence.pidfparser.PidfParserUtils; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; @@ -140,20 +141,36 @@ public abstract class CapabilityRequest implements UceRequest { return; } - // Get the capabilities from the cache. - final List<RcsContactUceCapability> cachedCapList - = isSkipGettingFromCache() ? Collections.EMPTY_LIST : getCapabilitiesFromCache(); + // Get the contact capabilities from the cache including the expired capabilities. + final List<EabCapabilityResult> eabResultList = getCapabilitiesFromCache(); + + // Get all the unexpired capabilities from the EAB result list and add to the response. + final List<RcsContactUceCapability> cachedCapList = isSkipGettingFromCache() ? + Collections.EMPTY_LIST : getUnexpiredCapabilities(eabResultList); mRequestResponse.addCachedCapabilities(cachedCapList); logd("executeRequest: cached capabilities size=" + cachedCapList.size()); + // Get the rest contacts which are not in the cache or has expired. + final List<Uri> expiredUris = getRequestingFromNetworkUris(cachedCapList); + + // For those uris that are not in the cache or have expired, we should request their + // capabilities from the network. However, we still need to check whether these contacts + // are in the throttling list. If the contact is in the throttling list, even if it has + // expired, we will get the cached capabilities. + final List<RcsContactUceCapability> throttlingUris = + getFromThrottlingList(expiredUris, eabResultList); + mRequestResponse.addCachedCapabilities(throttlingUris); + + logd("executeRequest: contacts in throttling list size=" + throttlingUris.size()); + // Notify that the cached capabilities are updated. - if (!cachedCapList.isEmpty()) { + if (!cachedCapList.isEmpty() || !throttlingUris.isEmpty()) { mRequestManagerCallback.notifyCachedCapabilitiesUpdated(mCoordinatorId, mTaskId); } // Get the rest contacts which need to request capabilities from the network. - final List<Uri> requestCapUris = getRequestingFromNetworkUris(cachedCapList); + List<Uri> requestCapUris = getRequestingFromNetworkUris(cachedCapList, throttlingUris); logd("executeRequest: requestCapUris size=" + requestCapUris.size()); @@ -193,21 +210,30 @@ public abstract class CapabilityRequest implements UceRequest { } // Get the cached capabilities by the given request type. - private List<RcsContactUceCapability> getCapabilitiesFromCache() { + private List<EabCapabilityResult> getCapabilitiesFromCache() { List<EabCapabilityResult> resultList = null; if (mRequestType == REQUEST_TYPE_CAPABILITY) { - resultList = mRequestManagerCallback.getCapabilitiesFromCache(mUriList); + resultList = mRequestManagerCallback.getCapabilitiesFromCacheIncludingExpired(mUriList); } else if (mRequestType == REQUEST_TYPE_AVAILABILITY) { // Always get the first element if the request type is availability. Uri uri = mUriList.get(0); - EabCapabilityResult eabResult = mRequestManagerCallback.getAvailabilityFromCache(uri); + EabCapabilityResult eabResult = + mRequestManagerCallback.getAvailabilityFromCacheIncludingExpired(uri); resultList = new ArrayList<>(); resultList.add(eabResult); } if (resultList == null) { return Collections.emptyList(); } - return resultList.stream() + return resultList; + } + + /** + * Get the unexpired contact capabilities from the given EAB result list. + * @param list the query result from the EAB + */ + private List<RcsContactUceCapability> getUnexpiredCapabilities(List<EabCapabilityResult> list) { + return list.stream() .filter(Objects::nonNull) .filter(result -> result.getStatus() == EabCapabilityResult.EAB_QUERY_SUCCESSFUL) .map(EabCapabilityResult::getContactCapabilities) @@ -227,6 +253,67 @@ public abstract class CapabilityRequest implements UceRequest { } /** + * Get the contact uris which cannot retrieve capabilities from the cache. + * @param cachedCapList The capabilities which are already stored in the cache. + * @param throttlingUris The capabilities which are in the throttling list. + */ + private List<Uri> getRequestingFromNetworkUris(List<RcsContactUceCapability> cachedCapList, + List<RcsContactUceCapability> throttlingUris) { + // We won't request the network query for those contacts in the cache and in the + // throttling list. Merging the two list and get the rest contact uris. + List<RcsContactUceCapability> notNetworkQueryList = new ArrayList<>(cachedCapList); + notNetworkQueryList.addAll(throttlingUris); + return getRequestingFromNetworkUris(notNetworkQueryList); + } + + /** + * Get the contact capabilities for those uri are in the throttling list. If the contact uri is + * in the throttling list, the capabilities will be retrieved from cache even if it has expired. + * If the capabilities cannot be found, return the non-RCS contact capabilities instead. + * @param expiredUris the expired/unknown uris to check whether are in the throttling list + * @return the contact capabilities for the uris are in the throttling list + */ + private List<RcsContactUceCapability> getFromThrottlingList(final List<Uri> expiredUris, + final List<EabCapabilityResult> eabResultList) { + List<RcsContactUceCapability> resultList = new ArrayList<>(); + List<RcsContactUceCapability> notFoundFromCacheList = new ArrayList<>(); + + // Retrieve the uris put in the throttling list from the expired/unknown contacts. + List<Uri> throttlingUris = mRequestManagerCallback.getInThrottlingListUris(expiredUris); + + // For these uris in the throttling list, check whether their capabilities are in the cache. + List<EabCapabilityResult> throttlingUriFoundInEab = new ArrayList<>(); + for (Uri uri : throttlingUris) { + for (EabCapabilityResult eabResult : eabResultList) { + if (eabResult.getContact().equals(uri)) { + throttlingUriFoundInEab.add(eabResult); + break; + } + } + } + + throttlingUriFoundInEab.forEach(eabResult -> { + if (eabResult.getStatus() == EabCapabilityResult.EAB_QUERY_SUCCESSFUL || + eabResult.getStatus() == EabCapabilityResult.EAB_CONTACT_EXPIRED_FAILURE) { + // The capabilities are found, add to the result list + resultList.add(eabResult.getContactCapabilities()); + } else { + // Cannot get the capabilities from cache, create the non-RCS capabilities instead. + notFoundFromCacheList.add(PidfParserUtils.getNotFoundContactCapabilities( + eabResult.getContact())); + } + }); + + if (!notFoundFromCacheList.isEmpty()) { + resultList.addAll(notFoundFromCacheList); + } + + logd("getFromThrottlingList: requesting uris in the list size=" + throttlingUris.size() + + ", generate non-RCS size=" + notFoundFromCacheList.size()); + return resultList; + } + + /** * Set the timeout timer of this request. */ protected void setupRequestTimeoutTimer() { diff --git a/src/java/com/android/ims/rcs/uce/request/ContactThrottlingList.java b/src/java/com/android/ims/rcs/uce/request/ContactThrottlingList.java new file mode 100644 index 00000000..da67f6c9 --- /dev/null +++ b/src/java/com/android/ims/rcs/uce/request/ContactThrottlingList.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 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.ims.rcs.uce.request; + +import android.net.Uri; +import android.util.Log; + +import com.android.ims.rcs.uce.util.UceUtils; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * The class is used to store when the contact's capabilities request result is inconclusive. + */ +public class ContactThrottlingList { + private static final String LOG_TAG = UceUtils.getLogPrefix() + "ThrottlingList"; + + private static class ContactInfo { + Uri mContactUri; + int mSipCode; + Instant mThrottleEndTimestamp; + + public ContactInfo(Uri contactUri, int sipCode, Instant timestamp) { + mContactUri = contactUri; + mSipCode = sipCode; + mThrottleEndTimestamp = timestamp; + } + } + + private final int mSubId; + private final List<ContactInfo> mThrottlingList = new ArrayList<>(); + + public ContactThrottlingList(int subId) { + mSubId = subId; + } + + public synchronized void reset() { + mThrottlingList.clear(); + } + + public synchronized void addToThrottlingList(List<Uri> uriList, int sipCode) { + // Clean up the expired contacts before starting. + cleanUpExpiredContacts(); + + List<Uri> addToThrottlingList = getNotInThrottlingListUris(uriList); + long expiration = UceUtils.getAvailabilityCacheExpiration(mSubId); + Instant timestamp = Instant.now().plusSeconds(expiration); + + List<ContactInfo> list = addToThrottlingList.stream().map(uri -> + new ContactInfo(uri, sipCode, timestamp)).collect(Collectors.toList()); + + int previousSize = mThrottlingList.size(); + mThrottlingList.addAll(list); + + logd("addToThrottlingList: previous size=" + previousSize + + ", current size=" + mThrottlingList.size() + ", expired time=" + timestamp); + } + + private synchronized List<Uri> getNotInThrottlingListUris(List<Uri> uriList) { + List<Uri> throttlingUris = mThrottlingList.stream().map(contactInfo -> + contactInfo.mContactUri).collect(Collectors.toList()); + List<Uri> addToThrottlingUris = new ArrayList<>(uriList); + addToThrottlingUris.removeAll(throttlingUris); + return addToThrottlingUris; + } + + public synchronized List<Uri> getInThrottlingListUris(List<Uri> uriList) { + // Clean up the expired contacts before starting. + cleanUpExpiredContacts(); + + return uriList.stream() + .filter(uri -> mThrottlingList.stream() + .anyMatch(contactInfo -> contactInfo.mContactUri.equals(uri))) + .collect(Collectors.toList()); + } + + /** + * Clean up the expired contacts from the throttling list. + */ + private synchronized void cleanUpExpiredContacts() { + final int previousSize = mThrottlingList.size(); + List<ContactInfo> expiredContacts = mThrottlingList.stream() + .filter(contactInfo -> Instant.now() + .isAfter(contactInfo.mThrottleEndTimestamp)) + .collect(Collectors.toList()); + mThrottlingList.removeAll(expiredContacts); + + logd("cleanUpExpiredContacts: previous size=" + previousSize + + ", current size=" + mThrottlingList.size()); + } + + private void logd(String log) { + Log.d(LOG_TAG, getLogPrefix().append(log).toString()); + } + + private StringBuilder getLogPrefix() { + StringBuilder builder = new StringBuilder("["); + builder.append(mSubId); + builder.append("] "); + return builder; + } +} diff --git a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java index 8913340b..f44686ac 100644 --- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java +++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java @@ -25,12 +25,14 @@ import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.aidl.IRcsUceControllerCallback; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; +import com.android.ims.rcs.uce.eab.EabCapabilityResult; import com.android.ims.rcs.uce.presence.pidfparser.PidfParserUtils; import com.android.ims.rcs.uce.request.SubscriptionTerminatedHelper.TerminatedResult; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; import com.android.ims.rcs.uce.UceStatsWriter; import com.android.internal.annotations.VisibleForTesting; +import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; @@ -311,6 +313,7 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { private RequestResult handleNetworkResponseFailed(SubscribeRequest request) { final long taskId = request.getTaskId(); final CapabilityRequestResponse response = request.getRequestResponse(); + final List<Uri> requestUris = response.getNotReceiveCapabilityUpdatedContact(); RequestResult requestResult = null; if (response.isNotFound()) { @@ -318,8 +321,7 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { // updated callback from the ImsService afterward. Therefore, we create the capabilities // with the result REQUEST_RESULT_NOT_FOUND by ourself and will trigger the // capabilities received callback to the clients later. - List<Uri> uriList = request.getContactUri(); - List<RcsContactUceCapability> capabilityList = uriList.stream().map(uri -> + List<RcsContactUceCapability> capabilityList = requestUris.stream().map(uri -> PidfParserUtils.getNotFoundContactCapabilities(uri)) .collect(Collectors.toList()); response.addUpdatedCapabilities(capabilityList); @@ -327,9 +329,18 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { // We treat the NOT FOUND is a successful result. requestResult = sNetworkRespSuccessfulCreator.createRequestResult(taskId, response, mRequestManagerCallback); - } + } else { + // The request result is unsuccessful and it's not the NOT FOUND error. we need to get + // the capabilities from the cache. + List<RcsContactUceCapability> capabilitiesList = + getCapabilitiesFromCacheIncludingExpired(requestUris); + response.addUpdatedCapabilities(capabilitiesList); + + // Add to the throttling list for the inconclusive result of the contacts. + mRequestManagerCallback.addToThrottlingList(requestUris, + response.getResponseSipCode().orElse( + com.android.ims.rcs.uce.util.NetworkSipCode.SIP_CODE_REQUEST_TIMEOUT)); - if (requestResult == null) { requestResult = sNetworkRespErrorCreator.createRequestResult(taskId, response, mRequestManagerCallback); } @@ -337,6 +348,41 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { } /** + * Get the contact capabilities from the cache even if the capabilities have expired. If the + * capabilities doesn't exist, create the non-RCS capabilities instead. + * @param uris the uris to get the capabilities from cache. + * @return The contact capabilities for the given uris. + */ + private List<RcsContactUceCapability> getCapabilitiesFromCacheIncludingExpired(List<Uri> uris) { + List<RcsContactUceCapability> resultList = new ArrayList<>(); + List<RcsContactUceCapability> notFoundFromCacheList = new ArrayList<>(); + + // Get the capabilities from the cache. + List<EabCapabilityResult> eabResultList = + mRequestManagerCallback.getCapabilitiesFromCacheIncludingExpired(uris); + + eabResultList.forEach(eabResult -> { + if (eabResult.getStatus() == EabCapabilityResult.EAB_QUERY_SUCCESSFUL || + eabResult.getStatus() == EabCapabilityResult.EAB_CONTACT_EXPIRED_FAILURE) { + // The capabilities are found, add to the result list + resultList.add(eabResult.getContactCapabilities()); + } else { + // Cannot get the capabilities from cache, create the non-RCS capabilities instead. + notFoundFromCacheList.add(PidfParserUtils.getNotFoundContactCapabilities( + eabResult.getContact())); + } + }); + + if (!notFoundFromCacheList.isEmpty()) { + resultList.addAll(notFoundFromCacheList); + } + + logd("getCapabilitiesFromCacheIncludingExpired: requesting uris size=" + uris.size() + + ", capabilities not found from cache size=" + notFoundFromCacheList.size()); + return resultList; + } + + /** * This method is called when the given SubscribeRequest received the onNotifyCapabilitiesUpdate * callback from the ImsService. */ @@ -441,20 +487,39 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { } /** - * This method is called when the framework does not receive receive the result for - * capabilities request. + * This method is called when the framework did not receive the capabilities request result. */ private void handleRequestTimeout(SubscribeRequest request) { CapabilityRequestResponse response = request.getRequestResponse(); + List<Uri> requestUris = response.getNotReceiveCapabilityUpdatedContact(); logd("handleRequestTimeout: " + response); + logd("handleRequestTimeout: not received updated uri size=" + requestUris.size()); - // Finish this request - request.onFinish(); + // Add to the throttling list for the inconclusive result of the contacts. + mRequestManagerCallback.addToThrottlingList(requestUris, + com.android.ims.rcs.uce.util.NetworkSipCode.SIP_CODE_REQUEST_TIMEOUT); + + // Get the capabilities from the cache instead and add to the response. + List<RcsContactUceCapability> capabilitiesList = + getCapabilitiesFromCacheIncludingExpired(requestUris); + response.addUpdatedCapabilities(capabilitiesList); + + // Trigger capabilities updated callback if there is any. + List<RcsContactUceCapability> updatedCapList = response.getUpdatedContactCapability(); + if (!updatedCapList.isEmpty()) { + triggerCapabilitiesReceivedCallback(updatedCapList); + response.removeUpdatedCapabilities(updatedCapList); + } // Remove this request from the activated collection and notify RequestManager. long taskId = request.getTaskId(); RequestResult requestResult = sRequestTimeoutCreator.createRequestResult(taskId, response, mRequestManagerCallback); + + // Finish this request + request.onFinish(); + + // Remove this request from the activated collection and notify RequestManager. moveRequestToFinishedCollection(taskId, requestResult); } diff --git a/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java b/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java index 565f94e4..1e4f0b01 100644 --- a/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java +++ b/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java @@ -148,11 +148,21 @@ public class UceRequestManager { List<EabCapabilityResult> getCapabilitiesFromCache(List<Uri> uriList); /** + * Retrieve the contact capabilities from the cache including the expired capabilities. + */ + List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uriList); + + /** * Retrieve the contact availability from the cache. */ EabCapabilityResult getAvailabilityFromCache(Uri uri); /** + * Retrieve the contact availability from the cache including the expired capabilities. + */ + EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri uri); + + /** * Store the given contact capabilities to the cache. */ void saveCapabilities(List<RcsContactUceCapability> contactCapabilities); @@ -241,6 +251,19 @@ public class UceRequestManager { * to remove the coordinator from the UceRequestRepository. */ void notifyRequestCoordinatorFinished(long requestCoordinatorId); + + /** + * Check whether the given uris are in the throttling list. + * @param uriList the uris to check if it is in the throttling list + * @return the uris in the throttling list + */ + List<Uri> getInThrottlingListUris(List<Uri> uriList); + + /** + * Add the given uris to the throttling list because the capabilities request result + * is inconclusive. + */ + void addToThrottlingList(List<Uri> uriList, int sipCode); } private RequestManagerCallback mRequestMgrCallback = new RequestManagerCallback() { @@ -255,11 +278,21 @@ public class UceRequestManager { } @Override + public List<EabCapabilityResult> getCapabilitiesFromCacheIncludingExpired(List<Uri> uris) { + return mControllerCallback.getCapabilitiesFromCacheIncludingExpired(uris); + } + + @Override public EabCapabilityResult getAvailabilityFromCache(Uri uri) { return mControllerCallback.getAvailabilityFromCache(uri); } @Override + public EabCapabilityResult getAvailabilityFromCacheIncludingExpired(Uri uri) { + return mControllerCallback.getAvailabilityFromCacheIncludingExpired(uri); + } + + @Override public void saveCapabilities(List<RcsContactUceCapability> contactCapabilities) { mControllerCallback.saveCapabilities(contactCapabilities); } @@ -350,12 +383,23 @@ public class UceRequestManager { public void notifyRequestCoordinatorFinished(long requestCoordinatorId) { mHandler.sendRequestCoordinatorFinishedMessage(requestCoordinatorId); } + + @Override + public List<Uri> getInThrottlingListUris(List<Uri> uriList) { + return mThrottlingList.getInThrottlingListUris(uriList); + } + + @Override + public void addToThrottlingList(List<Uri> uriList, int sipCode) { + mThrottlingList.addToThrottlingList(uriList, sipCode); + } }; private final int mSubId; private final Context mContext; private final UceRequestHandler mHandler; private final UceRequestRepository mRequestRepository; + private final ContactThrottlingList mThrottlingList; private volatile boolean mIsDestroyed; private OptionsController mOptionsCtrl; @@ -367,6 +411,7 @@ public class UceRequestManager { mContext = context; mControllerCallback = c; mHandler = new UceRequestHandler(this, looper); + mThrottlingList = new ContactThrottlingList(mSubId); mRequestRepository = new UceRequestRepository(subId, mRequestMgrCallback); logi("create"); } @@ -379,6 +424,7 @@ public class UceRequestManager { mControllerCallback = c; mHandler = new UceRequestHandler(this, looper); mRequestRepository = requestRepository; + mThrottlingList = new ContactThrottlingList(mSubId); } /** @@ -402,10 +448,18 @@ public class UceRequestManager { logi("onDestroy"); mIsDestroyed = true; mHandler.onDestroy(); + mThrottlingList.reset(); mRequestRepository.onDestroy(); } /** + * Clear the throttling list. + */ + public void resetThrottlingList() { + mThrottlingList.reset(); + } + + /** * Send a new capability request. It is called by UceController. */ public void sendCapabilityRequest(List<Uri> uriList, boolean skipFromCache, diff --git a/src/java/com/android/ims/rcs/uce/util/UceUtils.java b/src/java/com/android/ims/rcs/uce/util/UceUtils.java index c88de0b3..d93f2a00 100644 --- a/src/java/com/android/ims/rcs/uce/util/UceUtils.java +++ b/src/java/com/android/ims/rcs/uce/util/UceUtils.java @@ -53,6 +53,9 @@ public class UceUtils { private static final long DEFAULT_CAP_REQUEST_TIMEOUT_AFTER_MS = TimeUnit.MINUTES.toMillis(3); private static Optional<Long> OVERRIDE_CAP_REQUEST_TIMEOUT_AFTER_MS = Optional.empty(); + // The default value of the availability cache expiration. + private static final long DEFAULT_AVAILABILITY_CACHE_EXPIRATION_SEC = 60L; // 60 seconds + // The task ID of the UCE request private static long TASK_ID = 0L; @@ -400,4 +403,26 @@ public class UceUtils { } return numberParts[0]; } + + /** + * Get the availability expiration from provisioning manager. + * @param subId The subscription ID + * @return the number of seconds for the availability cache expiration. + */ + public static long getAvailabilityCacheExpiration(int subId) { + long value = -1; + try { + ProvisioningManager pm = ProvisioningManager.createForSubscriptionId(subId); + value = pm.getProvisioningIntValue( + ProvisioningManager.KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC); + } catch (Exception e) { + Log.w(LOG_TAG, "Exception in getAvailabilityCacheExpiration: " + e); + } + + if (value <= 0) { + Log.w(LOG_TAG, "The availability expiration cannot be less than 0."); + value = DEFAULT_AVAILABILITY_CACHE_EXPIRATION_SEC; + } + return value; + } } |