Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -561,6 +561,7 @@ java_defaults { "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl", "telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl", "telephony/java/android/telephony/ICellInfoCallback.aidl", "telephony/java/android/telephony/IFinancialSmsCallback.aidl", "telephony/java/android/telephony/INetworkService.aidl", "telephony/java/android/telephony/INetworkServiceCallback.aidl", "telephony/java/com/android/ims/internal/IImsCallSession.aidl", Loading api/current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -44670,6 +44670,7 @@ package android.telephony { method public static android.telephony.SmsManager getDefault(); method public static int getDefaultSmsSubscriptionId(); method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback); method public int getSubscriptionId(); method public void injectSmsPdu(byte[], String, android.app.PendingIntent); method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent); Loading Loading @@ -44732,6 +44733,11 @@ package android.telephony { field public static final int STATUS_ON_ICC_UNSENT = 7; // 0x7 } public abstract static class SmsManager.FinancialSmsCallback { ctor public SmsManager.FinancialSmsCallback(); method public abstract void onFinancialSmsMessages(android.database.CursorWindow); } public class SmsMessage { method public static int[] calculateLength(CharSequence, boolean); method public static int[] calculateLength(String, boolean); core/java/android/app/role/IRoleManager.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package android.app.role; import android.app.role.IOnRoleHoldersChangedListener; import android.app.role.IRoleManagerCallback; import android.os.Bundle; import android.telephony.IFinancialSmsCallback; /** * @hide Loading Loading @@ -52,4 +54,8 @@ interface IRoleManager { List<String> getHeldRolesFromController(in String packageName); String getDefaultSmsPackage(int userId); /** * Get filtered SMS messages for financial app. */ void getSmsMessagesForFinancialApp(in String callingPkg, in Bundle params, in IFinancialSmsCallback callback); } services/core/java/com/android/server/role/FinancialSmsManager.java 0 → 100644 +218 −0 Original line number Diff line number Diff line /* * 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.role; import android.Manifest; import android.annotation.MainThread; 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.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.UserHandle; import android.service.sms.FinancialSmsService; import android.service.sms.IFinancialSmsService; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.ArrayList; /** * This class binds to {@code FinancialSmsService}. */ final class FinancialSmsManager { private static final String TAG = "FinancialSmsManager"; private final Context mContext; private final Object mLock = new Object(); @GuardedBy("mLock") private ServiceConnection mServiceConnection; @GuardedBy("mLock") private IFinancialSmsService mRemoteService; @GuardedBy("mLock") private ArrayList<Command> mQueuedCommands; FinancialSmsManager(Context context) { mContext = context; } @Nullable ServiceInfo getServiceInfo() { final String packageName = mContext.getPackageManager().getServicesSystemSharedLibraryPackageName(); if (packageName == null) { Slog.w(TAG, "no external services package!"); return null; } final Intent intent = new Intent(FinancialSmsService.ACTION_FINANCIAL_SERVICE_INTENT); intent.setPackage(packageName); final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, PackageManager.GET_SERVICES); if (resolveInfo == null || resolveInfo.serviceInfo == null) { Slog.w(TAG, "No valid components found."); return null; } return resolveInfo.serviceInfo; } @Nullable private ComponentName getServiceComponentName() { final ServiceInfo serviceInfo = getServiceInfo(); if (serviceInfo == null) return null; final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name); if (!Manifest.permission.BIND_FINANCIAL_SMS_SERVICE.equals(serviceInfo.permission)) { Slog.w(TAG, name.flattenToShortString() + " does not require permission " + Manifest.permission.BIND_FINANCIAL_SMS_SERVICE); return null; } return name; } void reset() { synchronized (mLock) { if (mServiceConnection != null) { mContext.unbindService(mServiceConnection); mServiceConnection = null; } else { Slog.d(TAG, "reset(): service is not bound. Do nothing."); } } } /** * Run a command, starting the service connection if necessary. */ private void connectAndRun(@NonNull Command command) { synchronized (mLock) { if (mRemoteService != null) { try { command.run(mRemoteService); } catch (RemoteException e) { Slog.w(TAG, "exception calling service: " + e); } return; } else { if (mQueuedCommands == null) { mQueuedCommands = new ArrayList<>(1); } mQueuedCommands.add(command); // If we're already connected, don't create a new connection, just leave - the // command will be run when the service connects if (mServiceConnection != null) return; } // Create the connection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mLock) { mRemoteService = IFinancialSmsService.Stub.asInterface(service); if (mQueuedCommands != null) { final int size = mQueuedCommands.size(); for (int i = 0; i < size; i++) { final Command queuedCommand = mQueuedCommands.get(i); try { queuedCommand.run(mRemoteService); } catch (RemoteException e) { Slog.w(TAG, "exception calling " + name + ": " + e); } } mQueuedCommands = null; } } } @Override @MainThread public void onServiceDisconnected(ComponentName name) { synchronized (mLock) { mRemoteService = null; } } @Override public void onBindingDied(ComponentName name) { synchronized (mLock) { mRemoteService = null; } } @Override public void onNullBinding(ComponentName name) { synchronized (mLock) { mRemoteService = null; } } }; final ComponentName component = getServiceComponentName(); if (component != null) { final Intent intent = new Intent(); intent.setComponent(component); final long token = Binder.clearCallingIdentity(); try { mContext.bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.getUserHandleForUid(UserHandle.getCallingUserId())); } finally { Binder.restoreCallingIdentity(token); } } } } void getSmsMessages(RemoteCallback callback, @Nullable Bundle params) { connectAndRun((service) -> service.getSmsMessages(callback, params)); } void dump(String prefix, PrintWriter pw) { final ComponentName impl = getServiceComponentName(); pw.print(prefix); pw.print("User ID: "); pw.println(UserHandle.getCallingUserId()); pw.print(prefix); pw.print("Queued commands: "); if (mQueuedCommands == null) { pw.println("N/A"); } else { pw.println(mQueuedCommands.size()); } pw.print(prefix); pw.print("Implementation: "); if (impl == null) { pw.println("N/A"); return; } pw.println(impl.flattenToShortString()); } private interface Command { void run(IFinancialSmsService service) throws RemoteException; } } services/core/java/com/android/server/role/RoleManagerService.java +54 −0 Original line number Diff line number Diff line Loading @@ -33,16 +33,24 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.PermissionChecker; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.database.CursorWindow; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManagerInternal; import android.service.sms.FinancialSmsService; import android.telephony.IFinancialSmsCallback; import android.text.TextUtils; import android.util.ArraySet; import android.util.PackageUtils; Loading Loading @@ -620,5 +628,51 @@ public class RoleManagerService extends SystemService implements RoleUserState.C dumpOutputStream.flush(); } /** * Get filtered SMS messages for financial app. */ @Override public void getSmsMessagesForFinancialApp( String callingPkg, Bundle params, IFinancialSmsCallback callback) { int mode = PermissionChecker.checkCallingOrSelfPermission( getContext(), AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS); if (mode == PermissionChecker.PERMISSION_GRANTED) { FinancialSmsManager financialSmsManager = new FinancialSmsManager(getContext()); financialSmsManager.getSmsMessages(new RemoteCallback((result) -> { CursorWindow messages = null; if (result == null) { Slog.w(LOG_TAG, "result is null."); } else { messages = result.getParcelable(FinancialSmsService.EXTRA_SMS_MSGS); } try { callback.onGetSmsMessagesForFinancialApp(messages); } catch (RemoteException e) { // do nothing } }), params); } else { try { callback.onGetSmsMessagesForFinancialApp(null); } catch (RemoteException e) { // do nothing } } } private int getUidForPackage(String packageName) { long ident = Binder.clearCallingIdentity(); try { return getContext().getPackageManager().getApplicationInfo(packageName, PackageManager.MATCH_ANY_USER).uid; } catch (NameNotFoundException nnfe) { return -1; } finally { Binder.restoreCallingIdentity(ident); } } } } Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -561,6 +561,7 @@ java_defaults { "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl", "telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl", "telephony/java/android/telephony/ICellInfoCallback.aidl", "telephony/java/android/telephony/IFinancialSmsCallback.aidl", "telephony/java/android/telephony/INetworkService.aidl", "telephony/java/android/telephony/INetworkServiceCallback.aidl", "telephony/java/com/android/ims/internal/IImsCallSession.aidl", Loading
api/current.txt +6 −0 Original line number Diff line number Diff line Loading @@ -44670,6 +44670,7 @@ package android.telephony { method public static android.telephony.SmsManager getDefault(); method public static int getDefaultSmsSubscriptionId(); method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback); method public int getSubscriptionId(); method public void injectSmsPdu(byte[], String, android.app.PendingIntent); method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent); Loading Loading @@ -44732,6 +44733,11 @@ package android.telephony { field public static final int STATUS_ON_ICC_UNSENT = 7; // 0x7 } public abstract static class SmsManager.FinancialSmsCallback { ctor public SmsManager.FinancialSmsCallback(); method public abstract void onFinancialSmsMessages(android.database.CursorWindow); } public class SmsMessage { method public static int[] calculateLength(CharSequence, boolean); method public static int[] calculateLength(String, boolean);
core/java/android/app/role/IRoleManager.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package android.app.role; import android.app.role.IOnRoleHoldersChangedListener; import android.app.role.IRoleManagerCallback; import android.os.Bundle; import android.telephony.IFinancialSmsCallback; /** * @hide Loading Loading @@ -52,4 +54,8 @@ interface IRoleManager { List<String> getHeldRolesFromController(in String packageName); String getDefaultSmsPackage(int userId); /** * Get filtered SMS messages for financial app. */ void getSmsMessagesForFinancialApp(in String callingPkg, in Bundle params, in IFinancialSmsCallback callback); }
services/core/java/com/android/server/role/FinancialSmsManager.java 0 → 100644 +218 −0 Original line number Diff line number Diff line /* * 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.role; import android.Manifest; import android.annotation.MainThread; 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.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.UserHandle; import android.service.sms.FinancialSmsService; import android.service.sms.IFinancialSmsService; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.ArrayList; /** * This class binds to {@code FinancialSmsService}. */ final class FinancialSmsManager { private static final String TAG = "FinancialSmsManager"; private final Context mContext; private final Object mLock = new Object(); @GuardedBy("mLock") private ServiceConnection mServiceConnection; @GuardedBy("mLock") private IFinancialSmsService mRemoteService; @GuardedBy("mLock") private ArrayList<Command> mQueuedCommands; FinancialSmsManager(Context context) { mContext = context; } @Nullable ServiceInfo getServiceInfo() { final String packageName = mContext.getPackageManager().getServicesSystemSharedLibraryPackageName(); if (packageName == null) { Slog.w(TAG, "no external services package!"); return null; } final Intent intent = new Intent(FinancialSmsService.ACTION_FINANCIAL_SERVICE_INTENT); intent.setPackage(packageName); final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, PackageManager.GET_SERVICES); if (resolveInfo == null || resolveInfo.serviceInfo == null) { Slog.w(TAG, "No valid components found."); return null; } return resolveInfo.serviceInfo; } @Nullable private ComponentName getServiceComponentName() { final ServiceInfo serviceInfo = getServiceInfo(); if (serviceInfo == null) return null; final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name); if (!Manifest.permission.BIND_FINANCIAL_SMS_SERVICE.equals(serviceInfo.permission)) { Slog.w(TAG, name.flattenToShortString() + " does not require permission " + Manifest.permission.BIND_FINANCIAL_SMS_SERVICE); return null; } return name; } void reset() { synchronized (mLock) { if (mServiceConnection != null) { mContext.unbindService(mServiceConnection); mServiceConnection = null; } else { Slog.d(TAG, "reset(): service is not bound. Do nothing."); } } } /** * Run a command, starting the service connection if necessary. */ private void connectAndRun(@NonNull Command command) { synchronized (mLock) { if (mRemoteService != null) { try { command.run(mRemoteService); } catch (RemoteException e) { Slog.w(TAG, "exception calling service: " + e); } return; } else { if (mQueuedCommands == null) { mQueuedCommands = new ArrayList<>(1); } mQueuedCommands.add(command); // If we're already connected, don't create a new connection, just leave - the // command will be run when the service connects if (mServiceConnection != null) return; } // Create the connection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mLock) { mRemoteService = IFinancialSmsService.Stub.asInterface(service); if (mQueuedCommands != null) { final int size = mQueuedCommands.size(); for (int i = 0; i < size; i++) { final Command queuedCommand = mQueuedCommands.get(i); try { queuedCommand.run(mRemoteService); } catch (RemoteException e) { Slog.w(TAG, "exception calling " + name + ": " + e); } } mQueuedCommands = null; } } } @Override @MainThread public void onServiceDisconnected(ComponentName name) { synchronized (mLock) { mRemoteService = null; } } @Override public void onBindingDied(ComponentName name) { synchronized (mLock) { mRemoteService = null; } } @Override public void onNullBinding(ComponentName name) { synchronized (mLock) { mRemoteService = null; } } }; final ComponentName component = getServiceComponentName(); if (component != null) { final Intent intent = new Intent(); intent.setComponent(component); final long token = Binder.clearCallingIdentity(); try { mContext.bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE, UserHandle.getUserHandleForUid(UserHandle.getCallingUserId())); } finally { Binder.restoreCallingIdentity(token); } } } } void getSmsMessages(RemoteCallback callback, @Nullable Bundle params) { connectAndRun((service) -> service.getSmsMessages(callback, params)); } void dump(String prefix, PrintWriter pw) { final ComponentName impl = getServiceComponentName(); pw.print(prefix); pw.print("User ID: "); pw.println(UserHandle.getCallingUserId()); pw.print(prefix); pw.print("Queued commands: "); if (mQueuedCommands == null) { pw.println("N/A"); } else { pw.println(mQueuedCommands.size()); } pw.print(prefix); pw.print("Implementation: "); if (impl == null) { pw.println("N/A"); return; } pw.println(impl.flattenToShortString()); } private interface Command { void run(IFinancialSmsService service) throws RemoteException; } }
services/core/java/com/android/server/role/RoleManagerService.java +54 −0 Original line number Diff line number Diff line Loading @@ -33,16 +33,24 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.PermissionChecker; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.database.CursorWindow; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManagerInternal; import android.service.sms.FinancialSmsService; import android.telephony.IFinancialSmsCallback; import android.text.TextUtils; import android.util.ArraySet; import android.util.PackageUtils; Loading Loading @@ -620,5 +628,51 @@ public class RoleManagerService extends SystemService implements RoleUserState.C dumpOutputStream.flush(); } /** * Get filtered SMS messages for financial app. */ @Override public void getSmsMessagesForFinancialApp( String callingPkg, Bundle params, IFinancialSmsCallback callback) { int mode = PermissionChecker.checkCallingOrSelfPermission( getContext(), AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS); if (mode == PermissionChecker.PERMISSION_GRANTED) { FinancialSmsManager financialSmsManager = new FinancialSmsManager(getContext()); financialSmsManager.getSmsMessages(new RemoteCallback((result) -> { CursorWindow messages = null; if (result == null) { Slog.w(LOG_TAG, "result is null."); } else { messages = result.getParcelable(FinancialSmsService.EXTRA_SMS_MSGS); } try { callback.onGetSmsMessagesForFinancialApp(messages); } catch (RemoteException e) { // do nothing } }), params); } else { try { callback.onGetSmsMessagesForFinancialApp(null); } catch (RemoteException e) { // do nothing } } } private int getUidForPackage(String packageName) { long ident = Binder.clearCallingIdentity(); try { return getContext().getPackageManager().getApplicationInfo(packageName, PackageManager.MATCH_ANY_USER).uid; } catch (NameNotFoundException nnfe) { return -1; } finally { Binder.restoreCallingIdentity(ident); } } } }