1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.audio; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.ActivityManager; 22 import android.app.ActivityManagerInternal; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.UserInfo; 28 import android.media.AudioManager; 29 import android.os.Binder; 30 import android.os.UserHandle; 31 import android.os.UserManager; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 import com.android.server.LocalServices; 35 36 import java.util.Objects; 37 38 /** 39 * Provides an adapter to access functionality reserved to components running in system_server 40 * Functionality such as sending privileged broadcasts is to be accessed through the default 41 * adapter, whereas tests can inject a no-op adapter. 42 */ 43 public class SystemServerAdapter { 44 45 protected final Context mContext; 46 SystemServerAdapter(@ullable Context context)47 protected SystemServerAdapter(@Nullable Context context) { 48 mContext = context; 49 } 50 /** 51 * Create a wrapper around privileged functionality. 52 * @return the adapter 53 */ getDefaultAdapter(Context context)54 static final @NonNull SystemServerAdapter getDefaultAdapter(Context context) { 55 Objects.requireNonNull(context); 56 return new SystemServerAdapter(context); 57 } 58 59 /** 60 * @return true if this is supposed to be run in system_server, false otherwise (e.g. for a 61 * unit test) 62 */ isPrivileged()63 public boolean isPrivileged() { 64 return true; 65 } 66 67 /** 68 * Broadcast ACTION_MICROPHONE_MUTE_CHANGED 69 */ sendMicrophoneMuteChangedIntent()70 public void sendMicrophoneMuteChangedIntent() { 71 mContext.sendBroadcastAsUser( 72 new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED) 73 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 74 UserHandle.ALL); 75 } 76 77 /** 78 * Broadcast ACTION_AUDIO_BECOMING_NOISY 79 */ sendDeviceBecomingNoisyIntent()80 public void sendDeviceBecomingNoisyIntent() { 81 if (mContext == null) { 82 return; 83 } 84 final Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); 85 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 86 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 87 final long ident = Binder.clearCallingIdentity(); 88 try { 89 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 90 } finally { 91 Binder.restoreCallingIdentity(ident); 92 } 93 } 94 95 /** 96 * Send sticky broadcast to current user's profile group (including current user) 97 */ 98 @VisibleForTesting broadcastStickyIntentToCurrentProfileGroup(Intent intent)99 public void broadcastStickyIntentToCurrentProfileGroup(Intent intent) { 100 int[] profileIds = LocalServices.getService( 101 ActivityManagerInternal.class).getCurrentProfileIds(); 102 for (int userId : profileIds) { 103 ActivityManager.broadcastStickyIntent(intent, userId); 104 } 105 } 106 107 /** 108 * Broadcast sticky intents when a profile is started. This is needed because newly created 109 * profiles would not receive the intents until the next state change. 110 */ registerUserStartedReceiver(Context context)111 /*package*/ void registerUserStartedReceiver(Context context) { 112 IntentFilter filter = new IntentFilter(); 113 filter.addAction(Intent.ACTION_USER_STARTED); 114 context.registerReceiverAsUser(new BroadcastReceiver() { 115 @Override 116 public void onReceive(Context context, Intent intent) { 117 if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) { 118 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 119 UserHandle.USER_NULL); 120 if (userId == UserHandle.USER_NULL) { 121 return; 122 } 123 124 UserManager userManager = context.getSystemService(UserManager.class); 125 final UserInfo profileParent = userManager.getProfileParent(userId); 126 if (profileParent == null) { 127 return; 128 } 129 130 // get sticky intents from parent and broadcast them to the started profile 131 broadcastProfileParentStickyIntent(context, AudioManager.ACTION_HDMI_AUDIO_PLUG, 132 userId, profileParent.id); 133 broadcastProfileParentStickyIntent(context, AudioManager.ACTION_HEADSET_PLUG, 134 userId, profileParent.id); 135 } 136 } 137 }, UserHandle.ALL, filter, null, null); 138 } 139 broadcastProfileParentStickyIntent(Context context, String intentAction, int profileId, int parentId)140 private void broadcastProfileParentStickyIntent(Context context, String intentAction, 141 int profileId, int parentId) { 142 Intent intent = context.registerReceiverAsUser(/*receiver*/ null, UserHandle.of(parentId), 143 new IntentFilter(intentAction), /*broadcastPermission*/ null, /*scheduler*/ null); 144 if (intent != null) { 145 ActivityManager.broadcastStickyIntent(intent, profileId); 146 } 147 } 148 broadcastMasterMuteStatus(boolean muted)149 /*package*/ void broadcastMasterMuteStatus(boolean muted) { 150 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION); 151 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted); 152 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 153 | Intent.FLAG_RECEIVER_REPLACE_PENDING 154 | Intent.FLAG_RECEIVER_FOREGROUND); 155 final long ident = Binder.clearCallingIdentity(); 156 try { 157 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 158 } finally { 159 Binder.restoreCallingIdentity(ident); 160 } 161 } 162 } 163