aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdnan Begovic <adnan@cyngn.com>2016-06-21 13:55:18 -0700
committerAdnan Begovic <adnan@cyngn.com>2016-07-01 10:41:53 -0700
commitb62a4550c300171dd8845831393bab2209814460 (patch)
tree4865e16a5976123e8975d9b41e70698323628352
parent551b377da9a3e92f5103a52b0b92ad72e72d6f89 (diff)
downloadvendor_cmsdk-b62a4550c300171dd8845831393bab2209814460.zip
vendor_cmsdk-b62a4550c300171dd8845831393bab2209814460.tar.gz
vendor_cmsdk-b62a4550c300171dd8845831393bab2209814460.tar.bz2
cmsdk: Create brokerablecmsystemservice concept.
Extending the BrokerableCMSystemService allows a core system service to declare a delegate provider interface that can exist in another package, either in the same or an external process. Change-Id: Idf8d170b1504528b0d3aafb23895951e26459c98
-rw-r--r--cm/lib/main/java/org/cyanogenmod/platform/internal/BrokerableCMSystemService.java234
-rw-r--r--cm/lib/main/java/org/cyanogenmod/platform/internal/LiveLockScreenServiceBroker.java218
-rw-r--r--cm/lib/main/java/org/cyanogenmod/platform/internal/common/BrokeredServiceConnection.java38
-rw-r--r--cm/res/AndroidManifest.xml6
4 files changed, 341 insertions, 155 deletions
diff --git a/cm/lib/main/java/org/cyanogenmod/platform/internal/BrokerableCMSystemService.java b/cm/lib/main/java/org/cyanogenmod/platform/internal/BrokerableCMSystemService.java
new file mode 100644
index 0000000..76bad9f
--- /dev/null
+++ b/cm/lib/main/java/org/cyanogenmod/platform/internal/BrokerableCMSystemService.java
@@ -0,0 +1,234 @@
+/**
+ * Copyright (C) 2016 The CyanogenMod 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 org.cyanogenmod.platform.internal;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import cyanogenmod.platform.Manifest;
+
+import com.android.internal.util.Preconditions;
+
+import org.cyanogenmod.platform.internal.common.BrokeredServiceConnection;
+
+public abstract class BrokerableCMSystemService<T extends IInterface> extends CMSystemService {
+ private static final String TAG = BrokerableCMSystemService.class.getSimpleName();
+
+ private static final int MSG_TRY_CONNECTING = 1;
+ private static final long SERVICE_CONNECTION_WAIT_TIME_MS = 4 * 1000L; // 4 seconds
+ private Context mContext;
+
+ private BrokeredServiceConnection mBrokeredServiceConnection;
+ private T mImplementingBinderInterface;
+
+ public BrokerableCMSystemService(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ /**
+ * Called when the {@link IInterface} contract for the given {@link IBinder} is to
+ * be assigned for the implementing service {@link T}
+ * @param service
+ * @return {@link T}
+ */
+ protected abstract T getIBinderAsIInterface(@NonNull IBinder service);
+
+ /**
+ * Called when necessary as the default implementation. (usually a failure implementation)
+ * For when an implementing service is not found, is updating, or is failing.
+ * @return {@link T}
+ */
+ protected abstract T getDefaultImplementation();
+
+ /**
+ * Called when attempting to connect to the a given {@link T} implementation. Defines
+ * the {@link ComponentName} to be used for the binding operation.
+ *
+ * By default, the calling component MUST gate its implementation by the
+ * {@link Manifest.permission.BIND_CORE_SERVICE} permission as well as using,
+ * the permission granted to its own package.
+ *
+ * This permission can be overridden via {@link #getComponentFilteringPermission()}
+ *
+ * @return {@link ComponentName}
+ */
+ @Nullable
+ protected abstract ComponentName getServiceComponent();
+
+ /**
+ * Override this method if your broker will provide its own permission for guarding a vertical
+ * api defintion. Otherwise, the component from {@link #getServiceComponent()}
+ * will be gated via the {@link Manifest.permission.BIND_CORE_SERVICE} permission.
+ *
+ * @return boolean
+ */
+ @NonNull
+ protected String getComponentFilteringPermission() {
+ return Manifest.permission.BIND_CORE_SERVICE;
+ }
+
+ /**
+ * Set a {@link BrokeredServiceConnection} to receive callbacks when an implementation is
+ * connected or disconnected.
+ * @param brokeredServiceComponent
+ */
+ public final void setBrokeredServiceConnection(
+ @NonNull BrokeredServiceConnection brokeredServiceComponent) {
+ Preconditions.checkNotNull(brokeredServiceComponent);
+ Slog.e(TAG, "Setting brokered service connection "
+ + brokeredServiceComponent.toString());
+ mBrokeredServiceConnection = brokeredServiceComponent;
+ }
+
+ /**
+ * Get the implementing service for the given binder invocation. Usually called from a binder
+ * thread in a subclassed service.
+ * @return {@link T} that represents the implementing service
+ */
+ public final T getBrokeredService() {
+ final T service = getOrConnectService();
+ if (service != null) {
+ return service;
+ }
+ return getDefaultImplementation();
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ super.onBootPhase(phase);
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ Slog.d(TAG, "Third party apps ready");
+ tryConnecting();
+ }
+ }
+
+ private T getOrConnectService() {
+ synchronized (this) {
+ if (mImplementingBinderInterface != null) {
+ return mImplementingBinderInterface;
+ }
+ // Service is not connected. Try blocking connecting.
+ mConnectionHandler.sendMessage(
+ mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING));
+ final long shouldEnd =
+ SystemClock.elapsedRealtime() + SERVICE_CONNECTION_WAIT_TIME_MS;
+ long waitTime = SERVICE_CONNECTION_WAIT_TIME_MS;
+ while (waitTime > 0) {
+ try {
+ // TODO: consider using Java concurrent construct instead of raw object wait
+ this.wait(waitTime);
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "Connection wait interrupted", e);
+ }
+ if (mImplementingBinderInterface != null) {
+ // Success
+ return mImplementingBinderInterface;
+ }
+ // Calculate remaining waiting time to make sure we wait the full timeout period
+ waitTime = shouldEnd - SystemClock.elapsedRealtime();
+ }
+ return null;
+ }
+ }
+
+ private final Handler mConnectionHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_TRY_CONNECTING:
+ tryConnecting();
+ break;
+ default:
+ Slog.e(TAG, "Unknown message");
+ }
+ }
+ };
+
+ /**
+ * Attempt to connect to the component which is going to serve {@link T}
+ * interface contract implementation.
+ */
+ public final void tryConnecting() {
+ Slog.i(TAG, "Connecting to implementation");
+ synchronized (this) {
+ if (mImplementingBinderInterface != null) {
+ Slog.d(TAG, "Already connected");
+ return;
+ }
+ final Intent intent = new Intent();
+ final ComponentName cn = getServiceComponent();
+ if (cn == null) {
+ Slog.e(TAG, "No implementation service found");
+ return;
+ }
+ intent.setComponent(cn);
+ try {
+ if (mContext.getPackageManager().checkPermission(
+ getComponentFilteringPermission(),
+ cn.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
+ Slog.e(TAG, "Target component lacks " + getComponentFilteringPermission()
+ + " service permission, failing " + cn);
+ return;
+ }
+ if (!mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ Slog.e(TAG, "Failed to bind to implementation " + cn);
+ }
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Forbidden to bind to implementation " + cn, e);
+ }
+ }
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Slog.i(TAG, "Implementation service connected");
+ synchronized (BrokerableCMSystemService.this) {
+ mImplementingBinderInterface = getIBinderAsIInterface(service);
+ BrokerableCMSystemService.this.notifyAll();
+ if (mBrokeredServiceConnection != null) {
+ Slog.i(TAG, "Notifying service connected");
+ mBrokeredServiceConnection.onBrokeredServiceConnected();
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Slog.i(TAG, "Implementation service unexpectedly disconnected");
+ synchronized (BrokerableCMSystemService.this) {
+ mImplementingBinderInterface = null;
+ BrokerableCMSystemService.this.notifyAll();
+ if (mBrokeredServiceConnection != null) {
+ mBrokeredServiceConnection.onBrokeredServiceDisconnected();
+ }
+ }
+ }
+ };
+}
diff --git a/cm/lib/main/java/org/cyanogenmod/platform/internal/LiveLockScreenServiceBroker.java b/cm/lib/main/java/org/cyanogenmod/platform/internal/LiveLockScreenServiceBroker.java
index a142f1f..e133aa6 100644
--- a/cm/lib/main/java/org/cyanogenmod/platform/internal/LiveLockScreenServiceBroker.java
+++ b/cm/lib/main/java/org/cyanogenmod/platform/internal/LiveLockScreenServiceBroker.java
@@ -26,6 +26,7 @@ import android.content.pm.ResolveInfo;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IInterface;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -44,6 +45,8 @@ import cyanogenmod.app.LiveLockScreenManager;
import cyanogenmod.platform.Manifest;
import cyanogenmod.providers.CMSettings;
+import org.cyanogenmod.platform.internal.common.BrokeredServiceConnection;
+
import java.util.List;
/**
@@ -52,20 +55,15 @@ import java.util.List;
*
* @hide
*/
-public class LiveLockScreenServiceBroker extends CMSystemService {
+public class LiveLockScreenServiceBroker extends
+ BrokerableCMSystemService<ILiveLockScreenManagerProvider> {
private static final String TAG = LiveLockScreenServiceBroker.class.getSimpleName();
private static final boolean DEBUG = false;
- private static final int MSG_TRY_CONNECTING = 1;
-
- private static final long SERVICE_CONNECTION_WAIT_TIME_MS = 4 * 1000L; // 4 seconds
-
private static final String DEPRECATED_THIRD_PARTY_KEYGUARD_PERMISSION =
"android.permission.THIRD_PARTY_KEYGUARD";
private Context mContext;
- // The actual LLS service to invoke
- private ILiveLockScreenManagerProvider mService;
// Cached change listeners
private final RemoteCallbackList<ILiveLockScreenChangeListener> mChangeListeners =
@@ -73,53 +71,6 @@ public class LiveLockScreenServiceBroker extends CMSystemService {
private LiveLockScreenInfo mDefaultLlsInfo;
- private final Handler mConnectionHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_TRY_CONNECTING:
- tryConnecting();
- break;
- default:
- Slog.e(TAG, "Unknown message");
- }
- }
- };
-
- private ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- Slog.i(TAG, "LiveLockScreenManagerService connected");
- synchronized (LiveLockScreenServiceBroker.this) {
- mService = ILiveLockScreenManagerProvider.Stub.asInterface(service);
- LiveLockScreenServiceBroker.this.notifyAll();
- // If any change listeners are cached, register them with the newly connected
- // service.
- try {
- int N = mChangeListeners.beginBroadcast();
- if (mService != null && N > 0) {
- for (int i = 0; i < N; i++) {
- mService.registerChangeListener(mChangeListeners.getBroadcastItem(i));
- }
- }
- } catch (RemoteException e) {
- /* ignore */
- } finally {
- mChangeListeners.finishBroadcast();
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Slog.i(TAG, "LiveLockScreenManagerService unexpectedly disconnected");
- synchronized (LiveLockScreenServiceBroker.this) {
- mService = null;
- LiveLockScreenServiceBroker.this.notifyAll();
- }
- }
- };
-
/**
* ILiveLockScreenManager implementation to use when no backing service can be found.
*/
@@ -172,17 +123,17 @@ public class LiveLockScreenServiceBroker extends CMSystemService {
@Override
public void enqueueLiveLockScreen(String pkg, int id,
LiveLockScreenInfo lls, int[] idReceived, int userId) throws RemoteException {
- getServiceGuarded().enqueueLiveLockScreen(pkg, id, lls, idReceived, userId);
+ getBrokeredService().enqueueLiveLockScreen(pkg, id, lls, idReceived, userId);
}
@Override
public void cancelLiveLockScreen(String pkg, int id, int userId) throws RemoteException {
- getServiceGuarded().cancelLiveLockScreen(pkg, id, userId);
+ getBrokeredService().cancelLiveLockScreen(pkg, id, userId);
}
@Override
public LiveLockScreenInfo getCurrentLiveLockScreen() throws RemoteException {
- return getServiceGuarded().getCurrentLiveLockScreen();
+ return getBrokeredService().getCurrentLiveLockScreen();
}
@Override
@@ -205,23 +156,23 @@ public class LiveLockScreenServiceBroker extends CMSystemService {
@Override
public boolean getLiveLockScreenEnabled() throws RemoteException {
- return getServiceGuarded().getLiveLockScreenEnabled();
+ return getBrokeredService().getLiveLockScreenEnabled();
}
@Override
public boolean registerChangeListener(
ILiveLockScreenChangeListener listener) throws RemoteException {
- boolean registered = getServiceGuarded().registerChangeListener(listener);
+ boolean registered = getBrokeredService().registerChangeListener(listener);
if (registered) {
mChangeListeners.register(listener);
}
- return getServiceGuarded().registerChangeListener(listener);
+ return registered;
}
@Override
public boolean unregisterChangeListener(
ILiveLockScreenChangeListener listener) throws RemoteException {
- boolean unregistered = getServiceGuarded().unregisterChangeListener(listener);
+ boolean unregistered = getBrokeredService().unregisterChangeListener(listener);
if (unregistered) {
mChangeListeners.unregister(listener);
}
@@ -232,6 +183,7 @@ public class LiveLockScreenServiceBroker extends CMSystemService {
public LiveLockScreenServiceBroker(Context context) {
super(context);
mContext = context;
+ setBrokeredServiceConnection(mServiceConnection);
}
@Override
@@ -246,121 +198,79 @@ public class LiveLockScreenServiceBroker extends CMSystemService {
}
@Override
- public void onBootPhase(int phase) {
- if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
- if (DEBUG) Slog.d(TAG, "Third party apps ready");
+ protected ILiveLockScreenManagerProvider getIBinderAsIInterface(IBinder service) {
+ return ILiveLockScreenManagerProvider.Stub.asInterface(service);
+ }
- // Initialize the default LLS component
- String defComponent = CMSettings.Secure.getString(mContext.getContentResolver(),
- CMSettings.Secure.DEFAULT_LIVE_LOCK_SCREEN_COMPONENT);
- if (!TextUtils.isEmpty(defComponent)) {
- mDefaultLlsInfo = new LiveLockScreenInfo.Builder()
- .setComponent(ComponentName.unflattenFromString(defComponent))
- .build();
- }
- // Now that 3rd party apps are ready, try connecting to the backing service
- tryConnecting();
- }
+ @Override
+ public ILiveLockScreenManagerProvider getDefaultImplementation() {
+ return mServiceStubForFailure;
}
- /**
- * Binds to the backing service if one is found
- */
- private void tryConnecting() {
- Slog.i(TAG, "Connecting to LiveLockScreenManagerService");
- synchronized (this) {
- if (mService != null) {
- Slog.d(TAG, "Already connected");
- return;
- }
- final Intent intent = new Intent();
- final ComponentName cn = getLiveLockScreenServiceComponent();
- if (cn == null) {
- Slog.e(TAG, "No live lock screen manager service found");
- return;
- }
- intent.setComponent(getLiveLockScreenServiceComponent());
+ private BrokeredServiceConnection mServiceConnection = new BrokeredServiceConnection() {
+ @Override
+ public void onBrokeredServiceConnected() {
+ // If any change listeners are cached, register them with the newly connected
+ // service.
try {
- if (!mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
- Slog.e(TAG, "Failed to bind to LiveLockScreenManagerService");
+ int N = mChangeListeners.beginBroadcast();
+ ILiveLockScreenManagerProvider iLiveLockScreenManagerProvider =
+ getBrokeredService();
+ if (iLiveLockScreenManagerProvider != null && N > 0) {
+ for (int i = 0; i < N; i++) {
+ iLiveLockScreenManagerProvider
+ .registerChangeListener(mChangeListeners.getBroadcastItem(i));
+ }
}
- } catch (SecurityException e) {
- Slog.e(TAG, "Forbidden to bind to LiveLockScreenManagerService", e);
+ } catch (RemoteException e) {
+ /* ignore */
+ } finally {
+ mChangeListeners.finishBroadcast();
}
}
+
+ @Override
+ public void onBrokeredServiceDisconnected() {
+
+ }
+ };
+
+ @Override
+ protected String getComponentFilteringPermission() {
+ // Live lock screen service has its own vertical providing permission
+ return Manifest.permission.LIVE_LOCK_SCREEN_MANAGER_PROVIDER;
}
- /**
- * Queries package manager for the component which handles the
- * {@link LiveLockScreenManager#SERVICE_INTERFACE} and has been granted the
- * {@link org.cyanogenmod.platform.internal.Manifest.permission#LIVE_LOCK_SCREEN_MANAGER_PROVIDER}
- * permission.
- *
- * @return A valid component that supports {@link LiveLockScreenManager#SERVICE_INTERFACE} or
- * null if no component can be found.
- */
- @Nullable private ComponentName getLiveLockScreenServiceComponent() {
+ @Override
+ protected ComponentName getServiceComponent() {
PackageManager pm = mContext.getPackageManager();
Intent intent = new Intent(LiveLockScreenManager.SERVICE_INTERFACE);
List<ResolveInfo> resolveInfos = pm.queryIntentServices(intent, 0);
for (ResolveInfo info : resolveInfos) {
if (info != null) {
- if (pm.checkPermission(Manifest.permission.LIVE_LOCK_SCREEN_MANAGER_PROVIDER,
- info.serviceInfo.packageName) == PackageManager.PERMISSION_GRANTED &&
- info.serviceInfo.isEnabled()) {
+ if (info.serviceInfo.isEnabled()) {
return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
}
}
}
-
return null;
}
- private ILiveLockScreenManagerProvider getOrConnectService() {
- synchronized (this) {
- if (mService != null) {
- return mService;
- }
- // Service is not connected. Try blocking connecting.
- Slog.w(TAG, "LiveLockScreenManagerService not connected. Try connecting...");
- mConnectionHandler.sendMessage(
- mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING));
- final long shouldEnd =
- SystemClock.elapsedRealtime() + SERVICE_CONNECTION_WAIT_TIME_MS;
- long waitTime = SERVICE_CONNECTION_WAIT_TIME_MS;
- while (waitTime > 0) {
- try {
- // TODO: consider using Java concurrent construct instead of raw object wait
- this.wait(waitTime);
- } catch (InterruptedException e) {
- Slog.w(TAG, "Connection wait interrupted", e);
- }
- if (mService != null) {
- // Success
- return mService;
- }
- // Calculate remaining waiting time to make sure we wait the full timeout period
- waitTime = shouldEnd - SystemClock.elapsedRealtime();
- }
- // Timed out. Something's really wrong.
- Slog.e(TAG, "Can not connect to LiveLockScreenManagerService (timed out)");
- return null;
- }
- }
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ if (DEBUG) Slog.d(TAG, "Third party apps ready");
- /**
- * Make sure to return a non-empty service instance. Return the connected LiveLockScreenManager
- * instance, if not connected, try connecting. If fail to connect, return a fake service
- * instance which returns failure to service caller.
- *
- * @return a non-empty service instance, real or fake
- */
- private ILiveLockScreenManagerProvider getServiceGuarded() {
- final ILiveLockScreenManagerProvider service = getOrConnectService();
- if (service != null) {
- return service;
+ // Initialize the default LLS component
+ String defComponent = CMSettings.Secure.getString(mContext.getContentResolver(),
+ CMSettings.Secure.DEFAULT_LIVE_LOCK_SCREEN_COMPONENT);
+ if (!TextUtils.isEmpty(defComponent)) {
+ mDefaultLlsInfo = new LiveLockScreenInfo.Builder()
+ .setComponent(ComponentName.unflattenFromString(defComponent))
+ .build();
+ }
}
- return mServiceStubForFailure;
+ super.onBootPhase(phase);
}
/**
@@ -406,7 +316,7 @@ public class LiveLockScreenServiceBroker extends CMSystemService {
mDefaultLlsInfo = llsInfo;
try {
- getServiceGuarded().updateDefaultLiveLockScreen(llsInfo);
+ getBrokeredService().updateDefaultLiveLockScreen(llsInfo);
} catch (RemoteException e) {
/* ignore */
}
diff --git a/cm/lib/main/java/org/cyanogenmod/platform/internal/common/BrokeredServiceConnection.java b/cm/lib/main/java/org/cyanogenmod/platform/internal/common/BrokeredServiceConnection.java
new file mode 100644
index 0000000..6775937
--- /dev/null
+++ b/cm/lib/main/java/org/cyanogenmod/platform/internal/common/BrokeredServiceConnection.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2016 The CyanogenMod 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 org.cyanogenmod.platform.internal.common;
+
+/**
+ * The {@link BrokeredServiceConnection} provides callbacks for when a
+ * {@link org.cyanogenmod.platform.internal.BrokerableCMSystemService} interface
+ * contract is either fulfilled and connected to an implementation or disconnected.
+ */
+public interface BrokeredServiceConnection {
+
+ /**
+ * Callback that signifies that the given interface contract passed into the
+ * {@link org.cyanogenmod.platform.internal.BrokerableCMSystemService} is implemented
+ * and connected.
+ */
+ void onBrokeredServiceConnected();
+
+ /**
+ * Callback that signifies that the given implementation for the interface contract passed
+ * into the {@link org.cyanogenmod.platform.internal.BrokerableCMSystemService} is disconnected.
+ */
+ void onBrokeredServiceDisconnected();
+}
diff --git a/cm/res/AndroidManifest.xml b/cm/res/AndroidManifest.xml
index 6468722..de6414f 100644
--- a/cm/res/AndroidManifest.xml
+++ b/cm/res/AndroidManifest.xml
@@ -220,7 +220,6 @@
android:description="@string/permdesc_observe_audio_sessions"
android:protectionLevel="normal"/>
-
<!-- Allows an application to access the weather service.
<p>Although the protection is normal, this permission should be required ONLY by those apps
meant to do something meaningful with the data provided by the service (LockClock, SysUI)-->
@@ -236,6 +235,11 @@
android:icon="@drawable/ic_launcher_cyanogenmod"
android:protectionLevel="normal" />
+ <!-- Not meant for third parties. Allows brokering core services to other
+ processes @hide -->
+ <permission android:name="cyanogenmod.permission.BIND_CORE_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"