• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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