Merge "Add system captions manager service" into qt-dev

This commit is contained in:
TreeHugger Robot
2019-04-08 08:57:44 +00:00
committed by Android (Google) Code Review
10 changed files with 424 additions and 14 deletions

View File

@@ -3558,6 +3558,12 @@
--> -->
<string name="config_defaultSystemCaptionsService" translatable="false"></string> <string name="config_defaultSystemCaptionsService" translatable="false"></string>
<!-- The component name for the system-wide captions manager service.
This service must be trusted, as the system binds to it and keeps it running.
Example: "com.android.captions/.SystemCaptionsManagerService"
-->
<string name="config_defaultSystemCaptionsManagerService" translatable="false"></string>
<!-- The package name for the incident report approver app. <!-- The package name for the incident report approver app.
This app is usually PermissionController or an app that replaces it. When This app is usually PermissionController or an app that replaces it. When
a bugreport or incident report with EXPLICT-level sharing flags is going to be a bugreport or incident report with EXPLICT-level sharing flags is going to be

View File

@@ -3409,6 +3409,7 @@
<java-symbol type="string" name="config_defaultContentSuggestionsService" /> <java-symbol type="string" name="config_defaultContentSuggestionsService" />
<java-symbol type="string" name="config_defaultAttentionService" /> <java-symbol type="string" name="config_defaultAttentionService" />
<java-symbol type="string" name="config_defaultSystemCaptionsService" /> <java-symbol type="string" name="config_defaultSystemCaptionsService" />
<java-symbol type="string" name="config_defaultSystemCaptionsManagerService" />
<java-symbol type="string" name="notification_channel_foreground_service" /> <java-symbol type="string" name="notification_channel_foreground_service" />
<java-symbol type="string" name="foreground_service_app_in_background" /> <java-symbol type="string" name="foreground_service_app_in_background" />

View File

