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>
<!-- 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.
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

View File

@@ -3409,6 +3409,7 @@
<java-symbol type="string" name="config_defaultContentSuggestionsService" />
<java-symbol type="string" name="config_defaultAttentionService" />
<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="foreground_service_app_in_background" />

View File

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

View File

@@ -129,7 +129,8 @@ public final class ContentCaptureManagerService extends
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
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,
ActivityThread.currentApplication().getMainExecutor(),
(namespace, key, value) -> onDeviceConfigChange(key, value));

View File

@@ -15,6 +15,7 @@
*/
package com.android.server.infra;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -45,6 +46,8 @@ import com.android.server.LocalServices;
import com.android.server.SystemService;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -75,6 +78,30 @@ import java.util.List;
public abstract class AbstractMasterSystemService<M extends AbstractMasterSystemService<M, S>,
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
*/
@@ -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.
*
* <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.
@@ -154,7 +184,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
@Nullable ServiceNameResolver serviceNameResolver,
@Nullable String 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
* disables the service. <b>NOTE: </b> you'll also need to add it to
* {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
* @param refreshServiceOnPackageUpdate when {@code true}, the
* {@link AbstractPerUserSystemService} is removed from the cache (and re-added) when the
* service package is updated; when {@code false}, the service is untouched during the
* update.
* @param packageUpdatePolicy when {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY}, the
* {@link AbstractPerUserSystemService} is removed from the cache when the service
* package is updated; when {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}, the
* {@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,
@Nullable ServiceNameResolver serviceNameResolver,
@Nullable String disallowProperty, boolean refreshServiceOnPackageUpdate) {
@Nullable String disallowProperty, @PackageUpdatePolicy int packageUpdatePolicy) {
super(context);
mRefreshServiceOnPackageUpdate = refreshServiceOnPackageUpdate;
mPackageUpdatePolicy = packageUpdatePolicy;
mServiceNameResolver = serviceNameResolver;
if (mServiceNameResolver != null) {
@@ -645,7 +677,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
final int size = mServicesCache.size();
pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
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) {
pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
}
@@ -701,12 +733,21 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
}
mUpdatingPackageNames.put(userId, packageName);
onServicePackageUpdatingLocked(userId);
if (mRefreshServiceOnPackageUpdate) {
if (mPackageUpdatePolicy != PACKAGE_UPDATE_POLICY_NO_REFRESH) {
if (debug) {
Slog.d(mTag, "Removing service for user " + userId + " because package "
+ activePackageName + " is being updated");
Slog.d(mTag, "Removing service for user " + userId
+ " because package " + activePackageName
+ " is being updated");
}
removeCachedServiceLocked(userId);
if (mPackageUpdatePolicy == PACKAGE_UPDATE_POLICY_REFRESH_EAGER) {
if (debug) {
Slog.d(mTag, "Eagerly recreating service for user "
+ userId);
}
getServiceForUserLocked(userId);
}
} else {
if (debug) {
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";
private static final String CONTENT_CAPTURE_MANAGER_SERVICE_CLASS =
"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 =
"com.android.server.timezone.RulesManagerService$Lifecycle";
private static final String IOT_SERVICE_CLASS =
@@ -1232,6 +1234,8 @@ public final class SystemServer {
startContentCaptureService(context);
startAttentionService(context);
startSystemCaptionsManagerService(context);
// App prediction manager service
traceBeginAndSlog("StartAppPredictionService");
mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
@@ -2225,6 +2229,19 @@ public final class SystemServer {
}, 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) {
// First check if it was explicitly enabled by DeviceConfig
boolean explicitlyEnabled = false;
@@ -2273,7 +2290,7 @@ public final class SystemServer {
traceEnd();
}
static final void startSystemUi(Context context, WindowManagerService windowManager) {
private static void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"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();
}
}
}