diff options
author | Robert Berry <robertberry@google.com> | 2019-03-18 16:33:42 -0400 |
---|---|---|
committer | Robert Berry <robertberry@google.com> | 2019-04-03 20:41:03 -0400 |
commit | e14120edf2cb2251b5ece810ef38eaadd27bc46d (patch) | |
tree | dc55ee0ef5412649d6a7fbeee1fe464b9b9d326f /services/systemcaptions | |
parent | 259c73c00704a48fe25505546ce4f721eb40de9b (diff) |
Add system captions manager service
This service connects to a remote system captions manager service. This
service is responsible for enabling system captions when the user
requests them. As the system binds to it, this service will be
persistent.
Bug: 128925852
Test: Manual. I created an implementation of the service.
Change-Id: Iafde1bb68f4754d8167624f47c6833d43c0ec336
Diffstat (limited to 'services/systemcaptions')
4 files changed, 343 insertions, 0 deletions
diff --git a/services/systemcaptions/Android.bp b/services/systemcaptions/Android.bp new file mode 100644 index 000000000000..4e190b639b2c --- /dev/null +++ b/services/systemcaptions/Android.bp @@ -0,0 +1,5 @@ +java_library_static { + name: "services.systemcaptions", + srcs: ["java/**/*.java"], + libs: ["services.core"], +} diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java b/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java new file mode 100644 index 000000000000..5480b6ced4e1 --- /dev/null +++ b/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java @@ -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; + } + } + } +} diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerPerUserService.java b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerPerUserService.java new file mode 100644 index 000000000000..b503670e9dcd --- /dev/null +++ b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerPerUserService.java @@ -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; + } +} diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java new file mode 100644 index 000000000000..27a116c8043e --- /dev/null +++ b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java @@ -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(); + } + } +} |