@@ -31,6 +31,7 @@ java_library {
"services.print", "services.print",
"services.restrictions", "services.restrictions",
"services.startop", "services.startop",
"services.systemcaptions",
"services.usage", "services.usage",
"services.usb", "services.usb",
"services.voiceinteraction", "services.voiceinteraction",

View File

@@ -129,7 +129,8 @@ public final class ContentCaptureManagerService extends
public ContentCaptureManagerService(@NonNull Context context) { public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context, super(context, new FrameworkResourcesServiceNameResolver(context,
com.android.internal.R.string.config_defaultContentCaptureService), com.android.internal.R.string.config_defaultContentCaptureService),
UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate= */ false); UserManager.DISALLOW_CONTENT_CAPTURE,
/*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_NO_REFRESH);
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE, DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
ActivityThread.currentApplication().getMainExecutor(), ActivityThread.currentApplication().getMainExecutor(),
(namespace, key, value) -> onDeviceConfigChange(key, value)); (namespace, key, value) -> onDeviceConfigChange(key, value));

View File

@@ -15,6 +15,7 @@
*/ */
package com.android.server.infra; package com.android.server.infra;
import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
@@ -45,6 +46,8 @@ import com.android.server.LocalServices;
import com.android.server.SystemService; import com.android.server.SystemService;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List; import java.util.List;
/** /**
@@ -75,6 +78,30 @@ import java.util.List;
public abstract class AbstractMasterSystemService<M extends AbstractMasterSystemService<M, S>, public abstract class AbstractMasterSystemService<M extends AbstractMasterSystemService<M, S>,
S extends AbstractPerUserSystemService<S, M>> extends SystemService { S extends AbstractPerUserSystemService<S, M>> extends SystemService {
/** On a package update, does not refresh the per-user service in the cache. */
public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0;
/**
* On a package update, removes any existing per-user services in the cache.
*
* <p>This does not immediately recreate these services. It is assumed they will be recreated
* for the next user request.
*/
public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 1;
/**
* On a package update, removes and recreates any existing per-user services in the cache.
*/
public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 2;
@IntDef(flag = true, prefix = { "PACKAGE_UPDATE_POLICY_" }, value = {
PACKAGE_UPDATE_POLICY_NO_REFRESH,
PACKAGE_UPDATE_POLICY_REFRESH_LAZY,
PACKAGE_UPDATE_POLICY_REFRESH_EAGER
})
@Retention(RetentionPolicy.SOURCE)
public @interface PackageUpdatePolicy {}
/** /**
* Log tag * Log tag
*/ */
@@ -127,8 +154,11 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
/** /**
* Whether the per-user service should be removed from the cache when its apk is updated. * Whether the per-user service should be removed from the cache when its apk is updated.
*
* <p>One of {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
* {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY} or {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}.
*/ */
private final boolean mRefreshServiceOnPackageUpdate; private final @PackageUpdatePolicy int mPackageUpdatePolicy;
/** /**
* Name of the service packages whose APK are being updated, keyed by user id. * Name of the service packages whose APK are being updated, keyed by user id.
@@ -154,7 +184,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
@Nullable ServiceNameResolver serviceNameResolver, @Nullable ServiceNameResolver serviceNameResolver,
@Nullable String disallowProperty) { @Nullable String disallowProperty) {
this(context, serviceNameResolver, disallowProperty, this(context, serviceNameResolver, disallowProperty,
/* refreshServiceOnPackageUpdate=*/ true); /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_LAZY);
} }
/** /**
@@ -167,17 +197,19 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
* @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
* disables the service. <b>NOTE: </b> you'll also need to add it to * disables the service. <b>NOTE: </b> you'll also need to add it to
* {@code UserRestrictionsUtils.USER_RESTRICTIONS}. * {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
* @param refreshServiceOnPackageUpdate when {@code true}, the * @param packageUpdatePolicy when {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY}, the
* {@link AbstractPerUserSystemService} is removed from the cache (and re-added) when the * {@link AbstractPerUserSystemService} is removed from the cache when the service
* service package is updated; when {@code false}, the service is untouched during the * package is updated; when {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}, the
* update. * {@link AbstractPerUserSystemService} is removed from the cache and immediately
* re-added when the service package is updated; when
* {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH}, the service is untouched during the update.
*/ */
protected AbstractMasterSystemService(@NonNull Context context, protected AbstractMasterSystemService(@NonNull Context context,
@Nullable ServiceNameResolver serviceNameResolver, @Nullable ServiceNameResolver serviceNameResolver,
@Nullable String disallowProperty, boolean refreshServiceOnPackageUpdate) { @Nullable String disallowProperty, @PackageUpdatePolicy int packageUpdatePolicy) {
super(context); super(context);
mRefreshServiceOnPackageUpdate = refreshServiceOnPackageUpdate; mPackageUpdatePolicy = packageUpdatePolicy;
mServiceNameResolver = serviceNameResolver; mServiceNameResolver = serviceNameResolver;
if (mServiceNameResolver != null) { if (mServiceNameResolver != null) {
@@ -645,7 +677,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
final int size = mServicesCache.size(); final int size = mServicesCache.size();
pw.print(prefix); pw.print("Debug: "); pw.print(realDebug); pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
pw.print(" Verbose: "); pw.println(realVerbose); pw.print(" Verbose: "); pw.println(realVerbose);
pw.print("Refresh on package update: "); pw.println(mRefreshServiceOnPackageUpdate); pw.print("Refresh on package update: "); pw.println(mPackageUpdatePolicy);
if (mUpdatingPackageNames != null) { if (mUpdatingPackageNames != null) {
pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames); pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
} }
@@ -701,12 +733,21 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
} }
mUpdatingPackageNames.put(userId, packageName); mUpdatingPackageNames.put(userId, packageName);
onServicePackageUpdatingLocked(userId); onServicePackageUpdatingLocked(userId);
if (mRefreshServiceOnPackageUpdate) { if (mPackageUpdatePolicy != PACKAGE_UPDATE_POLICY_NO_REFRESH) {
if (debug) { if (debug) {
Slog.d(mTag, "Removing service for user " + userId + " because package " Slog.d(mTag, "Removing service for user " + userId
+ activePackageName + " is being updated"); + " because package " + activePackageName
+ " is being updated");
} }
removeCachedServiceLocked(userId); removeCachedServiceLocked(userId);
if (mPackageUpdatePolicy == PACKAGE_UPDATE_POLICY_REFRESH_EAGER) {
if (debug) {
Slog.d(mTag, "Eagerly recreating service for user "
+ userId);
}
getServiceForUserLocked(userId);
}
} else { } else {
if (debug) { if (debug) {
Slog.d(mTag, "Holding service for user " + userId + " while package " Slog.d(mTag, "Holding service for user " + userId + " while package "

View File

@@ -254,6 +254,8 @@ public final class SystemServer {
"com.android.server.autofill.AutofillManagerService"; "com.android.server.autofill.AutofillManagerService";
private static final String CONTENT_CAPTURE_MANAGER_SERVICE_CLASS = private static final String CONTENT_CAPTURE_MANAGER_SERVICE_CLASS =
"com.android.server.contentcapture.ContentCaptureManagerService"; "com.android.server.contentcapture.ContentCaptureManagerService";
private static final String SYSTEM_CAPTIONS_MANAGER_SERVICE_CLASS =
"com.android.server.systemcaptions.SystemCaptionsManagerService";
private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS = private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS =
"com.android.server.timezone.RulesManagerService$Lifecycle"; "com.android.server.timezone.RulesManagerService$Lifecycle";
private static final String IOT_SERVICE_CLASS = private static final String IOT_SERVICE_CLASS =
@@ -1232,6 +1234,8 @@ public final class SystemServer {
startContentCaptureService(context); startContentCaptureService(context);
startAttentionService(context); startAttentionService(context);
startSystemCaptionsManagerService(context);
// App prediction manager service // App prediction manager service
traceBeginAndSlog("StartAppPredictionService"); traceBeginAndSlog("StartAppPredictionService");
mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS); mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
@@ -2225,6 +2229,19 @@ public final class SystemServer {
}, BOOT_TIMINGS_TRACE_LOG); }, BOOT_TIMINGS_TRACE_LOG);
} }
private void startSystemCaptionsManagerService(@NonNull Context context) {
String serviceName = context.getString(
com.android.internal.R.string.config_defaultSystemCaptionsManagerService);
if (TextUtils.isEmpty(serviceName)) {
Slog.d(TAG, "SystemCaptionsManagerService disabled because resource is not overlaid");
return;
}
traceBeginAndSlog("StartSystemCaptionsManagerService");
mSystemServiceManager.startService(SYSTEM_CAPTIONS_MANAGER_SERVICE_CLASS);
traceEnd();
}
private void startContentCaptureService(@NonNull Context context) { private void startContentCaptureService(@NonNull Context context) {
// First check if it was explicitly enabled by DeviceConfig // First check if it was explicitly enabled by DeviceConfig
boolean explicitlyEnabled = false; boolean explicitlyEnabled = false;
@@ -2273,7 +2290,7 @@ public final class SystemServer {
traceEnd(); traceEnd();
} }
static final void startSystemUi(Context context, WindowManagerService windowManager) { private static void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui", intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService")); "com.android.systemui.SystemUIService"));

View File

@@ -0,0 +1,5 @@
java_library_static {
name: "services.systemcaptions",
srcs: ["java/**/*.java"],
libs: ["services.core"],
}

View File

@@ -0,0 +1,164 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.systemcaptions;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
/** Manages the connection to the remote system captions manager service. */
final class RemoteSystemCaptionsManagerService {
private static final String TAG = RemoteSystemCaptionsManagerService.class.getSimpleName();
private static final String SERVICE_INTERFACE =
"android.service.systemcaptions.SystemCaptionsManagerService";
private final Object mLock = new Object();
private final Context mContext;
private final Intent mIntent;
private final ComponentName mComponentName;
private final int mUserId;
private final boolean mVerbose;
private final Handler mHandler;
private final RemoteServiceConnection mServiceConnection = new RemoteServiceConnection();
@GuardedBy("mLock")
@Nullable private IBinder mService;
@GuardedBy("mLock")
private boolean mBinding = false;
@GuardedBy("mLock")
private boolean mDestroyed = false;
RemoteSystemCaptionsManagerService(
Context context, ComponentName componentName, int userId, boolean verbose) {
mContext = context;
mComponentName = componentName;
mUserId = userId;
mVerbose = verbose;
mIntent = new Intent(SERVICE_INTERFACE).setComponent(componentName);
mHandler = new Handler(Looper.getMainLooper());
}
void initialize() {
if (mVerbose) {
Slog.v(TAG, "initialize()");
}
ensureBound();
}
void destroy() {
if (mVerbose) {
Slog.v(TAG, "destroy()");
}
synchronized (mLock) {
if (mDestroyed) {
if (mVerbose) {
Slog.v(TAG, "destroy(): Already destroyed");
}
return;
}
mDestroyed = true;
ensureUnboundLocked();
}
}
boolean isDestroyed() {
synchronized (mLock) {
return mDestroyed;
}
}
private void ensureBound() {
synchronized (mLock) {
if (mService != null || mBinding) {
return;
}
if (mVerbose) {
Slog.v(TAG, "ensureBound(): binding");
}
mBinding = true;
int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
mHandler, new UserHandle(mUserId));
if (!willBind) {
Slog.w(TAG, "Could not bind to " + mIntent + " with flags " + flags);
mBinding = false;
mService = null;
}
}
}
@GuardedBy("mLock")
private void ensureUnboundLocked() {
if (mService == null && !mBinding) {
return;
}
mBinding = false;
mService = null;
if (mVerbose) {
Slog.v(TAG, "ensureUnbound(): unbinding");
}
mContext.unbindService(mServiceConnection);
}
private class RemoteServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
if (mVerbose) {
Slog.v(TAG, "onServiceConnected()");
}
if (mDestroyed || !mBinding) {
Slog.wtf(TAG, "onServiceConnected() dispatched after unbindService");
return;
}
mBinding = false;
mService = service;
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
synchronized (mLock) {
if (mVerbose) {
Slog.v(TAG, "onServiceDisconnected()");
}
mBinding = true;
mService = null;
}
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.systemcaptions;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.RemoteException;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.infra.AbstractPerUserSystemService;
/** Manages the captions manager service on a per-user basis. */
final class SystemCaptionsManagerPerUserService extends
AbstractPerUserSystemService<SystemCaptionsManagerPerUserService,
SystemCaptionsManagerService> {
private static final String TAG = SystemCaptionsManagerPerUserService.class.getSimpleName();
@Nullable
@GuardedBy("mLock")
private RemoteSystemCaptionsManagerService mRemoteService;
SystemCaptionsManagerPerUserService(
@NonNull SystemCaptionsManagerService master,
@NonNull Object lock, boolean disabled, @UserIdInt int userId) {
super(master, lock, userId);
}
@Override
@NonNull
protected ServiceInfo newServiceInfoLocked(
@SuppressWarnings("unused") @NonNull ComponentName serviceComponent)
throws PackageManager.NameNotFoundException {
try {
return AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
PackageManager.GET_META_DATA, mUserId);
} catch (RemoteException e) {
throw new PackageManager.NameNotFoundException(
"Could not get service for " + serviceComponent);
}
}
@GuardedBy("mLock")
void initializeLocked() {
if (mMaster.verbose) {
Slog.v(TAG, "initialize()");
}
RemoteSystemCaptionsManagerService service = getRemoteServiceLocked();
if (service == null && mMaster.verbose) {
Slog.v(TAG, "initialize(): Failed to init remote server");
}
}
@GuardedBy("mLock")
void destroyLocked() {
if (mMaster.verbose) {
Slog.v(TAG, "destroyLocked()");
}
if (mRemoteService != null) {
mRemoteService.destroy();
mRemoteService = null;
}
}
@GuardedBy("mLock")
@Nullable
private RemoteSystemCaptionsManagerService getRemoteServiceLocked() {
if (mRemoteService == null) {
String serviceName = getComponentNameLocked();
if (serviceName == null) {
if (mMaster.verbose) {
Slog.v(TAG, "getRemoteServiceLocked(): Not set");
}
return null;
}
ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
mRemoteService = new RemoteSystemCaptionsManagerService(
getContext(),
serviceComponent,
mUserId,
mMaster.verbose);
if (mMaster.verbose) {
Slog.v(TAG, "getRemoteServiceLocked(): initialize for user " + mUserId);
}
mRemoteService.initialize();
}
return mRemoteService;
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.systemcaptions;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
import com.android.server.infra.AbstractMasterSystemService;
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
/** A system service to bind to a remote system captions manager service. */
public final class SystemCaptionsManagerService extends
AbstractMasterSystemService<SystemCaptionsManagerService,
SystemCaptionsManagerPerUserService> {
public SystemCaptionsManagerService(@NonNull Context context) {
super(context,
new FrameworkResourcesServiceNameResolver(
context,
com.android.internal.R.string.config_defaultSystemCaptionsManagerService),
/*disallowProperty=*/ null,
/*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
}
@Override
public void onStart() {
// Do nothing. This service does not publish any local or system services.
}
@Override
protected SystemCaptionsManagerPerUserService newServiceLocked(
@UserIdInt int resolvedUserId, boolean disabled) {
SystemCaptionsManagerPerUserService perUserService =
new SystemCaptionsManagerPerUserService(this, mLock, disabled, resolvedUserId);
perUserService.initializeLocked();
return perUserService;
}
@Override
protected void onServiceRemoved(
SystemCaptionsManagerPerUserService service, @UserIdInt int userId) {
synchronized (mLock) {
service.destroyLocked();
}
}
}