diff --git a/play-services-api/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl b/play-services-api/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl index 75a949b8..3bc93136 100644 --- a/play-services-api/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl +++ b/play-services-api/src/main/aidl/com/google/android/auth/IAuthManagerService.aidl @@ -9,6 +9,9 @@ import com.google.android.gms.auth.AccountChangeEventsRequest; interface IAuthManagerService { Bundle getToken(String accountName, String scope, in Bundle extras) = 0; Bundle clearToken(String token, in Bundle extras) = 1; - AccountChangeEventsResponse getChangeEvents(in AccountChangeEventsRequest request) = 2; + AccountChangeEventsResponse getChangeEvents(in AccountChangeEventsRequest request) = 2; Bundle getTokenWithAccount(in Account account, String scope, in Bundle extras) = 4; + Bundle getAccounts(in Bundle extras) = 5; + Bundle removeAccount(in Account account) = 6; + Bundle requestGoogleAccountsAccess(String packageName) = 7; } diff --git a/play-services-api/src/main/aidl/com/google/android/gms/dynamite/IDynamiteLoader.aidl b/play-services-api/src/main/aidl/com/google/android/gms/dynamite/IDynamiteLoader.aidl deleted file mode 100644 index 8cb2be99..00000000 --- a/play-services-api/src/main/aidl/com/google/android/gms/dynamite/IDynamiteLoader.aidl +++ /dev/null @@ -1,10 +0,0 @@ -package com.google.android.gms.dynamite; - -import com.google.android.gms.dynamic.IObjectWrapper; - -interface IDynamiteLoader { - int getModuleVersion(IObjectWrapper context, String moduleId) = 0; - int getModuleVersion2(IObjectWrapper context, String moduleId, boolean updateConfigIfRequired) = 2; - - IObjectWrapper createModuleContext(IObjectWrapper context, String moduleId, int minVersion) = 1; -} \ No newline at end of file diff --git a/play-services-api/src/main/aidl/com/mgoogle/android/gms/dynamite/IDynamiteLoader.aidl b/play-services-api/src/main/aidl/com/mgoogle/android/gms/dynamite/IDynamiteLoader.aidl new file mode 100644 index 00000000..2826205e --- /dev/null +++ b/play-services-api/src/main/aidl/com/mgoogle/android/gms/dynamite/IDynamiteLoader.aidl @@ -0,0 +1,14 @@ +package com.mgoogle.android.gms.dynamite; + +import com.google.android.gms.dynamic.IObjectWrapper; + +interface IDynamiteLoader { + int getModuleVersion(IObjectWrapper wrappedContext, String moduleId) = 0; + int getModuleVersion2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) = 2; + int getModuleVersion2NoCrashUtils(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) = 4; + + IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) = 1; + IObjectWrapper createModuleContextNoCrashUtils(IObjectWrapper wrappedContext, String moduleId, int minVersion) = 3; + + int getIDynamiteLoaderVersion() = 5; +} diff --git a/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteLoaderImpl.java b/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteLoaderImpl.java deleted file mode 100644 index e9f0e18b..00000000 --- a/play-services-core/src/main/java/com/google/android/gms/chimera/container/DynamiteLoaderImpl.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2013-2017 microG Project Team - * - * 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.google.android.gms.chimera.container; - -import android.content.Context; -import android.content.ContextWrapper; -import android.content.pm.PackageManager; -import android.os.RemoteException; -import android.util.Log; - -import com.google.android.gms.dynamic.IObjectWrapper; -import com.google.android.gms.dynamic.ObjectWrapper; -import com.google.android.gms.dynamite.IDynamiteLoader; - -import org.microg.gms.common.Constants; - -import java.lang.reflect.Field; - -public class DynamiteLoaderImpl extends IDynamiteLoader.Stub { - private static final String TAG = "GmsDynamiteLoaderImpl"; - - @Override - public IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException { - Log.d(TAG, "createModuleContext for " + moduleId + " at version " + minVersion); - final Context context = (Context) ObjectWrapper.unwrap(wrappedContext); - try { - return ObjectWrapper.wrap(new ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY)) { - @Override - public Context getApplicationContext() { - return context; - } - }); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "returning null instead", e); - return null; - } - } - - @Override - public int getModuleVersion(IObjectWrapper context, String moduleId) throws RemoteException { - return getModuleVersion2(context, moduleId, true); - } - - @Override - public int getModuleVersion2(IObjectWrapper context, String moduleId, boolean updateConfigIfRequired) throws RemoteException { - try { - return Class.forName("com.google.android.gms.dynamite.descriptors." + moduleId + ".ModuleDescriptor").getDeclaredField("MODULE_VERSION").getInt(null); - } catch (Exception e) { - Log.w(TAG, "No such module known: " + moduleId); - } - - if (moduleId.equals("com.google.android.gms.googlecertificates")) { - return com.google.android.gms.dynamite.descriptors.com.google.android.gms.googlecertificates.ModuleDescriptor.MODULE_VERSION; - } - if (moduleId.equals("com.google.android.gms.cast.framework.dynamite")) { - Log.d(TAG, "returning temp fix module version for " + moduleId + ". Cast API wil not be functional!"); - return 1; - } - - if (moduleId.equals("com.google.android.gms.maps_dynamite")) { - Log.d(TAG, "returning v1 for maps"); - return 1; - } - - Log.d(TAG, "unimplemented Method: getModuleVersion for " + moduleId); - return 0; - } -} diff --git a/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteContext.java b/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteContext.java new file mode 100644 index 00000000..78d484be --- /dev/null +++ b/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteContext.java @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.mgoogle.android.gms.chimera.container; + +import android.content.Context; +import android.content.ContextWrapper; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Process; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +import org.microg.gms.common.Constants; + +import java.io.File; + +import dalvik.system.PathClassLoader; + +public class DynamiteContext extends ContextWrapper { + private static final String TAG = "DynamiteContext"; + private DynamiteModuleInfo moduleInfo; + private Context originalContext; + private Context gmsContext; + private DynamiteContext appContext; + + public DynamiteContext(DynamiteModuleInfo moduleInfo, Context base, Context gmsContext, DynamiteContext appContext) { + super(base); + this.moduleInfo = moduleInfo; + this.originalContext = base; + this.gmsContext = gmsContext; + this.appContext = appContext; + } + + @Override + public ClassLoader getClassLoader() { + StringBuilder nativeLoaderDirs = new StringBuilder(gmsContext.getApplicationInfo().nativeLibraryDir); + if (Build.VERSION.SDK_INT >= 23 && Process.is64Bit()) { + for (String abi : Build.SUPPORTED_64_BIT_ABIS) { + nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi); + } + } else if (Build.VERSION.SDK_INT >= 21) { + for (String abi : Build.SUPPORTED_32_BIT_ABIS) { + nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(abi); + } + } else { + nativeLoaderDirs.append(File.pathSeparator).append(gmsContext.getApplicationInfo().sourceDir).append("!/lib/").append(Build.CPU_ABI); + } + return new PathClassLoader(gmsContext.getApplicationInfo().sourceDir, nativeLoaderDirs.toString(), new FilteredClassLoader(originalContext.getClassLoader(), moduleInfo.getMergedClasses(), moduleInfo.getMergedPackages())); + } + + @Override + public String getPackageName() { + return gmsContext.getPackageName(); + } + + @Override + public ApplicationInfo getApplicationInfo() { + return gmsContext.getApplicationInfo(); + } + + @Override + public Context getApplicationContext() { + return appContext; + } + + @RequiresApi(24) + @Override + public Context createDeviceProtectedStorageContext() { + return new DynamiteContext(moduleInfo, originalContext.createDeviceProtectedStorageContext(), gmsContext.createDeviceProtectedStorageContext(), appContext); + } + + public static DynamiteContext create(String moduleId, Context originalContext) { + try { + DynamiteModuleInfo moduleInfo = new DynamiteModuleInfo(moduleId); + Context gmsContext = originalContext.createPackageContext(Constants.GMS_PACKAGE_NAME, 0); + Context originalAppContext = originalContext.getApplicationContext(); + if (originalAppContext == null || originalAppContext == originalContext) { + return new DynamiteContext(moduleInfo, originalContext, gmsContext, null); + } else { + return new DynamiteContext(moduleInfo, originalContext, gmsContext, new DynamiteContext(moduleInfo, originalAppContext, gmsContext, null)); + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, e); + return null; + } + } +} diff --git a/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteLoaderImpl.java b/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteLoaderImpl.java index 390ddd06..71ded1cb 100644 --- a/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteLoaderImpl.java +++ b/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteLoaderImpl.java @@ -24,37 +24,58 @@ import android.util.Log; import com.google.android.gms.dynamic.IObjectWrapper; import com.google.android.gms.dynamic.ObjectWrapper; -import com.google.android.gms.dynamite.IDynamiteLoader; +import com.mgoogle.android.gms.dynamite.IDynamiteLoader; import org.microg.gms.common.Constants; +import java.lang.reflect.Field; + public class DynamiteLoaderImpl extends IDynamiteLoader.Stub { private static final String TAG = "GmsDynamiteLoaderImpl"; @Override public IObjectWrapper createModuleContext(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException { - Log.d(TAG, "unimplemented Method: createModuleContext for " + moduleId + " at version " + minVersion + ", returning gms context"); + // We don't have crash utils, so just forward + return createModuleContextNoCrashUtils(wrappedContext, moduleId, minVersion); + } + + @Override + public IObjectWrapper createModuleContextNoCrashUtils(IObjectWrapper wrappedContext, String moduleId, int minVersion) throws RemoteException { + Log.d(TAG, "createModuleContext for " + moduleId + " at version " + minVersion); + final Context originalContext = (Context) ObjectWrapper.unwrap(wrappedContext); + return ObjectWrapper.wrap(DynamiteContext.create(moduleId, originalContext)); + } + + @Override + public int getIDynamiteLoaderVersion() throws RemoteException { + return 2; + } + + @Override + public int getModuleVersion(IObjectWrapper wrappedContext, String moduleId) throws RemoteException { + return getModuleVersion2(wrappedContext, moduleId, true); + } + + @Override + public int getModuleVersion2(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) throws RemoteException { + // We don't have crash utils, so just forward + return getModuleVersion2NoCrashUtils(wrappedContext, moduleId, updateConfigIfRequired); + } + + @Override + public int getModuleVersion2NoCrashUtils(IObjectWrapper wrappedContext, String moduleId, boolean updateConfigIfRequired) throws RemoteException { final Context context = (Context) ObjectWrapper.unwrap(wrappedContext); - try { - return ObjectWrapper.wrap(new ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY)) { - @Override - public Context getApplicationContext() { - return context; - } - }); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "returning null instead", e); - return null; + if (context == null) { + Log.w(TAG, "Invalid client context"); + return 0; } - } - @Override - public int getModuleVersion(IObjectWrapper context, String moduleId) throws RemoteException { - return getModuleVersion2(context, moduleId, true); - } + try { + return Class.forName("com.google.android.gms.dynamite.descriptors." + moduleId + ".ModuleDescriptor").getDeclaredField("MODULE_VERSION").getInt(null); + } catch (Exception e) { + Log.w(TAG, "No such module known: " + moduleId); + } - @Override - public int getModuleVersion2(IObjectWrapper context, String moduleId, boolean updateConfigIfRequired) throws RemoteException { if (moduleId.equals("com.google.android.gms.googlecertificates")) { return com.google.android.gms.dynamite.descriptors.com.google.android.gms.googlecertificates.ModuleDescriptor.MODULE_VERSION; } diff --git a/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteModuleInfo.java b/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteModuleInfo.java new file mode 100644 index 00000000..5d952172 --- /dev/null +++ b/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/DynamiteModuleInfo.java @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.mgoogle.android.gms.chimera.container; + +import java.util.Collection; +import java.util.Collections; + +import static android.content.Context.CONTEXT_IGNORE_SECURITY; +import static android.content.Context.CONTEXT_INCLUDE_CODE; + +public class DynamiteModuleInfo { + private Class descriptor; + private String moduleId; + + public DynamiteModuleInfo(String moduleId) { + this.moduleId = moduleId; + try { + this.descriptor = Class.forName("com.google.android.gms.dynamite.descriptors." + moduleId + ".ModuleDescriptor"); + } catch (Exception e) { + // Ignore + } + } + + public String getModuleId() { + return moduleId; + } + + public int getVersion() { + try { + return descriptor.getDeclaredField("MODULE_VERSION").getInt(null); + } catch (Exception e) { + return 0; + } + } + + public Collection getMergedPackages() { + try { + return (Collection) descriptor.getDeclaredField("MERGED_PACKAGES").get(null); + } catch (Exception e) { + return Collections.emptySet(); + } + } + + public Collection getMergedClasses() { + try { + return (Collection) descriptor.getDeclaredField("MERGED_CLASSES").get(null); + } catch (Exception e) { + return Collections.emptySet(); + } + } +} diff --git a/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/FilteredClassLoader.java b/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/FilteredClassLoader.java new file mode 100644 index 00000000..1d3e97bc --- /dev/null +++ b/play-services-core/src/main/java/com/mgoogle/android/gms/chimera/container/FilteredClassLoader.java @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.mgoogle.android.gms.chimera.container; + +import android.util.Log; + +import java.util.Collection; +import java.util.HashSet; + +public class FilteredClassLoader extends ClassLoader { + private static ClassLoader rootClassLoader; + private final Collection allowedClasses; + private final Collection allowedPackages; + + static { + rootClassLoader = ClassLoader.getSystemClassLoader(); + if (rootClassLoader == null) { + rootClassLoader = FilteredClassLoader.class.getClassLoader(); + while (rootClassLoader.getParent() != null) { + rootClassLoader = rootClassLoader.getParent(); + } + } + } + + public FilteredClassLoader(ClassLoader parent, Collection allowedClasses, Collection allowedPackages) { + super(parent); + this.allowedClasses = new HashSet<>(allowedClasses); + this.allowedPackages = new HashSet<>(allowedPackages); + } + + private String getPackageName(String name) { + int lastIndex = name.lastIndexOf("."); + if (lastIndex <= 0) return ""; + return name.substring(0, lastIndex); + } + + private String getClassName(String name) { + int lastIndex = name.indexOf("$"); + if (lastIndex <= 0) return name; + return name.substring(0, lastIndex); + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.startsWith("java.")) return rootClassLoader.loadClass(name); + if (allowedClasses.contains(name) || allowedClasses.contains(getClassName(name))) + return super.loadClass(name, resolve); + if (allowedClasses.contains("!" + name) || allowedClasses.contains("!" + getClassName(name))) + return rootClassLoader.loadClass(name); + if (allowedPackages.contains(getPackageName(name))) return super.loadClass(name, resolve); + return rootClassLoader.loadClass(name); + } +} diff --git a/play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java b/play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java index c3182e18..80ac29cf 100644 --- a/play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java +++ b/play-services-core/src/main/java/org/microg/gms/auth/AuthManagerServiceImpl.java @@ -18,6 +18,8 @@ package org.microg.gms.auth; import android.accounts.Account; import android.accounts.AccountManager; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; @@ -44,7 +46,9 @@ import org.microg.gms.common.PackageUtils; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; +import static android.accounts.AccountManager.KEY_ACCOUNTS; import static android.accounts.AccountManager.KEY_ACCOUNT_NAME; import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE; import static android.accounts.AccountManager.KEY_AUTHTOKEN; @@ -53,6 +57,7 @@ import static android.accounts.AccountManager.KEY_CALLER_PID; public class AuthManagerServiceImpl extends IAuthManagerService.Stub { private static final String TAG = "GmsAuthManagerSvc"; + public static final String KEY_ACCOUNT_FEATURES = "account_features"; public static final String KEY_AUTHORITY = "authority"; public static final String KEY_CALLBACK_INTENT = "callback_intent"; public static final String KEY_CALLER_UID = "callerUid"; @@ -74,14 +79,42 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub { } @Override - public Bundle getToken(String accountName, String scope, Bundle extras) throws RemoteException { + public Bundle getToken(String accountName, String scope, Bundle extras) { + return getTokenWithAccount(new Account(accountName, AuthConstants.DEFAULT_ACCOUNT_TYPE), scope, extras); + } + + private List getScopes(String scope) { + if (!scope.startsWith("oauth2:")) return null; + String[] strings = scope.substring(7).split(" "); + List res = new ArrayList(); + for (String string : strings) { + res.add(new Scope(string)); + } + return res; + } + + private static CharSequence getPackageLabel(String packageName, PackageManager pm) { + try { + return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)); + } catch (PackageManager.NameNotFoundException e) { + return packageName; + } + } + + @Override + public AccountChangeEventsResponse getChangeEvents(AccountChangeEventsRequest request) { + return new AccountChangeEventsResponse(); + } + + @Override + public Bundle getTokenWithAccount(Account account, String scope, Bundle extras) { String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME); if (packageName == null || packageName.isEmpty()) packageName = extras.getString(KEY_CLIENT_PACKAGE_NAME); packageName = PackageUtils.getAndCheckCallingPackage(context, packageName, extras.getInt(KEY_CALLER_UID, 0), extras.getInt(KEY_CALLER_PID, 0)); boolean notify = extras.getBoolean(KEY_HANDLE_NOTIFICATION, false); - Log.d(TAG, "getToken: account:" + accountName + " scope:" + scope + " extras:" + extras + ", notify: " + notify); + Log.d(TAG, "getToken: account:" + account.name + " scope:" + scope + " extras:" + extras + ", notify: " + notify); /* * TODO: This scope seems to be invalid (according to https://developers.google.com/oauthplayground/), @@ -89,9 +122,9 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub { */ scope = scope.replace("https://www.googleapis.com/auth/identity.plus.page.impersonation ", ""); - AuthManager authManager = new AuthManager(context, accountName, packageName, scope); + AuthManager authManager = new AuthManager(context, account.name, packageName, scope); Bundle result = new Bundle(); - result.putString(KEY_ACCOUNT_NAME, accountName); + result.putString(KEY_ACCOUNT_NAME, account.name); result.putString(KEY_ACCOUNT_TYPE, authManager.getAccountType()); if (!authManager.accountExists()) { result.putString(KEY_ERROR, "NetworkError"); @@ -114,36 +147,40 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub { return result; } - private List getScopes(String scope) { - if (!scope.startsWith("oauth2:")) return null; - String[] strings = scope.substring(7).split(" "); - List res = new ArrayList<>(); - for (String string : strings) { - res.add(new Scope(string)); + @Override + public Bundle getAccounts(Bundle extras) { + PackageUtils.assertExtendedAccess(context); + String[] accountFeatures = extras.getStringArray(KEY_ACCOUNT_FEATURES); + String accountType = extras.getString(KEY_ACCOUNT_TYPE); + Account[] accounts; + if (accountFeatures != null) { + try { + accounts = AccountManager.get(context).getAccountsByTypeAndFeatures(accountType, accountFeatures, null, null).getResult(5, TimeUnit.SECONDS); + } catch (Exception e) { + Log.w(TAG, e); + return null; + } + } else { + accounts = AccountManager.get(context).getAccountsByType(accountType); } + Bundle res = new Bundle(); + res.putParcelableArray(KEY_ACCOUNTS, accounts); return res; } - private static CharSequence getPackageLabel(String packageName, PackageManager pm) { - try { - return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)); - } catch (PackageManager.NameNotFoundException e) { - return packageName; - } + public Bundle removeAccount(Account account) { + Log.w(TAG, "Not implemented: removeAccount(" + account + ")"); + return null; } @Override - public AccountChangeEventsResponse getChangeEvents(AccountChangeEventsRequest request) { - return new AccountChangeEventsResponse(); + public Bundle requestGoogleAccountsAccess(String packageName) throws RemoteException { + Log.w(TAG, "Not implemented: requestGoogleAccountsAccess(" + packageName + ")"); + return null; } @Override - public Bundle getTokenWithAccount(Account account, String scope, Bundle extras) throws RemoteException { - return getToken(account.name, scope, extras); - } - - @Override - public Bundle clearToken(String token, Bundle extras) throws RemoteException { + public Bundle clearToken(String token, Bundle extras) { String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME); if (packageName == null) packageName = extras.getString(KEY_CLIENT_PACKAGE_NAME); packageName = PackageUtils.getAndCheckCallingPackage(context, packageName, extras.getInt(KEY_CALLER_UID, 0), extras.getInt(KEY_CALLER_PID, 0));