Revert (with changes) "Revert "Add multiple services support in SecureSettingsServiceNameResolver, to""
This reverts commit c66070ce35.
Reason for revert: Fixing the original issue. Credential Manager Service was configured as multiple mode without implementing newServiceListLocked(). For now, setting multiple mode config to false, and will enable it with the functionality later.
Change-Id: I6cced5f917633a9b953546622493dab713c575c2
This commit is contained in:
@@ -19,28 +19,9 @@ import android.annotation.ArrayRes;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.StringRes;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.AppGlobals;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Gets the service name using a framework resources, temporarily changing the service if necessary
|
||||
@@ -48,259 +29,42 @@ import java.util.List;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class FrameworkResourcesServiceNameResolver implements ServiceNameResolver {
|
||||
public final class FrameworkResourcesServiceNameResolver extends ServiceNameBaseResolver {
|
||||
|
||||
private static final String TAG = FrameworkResourcesServiceNameResolver.class.getSimpleName();
|
||||
|
||||
/** Handler message to {@link #resetTemporaryService(int)} */
|
||||
private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
|
||||
|
||||
@NonNull
|
||||
private final Context mContext;
|
||||
@NonNull
|
||||
private final Object mLock = new Object();
|
||||
@StringRes
|
||||
private final int mStringResourceId;
|
||||
@ArrayRes
|
||||
private final int mArrayResourceId;
|
||||
private final boolean mIsMultiple;
|
||||
/**
|
||||
* Map of temporary service name list set by {@link #setTemporaryServices(int, String[], int)},
|
||||
* keyed by {@code userId}.
|
||||
*
|
||||
* <p>Typically used by Shell command and/or CTS tests to configure temporary services if
|
||||
* mIsMultiple is true.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private final SparseArray<String[]> mTemporaryServiceNamesList = new SparseArray<>();
|
||||
/**
|
||||
* Map of default services that have been disabled by
|
||||
* {@link #setDefaultServiceEnabled(int, boolean)},keyed by {@code userId}.
|
||||
*
|
||||
* <p>Typically used by Shell command and/or CTS tests.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private final SparseBooleanArray mDefaultServicesDisabled = new SparseBooleanArray();
|
||||
@Nullable
|
||||
private NameResolverListener mOnSetCallback;
|
||||
/**
|
||||
* When the temporary service will expire (and reset back to the default).
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private long mTemporaryServiceExpiration;
|
||||
|
||||
/**
|
||||
* Handler used to reset the temporary service name.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private Handler mTemporaryHandler;
|
||||
|
||||
public FrameworkResourcesServiceNameResolver(@NonNull Context context,
|
||||
@StringRes int resourceId) {
|
||||
mContext = context;
|
||||
super(context, false);
|
||||
mStringResourceId = resourceId;
|
||||
mArrayResourceId = -1;
|
||||
mIsMultiple = false;
|
||||
}
|
||||
|
||||
public FrameworkResourcesServiceNameResolver(@NonNull Context context,
|
||||
@ArrayRes int resourceId, boolean isMultiple) {
|
||||
super(context, isMultiple);
|
||||
if (!isMultiple) {
|
||||
throw new UnsupportedOperationException("Please use "
|
||||
+ "FrameworkResourcesServiceNameResolver(context, @StringRes int) constructor "
|
||||
+ "if single service mode is requested.");
|
||||
}
|
||||
mContext = context;
|
||||
mStringResourceId = -1;
|
||||
mArrayResourceId = resourceId;
|
||||
mIsMultiple = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnTemporaryServiceNameChangedCallback(@NonNull NameResolverListener callback) {
|
||||
synchronized (mLock) {
|
||||
this.mOnSetCallback = callback;
|
||||
}
|
||||
public String[] readServiceNameList(int userId) {
|
||||
return mContext.getResources().getStringArray(mArrayResourceId);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getServiceName(@UserIdInt int userId) {
|
||||
String[] serviceNames = getServiceNameList(userId);
|
||||
return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0];
|
||||
public String readServiceName(int userId) {
|
||||
return mContext.getResources().getString(mStringResourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultServiceName(@UserIdInt int userId) {
|
||||
String[] serviceNames = getDefaultServiceNameList(userId);
|
||||
return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default list of the service names for the given user.
|
||||
*
|
||||
* <p>Typically implemented by services which want to provide multiple backends.
|
||||
*/
|
||||
@Override
|
||||
public String[] getServiceNameList(int userId) {
|
||||
synchronized (mLock) {
|
||||
String[] temporaryNames = mTemporaryServiceNamesList.get(userId);
|
||||
if (temporaryNames != null) {
|
||||
// Always log it, as it should only be used on CTS or during development
|
||||
Slog.w(TAG, "getServiceName(): using temporary name "
|
||||
+ Arrays.toString(temporaryNames) + " for user " + userId);
|
||||
return temporaryNames;
|
||||
}
|
||||
final boolean disabled = mDefaultServicesDisabled.get(userId);
|
||||
if (disabled) {
|
||||
// Always log it, as it should only be used on CTS or during development
|
||||
Slog.w(TAG, "getServiceName(): temporary name not set and default disabled for "
|
||||
+ "user " + userId);
|
||||
return null;
|
||||
}
|
||||
return getDefaultServiceNameList(userId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default list of the service names for the given user.
|
||||
*
|
||||
* <p>Typically implemented by services which want to provide multiple backends.
|
||||
*/
|
||||
@Override
|
||||
public String[] getDefaultServiceNameList(int userId) {
|
||||
synchronized (mLock) {
|
||||
if (mIsMultiple) {
|
||||
String[] serviceNameList = mContext.getResources().getStringArray(mArrayResourceId);
|
||||
// Filter out unimplemented services
|
||||
// Initialize the validated array as null because we do not know the final size.
|
||||
List<String> validatedServiceNameList = new ArrayList<>();
|
||||
try {
|
||||
for (int i = 0; i < serviceNameList.length; i++) {
|
||||
if (TextUtils.isEmpty(serviceNameList[i])) {
|
||||
continue;
|
||||
}
|
||||
ComponentName serviceComponent = ComponentName.unflattenFromString(
|
||||
serviceNameList[i]);
|
||||
ServiceInfo serviceInfo = AppGlobals.getPackageManager().getServiceInfo(
|
||||
serviceComponent,
|
||||
PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
|
||||
if (serviceInfo != null) {
|
||||
validatedServiceNameList.add(serviceNameList[i]);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Could not validate provided services.", e);
|
||||
}
|
||||
String[] validatedServiceNameArray = new String[validatedServiceNameList.size()];
|
||||
return validatedServiceNameList.toArray(validatedServiceNameArray);
|
||||
} else {
|
||||
final String name = mContext.getString(mStringResourceId);
|
||||
return TextUtils.isEmpty(name) ? new String[0] : new String[]{name};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfiguredInMultipleMode() {
|
||||
return mIsMultiple;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTemporary(@UserIdInt int userId) {
|
||||
synchronized (mLock) {
|
||||
return mTemporaryServiceNamesList.get(userId) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
|
||||
int durationMs) {
|
||||
setTemporaryServices(userId, new String[]{componentName}, durationMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemporaryServices(int userId, @NonNull String[] componentNames, int durationMs) {
|
||||
synchronized (mLock) {
|
||||
mTemporaryServiceNamesList.put(userId, componentNames);
|
||||
|
||||
if (mTemporaryHandler == null) {
|
||||
mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
|
||||
synchronized (mLock) {
|
||||
resetTemporaryService(userId);
|
||||
}
|
||||
} else {
|
||||
Slog.wtf(TAG, "invalid handler msg: " + msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
|
||||
}
|
||||
mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs;
|
||||
mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs);
|
||||
for (int i = 0; i < componentNames.length; i++) {
|
||||
notifyTemporaryServiceNameChangedLocked(userId, componentNames[i],
|
||||
/* isTemporary= */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetTemporaryService(@UserIdInt int userId) {
|
||||
synchronized (mLock) {
|
||||
Slog.i(TAG, "resetting temporary service for user " + userId + " from "
|
||||
+ Arrays.toString(mTemporaryServiceNamesList.get(userId)));
|
||||
mTemporaryServiceNamesList.remove(userId);
|
||||
if (mTemporaryHandler != null) {
|
||||
mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
|
||||
mTemporaryHandler = null;
|
||||
}
|
||||
notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null,
|
||||
/* isTemporary= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setDefaultServiceEnabled(int userId, boolean enabled) {
|
||||
synchronized (mLock) {
|
||||
final boolean currentlyEnabled = isDefaultServiceEnabledLocked(userId);
|
||||
if (currentlyEnabled == enabled) {
|
||||
Slog.i(TAG, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
|
||||
return false;
|
||||
}
|
||||
if (enabled) {
|
||||
Slog.i(TAG, "disabling default service for user " + userId);
|
||||
mDefaultServicesDisabled.removeAt(userId);
|
||||
} else {
|
||||
Slog.i(TAG, "enabling default service for user " + userId);
|
||||
mDefaultServicesDisabled.put(userId, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaultServiceEnabled(int userId) {
|
||||
synchronized (mLock) {
|
||||
return isDefaultServiceEnabledLocked(userId);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDefaultServiceEnabledLocked(int userId) {
|
||||
return !mDefaultServicesDisabled.get(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
synchronized (mLock) {
|
||||
return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNamesList + "]";
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/117779333): support proto
|
||||
@Override
|
||||
@@ -314,31 +78,4 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
|
||||
pw.print(mDefaultServicesDisabled.size());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/117779333): support proto
|
||||
@Override
|
||||
public void dumpShort(@NonNull PrintWriter pw, @UserIdInt int userId) {
|
||||
synchronized (mLock) {
|
||||
final String[] temporaryNames = mTemporaryServiceNamesList.get(userId);
|
||||
if (temporaryNames != null) {
|
||||
pw.print("tmpName=");
|
||||
pw.print(Arrays.toString(temporaryNames));
|
||||
final long ttl = mTemporaryServiceExpiration - SystemClock.elapsedRealtime();
|
||||
pw.print(" (expires in ");
|
||||
TimeUtils.formatDuration(ttl, pw);
|
||||
pw.print("), ");
|
||||
}
|
||||
pw.print("defaultName=");
|
||||
pw.print(getDefaultServiceName(userId));
|
||||
final boolean disabled = mDefaultServicesDisabled.get(userId);
|
||||
pw.println(disabled ? " (disabled)" : " (enabled)");
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyTemporaryServiceNameChangedLocked(@UserIdInt int userId,
|
||||
@Nullable String newTemporaryName, boolean isTemporary) {
|
||||
if (mOnSetCallback != null) {
|
||||
mOnSetCallback.onNameResolved(userId, newTemporaryName, isTemporary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,11 @@ import android.annotation.NonNull;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Gets the service name using a property from the {@link android.provider.Settings.Secure}
|
||||
@@ -28,21 +31,34 @@ import java.io.PrintWriter;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class SecureSettingsServiceNameResolver implements ServiceNameResolver {
|
||||
public final class SecureSettingsServiceNameResolver extends ServiceNameBaseResolver {
|
||||
/**
|
||||
* The delimiter to be used to parse the secure settings string. Services must make sure
|
||||
* that this delimiter is used while adding component names to their secure setting property.
|
||||
*/
|
||||
private static final char COMPONENT_NAME_SEPARATOR = ':';
|
||||
|
||||
private final @NonNull Context mContext;
|
||||
private final TextUtils.SimpleStringSplitter mStringColonSplitter =
|
||||
new TextUtils.SimpleStringSplitter(COMPONENT_NAME_SEPARATOR);
|
||||
|
||||
@NonNull
|
||||
private final String mProperty;
|
||||
|
||||
public SecureSettingsServiceNameResolver(@NonNull Context context, @NonNull String property) {
|
||||
mContext = context;
|
||||
mProperty = property;
|
||||
this(context, property, /*isMultiple*/false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultServiceName(@UserIdInt int userId) {
|
||||
return Settings.Secure.getStringForUser(mContext.getContentResolver(), mProperty, userId);
|
||||
/**
|
||||
*
|
||||
* @param context the context required to retrieve the secure setting value
|
||||
* @param property name of the secure setting key
|
||||
* @param isMultiple true if the system service using this resolver needs to connect to
|
||||
* multiple remote services, false otherwise
|
||||
*/
|
||||
public SecureSettingsServiceNameResolver(@NonNull Context context, @NonNull String property,
|
||||
boolean isMultiple) {
|
||||
super(context, isMultiple);
|
||||
mProperty = property;
|
||||
}
|
||||
|
||||
// TODO(b/117779333): support proto
|
||||
@@ -61,4 +77,34 @@ public final class SecureSettingsServiceNameResolver implements ServiceNameResol
|
||||
public String toString() {
|
||||
return "SecureSettingsServiceNameResolver[" + mProperty + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] readServiceNameList(int userId) {
|
||||
return parseColonDelimitedServiceNames(
|
||||
Settings.Secure.getStringForUser(
|
||||
mContext.getContentResolver(), mProperty, userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readServiceName(int userId) {
|
||||
return Settings.Secure.getStringForUser(
|
||||
mContext.getContentResolver(), mProperty, userId);
|
||||
}
|
||||
|
||||
private String[] parseColonDelimitedServiceNames(String serviceNames) {
|
||||
final Set<String> delimitedServices = new ArraySet<>();
|
||||
if (!TextUtils.isEmpty(serviceNames)) {
|
||||
final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
|
||||
splitter.setString(serviceNames);
|
||||
while (splitter.hasNext()) {
|
||||
final String str = splitter.next();
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
continue;
|
||||
}
|
||||
delimitedServices.add(str);
|
||||
}
|
||||
}
|
||||
String[] delimitedServicesArray = new String[delimitedServices.size()];
|
||||
return delimitedServices.toArray(delimitedServicesArray);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.infra;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.AppGlobals;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Gets the service name using a framework resources, temporarily changing the service if necessary
|
||||
* (typically during CTS tests or service development).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class ServiceNameBaseResolver implements ServiceNameResolver {
|
||||
|
||||
private static final String TAG = ServiceNameBaseResolver.class.getSimpleName();
|
||||
|
||||
/** Handler message to {@link #resetTemporaryService(int)} */
|
||||
private static final int MSG_RESET_TEMPORARY_SERVICE = 0;
|
||||
|
||||
@NonNull
|
||||
protected final Context mContext;
|
||||
@NonNull
|
||||
protected final Object mLock = new Object();
|
||||
|
||||
protected final boolean mIsMultiple;
|
||||
/**
|
||||
* Map of temporary service name list set by {@link #setTemporaryServices(int, String[], int)},
|
||||
* keyed by {@code userId}.
|
||||
*
|
||||
* <p>Typically used by Shell command and/or CTS tests to configure temporary services if
|
||||
* mIsMultiple is true.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
protected final SparseArray<String[]> mTemporaryServiceNamesList = new SparseArray<>();
|
||||
/**
|
||||
* Map of default services that have been disabled by
|
||||
* {@link #setDefaultServiceEnabled(int, boolean)},keyed by {@code userId}.
|
||||
*
|
||||
* <p>Typically used by Shell command and/or CTS tests.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
protected final SparseBooleanArray mDefaultServicesDisabled = new SparseBooleanArray();
|
||||
@Nullable
|
||||
private NameResolverListener mOnSetCallback;
|
||||
/**
|
||||
* When the temporary service will expire (and reset back to the default).
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private long mTemporaryServiceExpiration;
|
||||
|
||||
/**
|
||||
* Handler used to reset the temporary service name.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private Handler mTemporaryHandler;
|
||||
|
||||
protected ServiceNameBaseResolver(Context context, boolean isMultiple) {
|
||||
mContext = context;
|
||||
mIsMultiple = isMultiple;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnTemporaryServiceNameChangedCallback(@NonNull NameResolverListener callback) {
|
||||
synchronized (mLock) {
|
||||
this.mOnSetCallback = callback;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceName(@UserIdInt int userId) {
|
||||
String[] serviceNames = getServiceNameList(userId);
|
||||
return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultServiceName(@UserIdInt int userId) {
|
||||
String[] serviceNames = getDefaultServiceNameList(userId);
|
||||
return (serviceNames == null || serviceNames.length == 0) ? null : serviceNames[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default list of the service names for the given user.
|
||||
*
|
||||
* <p>Typically implemented by services which want to provide multiple backends.
|
||||
*/
|
||||
@Override
|
||||
public String[] getServiceNameList(int userId) {
|
||||
synchronized (mLock) {
|
||||
String[] temporaryNames = mTemporaryServiceNamesList.get(userId);
|
||||
if (temporaryNames != null) {
|
||||
// Always log it, as it should only be used on CTS or during development
|
||||
Slog.w(TAG, "getServiceName(): using temporary name "
|
||||
+ Arrays.toString(temporaryNames) + " for user " + userId);
|
||||
return temporaryNames;
|
||||
}
|
||||
final boolean disabled = mDefaultServicesDisabled.get(userId);
|
||||
if (disabled) {
|
||||
// Always log it, as it should only be used on CTS or during development
|
||||
Slog.w(TAG, "getServiceName(): temporary name not set and default disabled for "
|
||||
+ "user " + userId);
|
||||
return null;
|
||||
}
|
||||
return getDefaultServiceNameList(userId);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base classes must override this to read from the desired config e.g. framework resource,
|
||||
* secure settings etc.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract String[] readServiceNameList(int userId);
|
||||
|
||||
/**
|
||||
* Base classes must override this to read from the desired config e.g. framework resource,
|
||||
* secure settings etc.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract String readServiceName(int userId);
|
||||
|
||||
/**
|
||||
* Gets the default list of the service names for the given user.
|
||||
*
|
||||
* <p>Typically implemented by services which want to provide multiple backends.
|
||||
*/
|
||||
@Override
|
||||
public String[] getDefaultServiceNameList(int userId) {
|
||||
synchronized (mLock) {
|
||||
if (mIsMultiple) {
|
||||
String[] serviceNameList = readServiceNameList(userId);
|
||||
// Filter out unimplemented services
|
||||
// Initialize the validated array as null because we do not know the final size.
|
||||
List<String> validatedServiceNameList = new ArrayList<>();
|
||||
try {
|
||||
for (int i = 0; i < serviceNameList.length; i++) {
|
||||
if (TextUtils.isEmpty(serviceNameList[i])) {
|
||||
continue;
|
||||
}
|
||||
ComponentName serviceComponent = ComponentName.unflattenFromString(
|
||||
serviceNameList[i]);
|
||||
ServiceInfo serviceInfo = AppGlobals.getPackageManager().getServiceInfo(
|
||||
serviceComponent,
|
||||
PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
|
||||
if (serviceInfo != null) {
|
||||
validatedServiceNameList.add(serviceNameList[i]);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.e(TAG, "Could not validate provided services.", e);
|
||||
}
|
||||
String[] validatedServiceNameArray = new String[validatedServiceNameList.size()];
|
||||
return validatedServiceNameList.toArray(validatedServiceNameArray);
|
||||
} else {
|
||||
final String name = readServiceName(userId);
|
||||
return TextUtils.isEmpty(name) ? new String[0] : new String[]{name};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfiguredInMultipleMode() {
|
||||
return mIsMultiple;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTemporary(@UserIdInt int userId) {
|
||||
synchronized (mLock) {
|
||||
return mTemporaryServiceNamesList.get(userId) != null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemporaryService(@UserIdInt int userId, @NonNull String componentName,
|
||||
int durationMs) {
|
||||
setTemporaryServices(userId, new String[]{componentName}, durationMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemporaryServices(int userId, @NonNull String[] componentNames, int durationMs) {
|
||||
synchronized (mLock) {
|
||||
mTemporaryServiceNamesList.put(userId, componentNames);
|
||||
|
||||
if (mTemporaryHandler == null) {
|
||||
mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == MSG_RESET_TEMPORARY_SERVICE) {
|
||||
synchronized (mLock) {
|
||||
resetTemporaryService(userId);
|
||||
}
|
||||
} else {
|
||||
Slog.wtf(TAG, "invalid handler msg: " + msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
|
||||
}
|
||||
mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs;
|
||||
mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs);
|
||||
for (int i = 0; i < componentNames.length; i++) {
|
||||
notifyTemporaryServiceNameChangedLocked(userId, componentNames[i],
|
||||
/* isTemporary= */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetTemporaryService(@UserIdInt int userId) {
|
||||
synchronized (mLock) {
|
||||
Slog.i(TAG, "resetting temporary service for user " + userId + " from "
|
||||
+ Arrays.toString(mTemporaryServiceNamesList.get(userId)));
|
||||
mTemporaryServiceNamesList.remove(userId);
|
||||
if (mTemporaryHandler != null) {
|
||||
mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
|
||||
mTemporaryHandler = null;
|
||||
}
|
||||
notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null,
|
||||
/* isTemporary= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setDefaultServiceEnabled(int userId, boolean enabled) {
|
||||
synchronized (mLock) {
|
||||
final boolean currentlyEnabled = isDefaultServiceEnabledLocked(userId);
|
||||
if (currentlyEnabled == enabled) {
|
||||
Slog.i(TAG, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
|
||||
return false;
|
||||
}
|
||||
if (enabled) {
|
||||
Slog.i(TAG, "disabling default service for user " + userId);
|
||||
mDefaultServicesDisabled.removeAt(userId);
|
||||
} else {
|
||||
Slog.i(TAG, "enabling default service for user " + userId);
|
||||
mDefaultServicesDisabled.put(userId, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaultServiceEnabled(int userId) {
|
||||
synchronized (mLock) {
|
||||
return isDefaultServiceEnabledLocked(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean isDefaultServiceEnabledLocked(int userId) {
|
||||
return !mDefaultServicesDisabled.get(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
synchronized (mLock) {
|
||||
return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNamesList + "]";
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/117779333): support proto
|
||||
@Override
|
||||
public void dumpShort(@NonNull PrintWriter pw, @UserIdInt int userId) {
|
||||
synchronized (mLock) {
|
||||
final String[] temporaryNames = mTemporaryServiceNamesList.get(userId);
|
||||
if (temporaryNames != null) {
|
||||
pw.print("tmpName=");
|
||||
pw.print(Arrays.toString(temporaryNames));
|
||||
final long ttl = mTemporaryServiceExpiration - SystemClock.elapsedRealtime();
|
||||
pw.print(" (expires in ");
|
||||
TimeUtils.formatDuration(ttl, pw);
|
||||
pw.print("), ");
|
||||
}
|
||||
pw.print("defaultName=");
|
||||
pw.print(getDefaultServiceName(userId));
|
||||
final boolean disabled = mDefaultServicesDisabled.get(userId);
|
||||
pw.println(disabled ? " (disabled)" : " (enabled)");
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyTemporaryServiceNameChangedLocked(@UserIdInt int userId,
|
||||
@Nullable String newTemporaryName, boolean isTemporary) {
|
||||
if (mOnSetCallback != null) {
|
||||
mOnSetCallback.onNameResolved(userId, newTemporaryName, isTemporary);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user