diff options
20 files changed, 1110 insertions, 123 deletions
diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java index 77160557f5c2..91b796aba655 100644 --- a/core/java/android/os/HidlSupport.java +++ b/core/java/android/os/HidlSupport.java @@ -218,13 +218,6 @@ public class HidlSupport { @SystemApi public static native int getPidIfSharable(); - /** - * Return true if HIDL is supported on this device and false if not. - * - * @hide - */ - public static native boolean isHidlSupported(); - /** @hide */ public HidlSupport() {} } diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java index bc19655d1618..feed20800fd4 100644 --- a/core/java/android/os/HwBinder.java +++ b/core/java/android/os/HwBinder.java @@ -18,7 +18,6 @@ package android.os; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; -import android.util.Log; import libcore.util.NativeAllocationRegistry; @@ -79,17 +78,6 @@ public abstract class HwBinder implements IHwBinder { String iface, String serviceName) throws RemoteException, NoSuchElementException { - if (!HidlSupport.isHidlSupported() - && (iface.equals("android.hidl.manager@1.0::IServiceManager") - || iface.equals("android.hidl.manager@1.1::IServiceManager") - || iface.equals("android.hidl.manager@1.2::IServiceManager"))) { - Log.i( - TAG, - "Replacing Java hwservicemanager with a fake HwNoService" - + " because HIDL is not supported on this device."); - return new HwNoService(); - } - return getService(iface, serviceName, false /* retry */); } /** diff --git a/core/java/android/os/HwNoService.java b/core/java/android/os/HwNoService.java deleted file mode 100644 index 117c3ad7ee48..000000000000 --- a/core/java/android/os/HwNoService.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2023 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 android.os; - -/** - * A fake hwservicemanager that is used locally when HIDL isn't supported on the device. - * - * @hide - */ -final class HwNoService implements IHwBinder, IHwInterface { - /** @hide */ - @Override - public void transact(int code, HwParcel request, HwParcel reply, int flags) {} - - /** @hide */ - @Override - public IHwInterface queryLocalInterface(String descriptor) { - return new HwNoService(); - } - - /** @hide */ - @Override - public boolean linkToDeath(DeathRecipient recipient, long cookie) { - return true; - } - - /** @hide */ - @Override - public boolean unlinkToDeath(DeathRecipient recipient) { - return true; - } - - /** @hide */ - @Override - public IHwBinder asBinder() { - return this; - } -} diff --git a/core/java/android/service/persistentdata/OWNERS b/core/java/android/service/persistentdata/OWNERS new file mode 100644 index 000000000000..6dfb888dedad --- /dev/null +++ b/core/java/android/service/persistentdata/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/pdb/OWNERS diff --git a/core/jni/android_os_HidlSupport.cpp b/core/jni/android_os_HidlSupport.cpp index 3e51e9315d89..e3602d8f5c72 100644 --- a/core/jni/android_os_HidlSupport.cpp +++ b/core/jni/android_os_HidlSupport.cpp @@ -15,7 +15,6 @@ */ #include <hidl/HidlTransportSupport.h> -#include <hidl/ServiceManagement.h> #include <nativehelper/JNIHelp.h> #include "core_jni_helpers.h" @@ -25,13 +24,8 @@ static jint android_os_HidlSupport_getPidIfSharable(JNIEnv*, jclass) { return android::hardware::details::getPidIfSharable(); } -static jboolean android_os_HidlSupport_isHidlSupported(JNIEnv*, jclass) { - return android::hardware::isHidlSupported(); -} - static const JNINativeMethod gHidlSupportMethods[] = { - {"getPidIfSharable", "()I", (void*)android_os_HidlSupport_getPidIfSharable}, - {"isHidlSupported", "()Z", (void*)android_os_HidlSupport_isHidlSupported}, + {"getPidIfSharable", "()I", (void*)android_os_HidlSupport_getPidIfSharable}, }; const char* const kHidlSupportPathName = "android/os/HidlSupport"; diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp index 2b5b8f7a108e..337736289605 100644 --- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp +++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp @@ -63,6 +63,7 @@ class NativeCommandBuffer { std::optional<std::pair<char*, char*>> readLine(FailFn fail_fn) { char* result = mBuffer + mNext; while (true) { + // We have scanned up to, but not including mNext for this line's newline. if (mNext == mEnd) { if (mEnd == MAX_COMMAND_BYTES) { return {}; @@ -89,7 +90,7 @@ class NativeCommandBuffer { } else { mNext = nl - mBuffer + 1; if (--mLinesLeft < 0) { - fail_fn("ZygoteCommandBuffer.readLine attempted to read past mEnd of command"); + fail_fn("ZygoteCommandBuffer.readLine attempted to read past end of command"); } return std::make_pair(result, nl); } @@ -125,8 +126,8 @@ class NativeCommandBuffer { mEnd += lineLen + 1; } - // Clear mBuffer, start reading new command, return the number of arguments, leaving mBuffer - // positioned at the beginning of first argument. Return 0 on EOF. + // Start reading new command, return the number of arguments, leaving mBuffer positioned at the + // beginning of first argument. Return 0 on EOF. template<class FailFn> int getCount(FailFn fail_fn) { mLinesLeft = 1; @@ -451,11 +452,14 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( (CREATE_ERROR("Write unexpectedly returned short: %d < 5", res)); } } - // Clear buffer and get count from next command. - n_buffer->clear(); for (;;) { + // Clear buffer and get count from next command. + n_buffer->clear(); // Poll isn't strictly necessary for now. But without it, disconnect is hard to detect. int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */)); + if (poll_res < 0) { + fail_fn_z(CREATE_ERROR("Poll failed: %d: %s", errno, strerror(errno))); + } if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) { if (n_buffer->getCount(fail_fn_z) != 0) { break; diff --git a/media/OWNERS b/media/OWNERS index 4a6648e91af4..994a7b810009 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -21,7 +21,6 @@ wonsik@google.com include platform/frameworks/av:/media/janitors/media_solutions_OWNERS # SEO -sungsoo@google.com # SEA/KIR/BVE jtinker@google.com diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS index bbe5e06bb282..058c5be6af6c 100644 --- a/media/java/android/media/OWNERS +++ b/media/java/android/media/OWNERS @@ -2,7 +2,6 @@ fgoldfain@google.com elaurent@google.com lajos@google.com -sungsoo@google.com jmtrivi@google.com # go/android-fwk-media-solutions for info on areas of ownership. diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index bedfd1cfb60b..b555a52fe720 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -37,7 +37,6 @@ import static android.os.Process.INVALID_UID; import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE; import static android.provider.Settings.Secure.VOLUME_HUSH_OFF; import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE; - import static com.android.server.audio.SoundDoseHelper.ACTION_CHECK_MUSIC_ACTIVE; import static com.android.server.utils.EventLogger.Event.ALOGE; import static com.android.server.utils.EventLogger.Event.ALOGI; @@ -73,7 +72,6 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.content.res.Resources; @@ -263,6 +261,8 @@ public class AudioService extends IAudioService.Stub private final SettingsAdapter mSettings; private final AudioPolicyFacade mAudioPolicy; + private final MusicFxHelper mMusicFxHelper; + /** Debug audio mode */ protected static final boolean DEBUG_MODE = false; @@ -403,9 +403,15 @@ public class AudioService extends IAudioService.Stub private static final int MSG_CONFIGURATION_CHANGED = 54; private static final int MSG_BROADCAST_MASTER_MUTE = 55; - /** Messages handled by the {@link SoundDoseHelper}. */ + /** + * Messages handled by the {@link SoundDoseHelper}, do not exceed + * {@link MUSICFX_HELPER_MSG_START}. + */ /*package*/ static final int SAFE_MEDIA_VOLUME_MSG_START = 1000; + /** Messages handled by the {@link MusicFxHelper}. */ + /*package*/ static final int MUSICFX_HELPER_MSG_START = 1100; + // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) @@ -1268,6 +1274,8 @@ public class AudioService extends IAudioService.Stub 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */); queueMsgUnderWakeLock(mAudioHandler, MSG_INIT_SPATIALIZER, 0 /* arg1 */, 0 /* arg2 */, null /* obj */, 0 /* delay */); + + mMusicFxHelper = new MusicFxHelper(mContext, mAudioHandler); } private void initVolumeStreamStates() { @@ -4946,7 +4954,7 @@ public class AudioService extends IAudioService.Stub private void setMasterMuteInternalNoCallerCheck( boolean mute, int flags, int userId, String eventSource) { if (DEBUG_VOL) { - Log.d(TAG, TextUtils.formatSimple("Master mute %s, %d, user=%d from %s", + Log.d(TAG, TextUtils.formatSimple("Master mute %s, flags 0x%x, userId=%d from %s", mute, flags, userId, eventSource)); } @@ -9409,11 +9417,21 @@ public class AudioService extends IAudioService.Stub onConfigurationChanged(); break; + case MusicFxHelper.MSG_EFFECT_CLIENT_GONE: + mMusicFxHelper.handleMessage(msg); + break; + + case SoundDoseHelper.MSG_CONFIGURE_SAFE_MEDIA: + case SoundDoseHelper.MSG_CONFIGURE_SAFE_MEDIA_FORCED: + case SoundDoseHelper.MSG_PERSIST_SAFE_VOLUME_STATE: + case SoundDoseHelper.MSG_PERSIST_MUSIC_ACTIVE_MS: + case SoundDoseHelper.MSG_PERSIST_CSD_VALUES: + case SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION: + mSoundDoseHelper.handleMessage(msg); + break; + default: - if (msg.what >= SAFE_MEDIA_VOLUME_MSG_START) { - // msg could be for the SoundDoseHelper - mSoundDoseHelper.handleMessage(msg); - } + Log.e(TAG, "Unsupported msgId " + msg.what); } } } @@ -9648,7 +9666,7 @@ public class AudioService extends IAudioService.Stub } } else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) || action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) { - handleAudioEffectBroadcast(context, intent); + mMusicFxHelper.handleAudioEffectBroadcast(context, intent); } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) { final int[] suspendedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); final String[] suspendedPackages = @@ -9703,27 +9721,6 @@ public class AudioService extends IAudioService.Stub } } // end class AudioServiceUserRestrictionsListener - private void handleAudioEffectBroadcast(Context context, Intent intent) { - String target = intent.getPackage(); - if (target != null) { - Log.w(TAG, "effect broadcast already targeted to " + target); - return; - } - intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); - // TODO this should target a user-selected panel - List<ResolveInfo> ril = context.getPackageManager().queryBroadcastReceivers( - intent, 0 /* flags */); - if (ril != null && ril.size() != 0) { - ResolveInfo ri = ril.get(0); - if (ri != null && ri.activityInfo != null && ri.activityInfo.packageName != null) { - intent.setPackage(ri.activityInfo.packageName); - context.sendBroadcastAsUser(intent, UserHandle.ALL); - return; - } - } - Log.w(TAG, "couldn't find receiver package for effect intent"); - } - private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) { PackageManager pm = mContext.getPackageManager(); // Find the home activity of the user. It should not be killed to avoid expensive restart, @@ -13178,6 +13175,11 @@ public class AudioService extends IAudioService.Stub return mDeviceBroker.getDeviceSensorUuid(device); } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + MusicFxHelper getMusicFxHelper() { + return mMusicFxHelper; + } + //====================== // misc //====================== diff --git a/services/core/java/com/android/server/audio/MusicFxHelper.java b/services/core/java/com/android/server/audio/MusicFxHelper.java new file mode 100644 index 000000000000..85b3b49ecf78 --- /dev/null +++ b/services/core/java/com/android/server/audio/MusicFxHelper.java @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2023 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.audio; + +import static android.content.pm.PackageManager.MATCH_ANY_USER; + +import static com.android.server.audio.AudioService.MUSICFX_HELPER_MSG_START; + +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.app.ActivityManager; +import android.app.IUidObserver; +import android.app.UidObserver; +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.UserInfo; +import android.media.AudioManager; +import android.media.audiofx.AudioEffect; +import android.os.Binder; +import android.os.IBinder; +import android.os.Message; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.audio.AudioService.AudioHandler; + +import java.util.ArrayList; +import java.util.List; + +/** + * MusicFx management. + */ +public class MusicFxHelper { + private static final String TAG = "AS.MusicFxHelper"; + + @NonNull private final Context mContext; + + @NonNull private final AudioHandler mAudioHandler; + + // Synchronization UidSessionMap access between UidObserver and AudioServiceBroadcastReceiver. + private final Object mClientUidMapLock = new Object(); + + private final String mPackageName = this.getClass().getPackage().getName(); + + private final String mMusicFxPackageName = "com.android.musicfx"; + + /*package*/ static final int MSG_EFFECT_CLIENT_GONE = MUSICFX_HELPER_MSG_START + 1; + + // The binder token identifying the UidObserver registration. + private IBinder mUidObserverToken = null; + + // Package name and list of open audio sessions for this package + private static class PackageSessions { + String mPackageName; + List<Integer> mSessions; + } + + /* + * Override of SparseArray class to add bind/unbind and UID observer in the put/remove methods. + * + * put: + * - the first key/value set put into MySparseArray will trigger a procState bump (bindService) + * - if no valid observer token exist, will call registerUidObserver for put + * - for each new uid put into array, it will be added to uid observer list + * + * remove: + * - for each uid removed from array, it will be removed from uid observer list as well + * - if it's the last uid in array, no more MusicFx procState bump (unbindService), uid + * observer will also be removed, and observer token reset to null + */ + private class MySparseArray extends SparseArray<PackageSessions> { + private final String mMusicFxPackageName = "com.android.musicfx"; + + @RequiresPermission(anyOf = { + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + android.Manifest.permission.INTERACT_ACROSS_USERS, + android.Manifest.permission.INTERACT_ACROSS_PROFILES + }) + @Override + public void put(int uid, PackageSessions pkgSessions) { + if (size() == 0) { + int procState = ActivityManager.PROCESS_STATE_NONEXISTENT; + try { + procState = ActivityManager.getService().getPackageProcessState( + mMusicFxPackageName, mPackageName); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException with getPackageProcessState: " + e); + } + if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + Intent bindIntent = new Intent().setClassName(mMusicFxPackageName, + "com.android.musicfx.KeepAliveService"); + mContext.bindServiceAsUser( + bindIntent, mMusicFxBindConnection, Context.BIND_AUTO_CREATE, + UserHandle.of(getCurrentUserId())); + Log.i(TAG, "bindService to " + mMusicFxPackageName); + } + + Log.i(TAG, mMusicFxPackageName + " procState " + procState); + } + try { + if (mUidObserverToken == null) { + mUidObserverToken = ActivityManager.getService().registerUidObserverForUids( + mEffectUidObserver, ActivityManager.UID_OBSERVER_GONE, + ActivityManager.PROCESS_STATE_UNKNOWN, mPackageName, + new int[]{uid}); + Log.i(TAG, "registered to observer with UID " + uid); + } else if (get(uid) == null) { // addUidToObserver if this is a new UID + ActivityManager.getService().addUidToObserver(mUidObserverToken, mPackageName, + uid); + Log.i(TAG, " UID " + uid + " add to observer"); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException with UID observer add/register: " + e); + } + + super.put(uid, pkgSessions); + } + + @Override + public void remove(int uid) { + if (get(uid) != null) { + try { + ActivityManager.getService().removeUidFromObserver(mUidObserverToken, + mPackageName, uid); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException with removeUidFromObserver: " + e); + } + } + + super.remove(uid); + + // stop foreground service delegate and unregister UID observers with the last UID + if (size() == 0) { + try { + ActivityManager.getService().unregisterUidObserver(mEffectUidObserver); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException with unregisterUidObserver: " + e); + } + mUidObserverToken = null; + mContext.unbindService(mMusicFxBindConnection); + Log.i(TAG, "last session closed, unregister UID observer, and unbind " + + mMusicFxPackageName); + } + } + } + + // Hashmap of UID and list of open sessions for this UID. + @GuardedBy("mClientUidMapLock") + private MySparseArray mClientUidSessionMap = new MySparseArray(); + + // UID observer for effect MusicFx clients + private final IUidObserver mEffectUidObserver = new UidObserver() { + @Override public void onUidGone(int uid, boolean disabled) { + Log.w(TAG, " send MSG_EFFECT_CLIENT_GONE"); + mAudioHandler.sendMessageAtTime( + mAudioHandler.obtainMessage(MSG_EFFECT_CLIENT_GONE, + uid /* arg1 */, 0 /* arg2 */, + null /* obj */), 0 /* delay */); + } + }; + + // BindService connection implementation, we don't need any implementation now + private ServiceConnection mMusicFxBindConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + Log.d(TAG, " service connected to " + name); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + Log.d(TAG, " service disconnected from " + name); + } + }; + + MusicFxHelper(@NonNull Context context, @NonNull AudioHandler audioHandler) { + mContext = context; + mAudioHandler = audioHandler; + } + + /** + * Handle the broadcast {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and + * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. + * + * Only intents without target application package {@link android.content.Intent#getPackage} + * will be handled by the MusicFxHelper, all intents handled and forwarded by MusicFxHelper + * will have the target application package. + * + * If the intent is {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION}: + * - If the MusicFx process is not running, call bindServiceAsUser with AUTO_CREATE to create. + * - If this is the first audio session of MusicFx, call set foreground service delegate. + * - If this is the first audio session for a given UID, add the UID into observer. + * + * If the intent is {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} + * - The KeepAliveService of MusicFx will be unbound, and MusicFx will not be foreground + * delegated anymore if the last session of the last package was closed. + * - The Uid Observer will be removed when the last session of a package was closed. + */ + @RequiresPermission(allOf = {android.Manifest.permission.INTERACT_ACROSS_USERS}) + public void handleAudioEffectBroadcast(Context context, Intent intent) { + String target = intent.getPackage(); + if (target != null) { + Log.w(TAG, "effect broadcast already targeted to " + target); + return; + } + final PackageManager pm = context.getPackageManager(); + // TODO this should target a user-selected panel + List<ResolveInfo> ril = pm.queryBroadcastReceivers(intent, 0 /* flags */); + if (ril != null && ril.size() != 0) { + ResolveInfo ri = ril.get(0); + final String senderPackageName = intent.getStringExtra(AudioEffect.EXTRA_PACKAGE_NAME); + try { + if (ri != null && ri.activityInfo != null && ri.activityInfo.packageName != null) { + final int senderUid = pm.getPackageUidAsUser(senderPackageName, + PackageManager.PackageInfoFlags.of(MATCH_ANY_USER), getCurrentUserId()); + intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + intent.setPackage(ri.activityInfo.packageName); + if (setMusicFxServiceWithObserver(intent, senderUid, senderPackageName)) { + context.sendBroadcastAsUser(intent, UserHandle.ALL); + } + return; + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Not able to find UID from package: " + senderPackageName + " error: " + + e); + } + } + Log.w(TAG, "couldn't find receiver package for effect intent"); + } + + @RequiresPermission(anyOf = { + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + android.Manifest.permission.INTERACT_ACROSS_USERS, + android.Manifest.permission.INTERACT_ACROSS_PROFILES + }) + @GuardedBy("mClientUidMapLock") + private boolean handleAudioEffectSessionOpen( + int senderUid, String senderPackageName, int sessionId) { + Log.d(TAG, senderPackageName + " UID " + senderUid + " open MusicFx session " + sessionId); + + PackageSessions pkgSessions = mClientUidSessionMap.get(Integer.valueOf(senderUid)); + if (pkgSessions != null && pkgSessions.mSessions != null) { + if (pkgSessions.mSessions.contains(sessionId)) { + Log.e(TAG, "Audio session " + sessionId + " already open for UID: " + + senderUid + ", package: " + senderPackageName + ", abort"); + return false; + } + if (pkgSessions.mPackageName != senderPackageName) { + Log.w(TAG, "Inconsistency package names for UID open: " + senderUid + " prev: " + + pkgSessions.mPackageName + ", now: " + senderPackageName); + return false; + } + } else { + // first session for this UID, create a new Package/Sessions pair + pkgSessions = new PackageSessions(); + pkgSessions.mSessions = new ArrayList(); + pkgSessions.mPackageName = senderPackageName; + } + + pkgSessions.mSessions.add(Integer.valueOf(sessionId)); + mClientUidSessionMap.put(Integer.valueOf(senderUid), pkgSessions); + return true; + } + + @RequiresPermission(anyOf = { + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + android.Manifest.permission.INTERACT_ACROSS_USERS, + android.Manifest.permission.INTERACT_ACROSS_PROFILES + }) + @GuardedBy("mClientUidMapLock") + private boolean handleAudioEffectSessionClose( + int senderUid, String senderPackageName, int sessionId) { + Log.d(TAG, senderPackageName + " UID " + senderUid + " close MusicFx session " + sessionId); + + PackageSessions pkgSessions = mClientUidSessionMap.get(Integer.valueOf(senderUid)); + if (pkgSessions == null) { + Log.e(TAG, senderPackageName + " UID " + senderUid + " does not exist in map, abort"); + return false; + } + if (pkgSessions.mPackageName != senderPackageName) { + Log.w(TAG, "Inconsistency package names for UID " + senderUid + " close, prev: " + + pkgSessions.mPackageName + ", now: " + senderPackageName); + return false; + } + + if (pkgSessions.mSessions != null && pkgSessions.mSessions.size() != 0) { + if (!pkgSessions.mSessions.contains(sessionId)) { + Log.e(TAG, senderPackageName + " UID " + senderUid + " session " + sessionId + + " does not exist in map, abort"); + return false; + } + + pkgSessions.mSessions.remove(Integer.valueOf(sessionId)); + } + + if (pkgSessions.mSessions == null || pkgSessions.mSessions.size() == 0) { + // remove UID from map as well as the UID observer with the last session close + mClientUidSessionMap.remove(Integer.valueOf(senderUid)); + } else { + mClientUidSessionMap.put(Integer.valueOf(senderUid), pkgSessions); + } + + return true; + } + + /** + * @return true if the intent is validated and handled successfully, false with any error + * (invalid sender/intent for example). + */ + @RequiresPermission(anyOf = { + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + android.Manifest.permission.INTERACT_ACROSS_USERS, + android.Manifest.permission.INTERACT_ACROSS_PROFILES + }) + private boolean setMusicFxServiceWithObserver( + Intent intent, int senderUid, String packageName) { + final int session = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION, + AudioManager.AUDIO_SESSION_ID_GENERATE); + if (AudioManager.AUDIO_SESSION_ID_GENERATE == session) { + Log.e(TAG, packageName + " intent have no invalid audio session"); + return false; + } + + synchronized (mClientUidMapLock) { + if (intent.getAction().equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)) { + return handleAudioEffectSessionOpen(senderUid, packageName, session); + } else { + return handleAudioEffectSessionClose(senderUid, packageName, session); + } + } + } + + private int getCurrentUserId() { + final long ident = Binder.clearCallingIdentity(); + try { + UserInfo currentUser = ActivityManager.getService().getCurrentUser(); + return currentUser.id; + } catch (RemoteException e) { + // Activity manager not running, nothing we can do assume user 0. + } finally { + Binder.restoreCallingIdentity(ident); + } + return UserHandle.USER_SYSTEM; + } + + + /** + * Handle the UidObserver onUidGone callback of MusicFx clients. + * Send close intent for all open audio sessions of this UID. The mClientUidSessionMap will be + * updated with the handling of close intent in setMusicFxServiceWithObserver. + */ + @RequiresPermission(allOf = {android.Manifest.permission.INTERACT_ACROSS_USERS}) + private void handleEffectClientUidGone(int uid) { + synchronized (mClientUidMapLock) { + Log.d(TAG, "handle MSG_EFFECT_CLIENT_GONE uid: " + uid + " mapSize: " + + mClientUidSessionMap.size()); + // Once the uid is no longer running, close all remain audio session(s) for this UID + final PackageSessions pkgSessions = mClientUidSessionMap.get(Integer.valueOf(uid)); + if (pkgSessions != null) { + Log.i(TAG, "UID " + uid + " gone, closing all sessions"); + + // send close intent for each open session of the gone UID + for (Integer sessionId : pkgSessions.mSessions) { + Intent closeIntent = + new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); + closeIntent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, pkgSessions.mPackageName); + closeIntent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, sessionId); + closeIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + // set broadcast target + closeIntent.setPackage(mMusicFxPackageName); + mContext.sendBroadcastAsUser(closeIntent, UserHandle.ALL); + } + mClientUidSessionMap.remove(Integer.valueOf(uid)); + } + } + } + + @RequiresPermission(allOf = {android.Manifest.permission.INTERACT_ACROSS_USERS}) + /*package*/ void handleMessage(Message msg) { + switch (msg.what) { + case MSG_EFFECT_CLIENT_GONE: + Log.w(TAG, " handle MSG_EFFECT_CLIENT_GONE"); + handleEffectClientUidGone(msg.arg1 /* uid */); + break; + default: + Log.e(TAG, "Unexpected msg to handle in MusicFxHelper: " + msg.what); + break; + } + } +} diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java index 81365bfbf2a6..6c5f3e74b0d2 100644 --- a/services/core/java/com/android/server/audio/SoundDoseHelper.java +++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java @@ -108,11 +108,11 @@ public class SoundDoseHelper { private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed - private static final int MSG_CONFIGURE_SAFE_MEDIA = SAFE_MEDIA_VOLUME_MSG_START + 1; - private static final int MSG_CONFIGURE_SAFE_MEDIA_FORCED = SAFE_MEDIA_VOLUME_MSG_START + 2; - private static final int MSG_PERSIST_SAFE_VOLUME_STATE = SAFE_MEDIA_VOLUME_MSG_START + 3; - private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = SAFE_MEDIA_VOLUME_MSG_START + 4; - private static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 5; + /*package*/ static final int MSG_CONFIGURE_SAFE_MEDIA = SAFE_MEDIA_VOLUME_MSG_START + 1; + /*package*/ static final int MSG_CONFIGURE_SAFE_MEDIA_FORCED = SAFE_MEDIA_VOLUME_MSG_START + 2; + /*package*/ static final int MSG_PERSIST_SAFE_VOLUME_STATE = SAFE_MEDIA_VOLUME_MSG_START + 3; + /*package*/ static final int MSG_PERSIST_MUSIC_ACTIVE_MS = SAFE_MEDIA_VOLUME_MSG_START + 4; + /*package*/ static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 5; /*package*/ static final int MSG_CSD_UPDATE_ATTENUATION = SAFE_MEDIA_VOLUME_MSG_START + 6; private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index bde7c1f18f13..0c2eee5aebbe 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -352,7 +352,6 @@ public class LockSettingsService extends ILockSettings.Stub { mLockSettingsService.deleteRepairModePersistentDataIfNeeded(); } else if (phase == PHASE_BOOT_COMPLETED) { mLockSettingsService.loadEscrowData(); - mLockSettingsService.deleteRepairModePersistentDataIfNeeded(); } } diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp index 3d4f866948af..d66b9b956071 100644 --- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp +++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp @@ -182,7 +182,7 @@ static inline IncFsSize verityTreeSizeForFile(IncFsSize fileSize) { auto block_count = 1 + (fileSize - 1) / INCFS_DATA_FILE_BLOCK_SIZE; auto hash_block_count = block_count; - for (auto i = 0; hash_block_count > 1; i++) { + while (hash_block_count > 1) { hash_block_count = (hash_block_count + hash_per_block - 1) / hash_per_block; total_tree_block_count += hash_block_count; } diff --git a/services/tests/servicestests/src/com/android/server/audio/MusicFxHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/MusicFxHelperTest.java new file mode 100644 index 000000000000..472a82c02937 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/audio/MusicFxHelperTest.java @@ -0,0 +1,642 @@ +/* + * Copyright 2023 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.audio; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyObject; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.media.audiofx.AudioEffect; +import android.os.Message; +import android.util.Log; + +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class MusicFxHelperTest { + private static final String TAG = "MusicFxHelperTest"; + + @Mock private AudioService mMockAudioService; + @Mock private Context mMockContext; + @Mock private PackageManager mMockPackageManager; + + private ResolveInfo mResolveInfo1 = new ResolveInfo(); + private ResolveInfo mResolveInfo2 = new ResolveInfo(); + private final String mTestPkg1 = "testPkg1", mTestPkg2 = "testPkg2", mTestPkg3 = "testPkg3"; + private final String mMusicFxPkgName = "com.android.musicfx"; + private final int mTestUid1 = 1, mTestUid2 = 2, mTestUid3 = 3, mMusicFxUid = 78; + private final int mTestSession1 = 11, mTestSession2 = 22, mTestSession3 = 33; + + private List<ResolveInfo> mEmptyList = new ArrayList<>(); + private List<ResolveInfo> mSingleList = new ArrayList<>(); + private List<ResolveInfo> mDoubleList = new ArrayList<>(); + + // the class being unit-tested here + @InjectMocks private MusicFxHelper mMusicFxHelper; + + @Before + @SuppressWarnings("DirectInvocationOnMock") + public void setUp() throws Exception { + mMockAudioService = mock(AudioService.class); + mMusicFxHelper = mMockAudioService.getMusicFxHelper(); + MockitoAnnotations.initMocks(this); + + mResolveInfo1.activityInfo = new ActivityInfo(); + mResolveInfo1.activityInfo.packageName = mTestPkg1; + mResolveInfo2.activityInfo = new ActivityInfo(); + mResolveInfo2.activityInfo.packageName = mTestPkg2; + + mSingleList.add(mResolveInfo1); + mDoubleList.add(mResolveInfo1); + mDoubleList.add(mResolveInfo2); + + Assert.assertNotNull(mMusicFxHelper); + } + + private Intent newIntent(String action, String packageName, int sessionId) { + Intent intent = new Intent(action); + if (packageName != null) { + intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, packageName); + } + intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, sessionId); + return intent; + } + + /** + * Helper function to send ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION intent with verification. + * + * @throws NameNotFoundException if no such package is available to the caller. + */ + private void openSessionWithResList( + List<ResolveInfo> list, int bind, int broadcast, String packageName, int audioSession, + int uid) { + doReturn(mMockPackageManager).when(mMockContext).getPackageManager(); + doReturn(list).when(mMockPackageManager).queryBroadcastReceivers(anyObject(), anyInt()); + if (list != null && list.size() != 0) { + try { + doReturn(uid).when(mMockPackageManager) + .getPackageUidAsUser(eq(packageName), anyObject(), anyInt()); + doReturn(mMusicFxUid).when(mMockPackageManager) + .getPackageUidAsUser(eq(mMusicFxPkgName), anyObject(), anyInt()); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "NameNotFoundException: " + e); + } + } + + Intent intent = newIntent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION, + packageName, audioSession); + mMusicFxHelper.handleAudioEffectBroadcast(mMockContext, intent); + verify(mMockContext, times(bind)) + .bindServiceAsUser(anyObject(), anyObject(), anyInt(), anyObject()); + verify(mMockContext, times(broadcast)).sendBroadcastAsUser(anyObject(), anyObject()); + } + + /** + * Helper function to send ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION intent with verification. + * + * @throws NameNotFoundException if no such package is available to the caller. + */ + private void closeSessionWithResList( + List<ResolveInfo> list, int unBind, int broadcast, String packageName, + int audioSession, int uid) { + doReturn(mMockPackageManager).when(mMockContext).getPackageManager(); + doReturn(list).when(mMockPackageManager).queryBroadcastReceivers(anyObject(), anyInt()); + if (list != null && list.size() != 0) { + try { + doReturn(uid).when(mMockPackageManager) + .getPackageUidAsUser(eq(packageName), anyObject(), anyInt()); + doReturn(mMusicFxUid).when(mMockPackageManager) + .getPackageUidAsUser(eq(mMusicFxPkgName), anyObject(), anyInt()); + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "NameNotFoundException: " + e); + } + } + + Intent intent = newIntent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION, + packageName, audioSession); + mMusicFxHelper.handleAudioEffectBroadcast(mMockContext, intent); + verify(mMockContext, times(unBind)).unbindService(anyObject()); + verify(mMockContext, times(broadcast)).sendBroadcastAsUser(anyObject(), anyObject()); + } + + /** + * Helper function to send MSG_EFFECT_CLIENT_GONE message with verification. + */ + private void sendMessage(int msgId, int uid, int unBinds, int broadcasts) { + mMusicFxHelper.handleMessage(Message.obtain(null, msgId, uid /* arg1 */, 0 /* arg2 */)); + verify(mMockContext, times(broadcasts)).sendBroadcastAsUser(anyObject(), anyObject()); + verify(mMockContext, times(unBinds)).unbindService(anyObject()); + } + + /** + * Send invalid message to MusicFxHelper. + */ + @Test + public void testInvalidMessage() { + Log.i(TAG, "running testInvalidMessage"); + + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE - 1, 0, 0, 0); + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE + 1, 0, 0, 0); + } + + /** + * Send client gone message to MusicFxHelper when no client exist. + */ + @Test + public void testGoneMessageWhenNoClient() { + Log.i(TAG, "running testGoneMessageWhenNoClient"); + + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, 0, 0, 0); + } + + /** + * Send ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION intent to MusicFxHelper when no session exist. + */ + @Test + public void testCloseBroadcastIntent() { + Log.i(TAG, "running testCloseBroadcastIntent"); + + closeSessionWithResList(null, 0, 0, null, mTestSession1, mTestUid1); + } + + /** + * OPEN/CLOSE AUDIO_EFFECT_CONTROL_SESSION intent when target application package was set. + * When the target application package was set for an intent, it means this intent is limited + * to a specific target application, as a result MusicFxHelper will not handle this intent. + */ + @Test + public void testBroadcastIntentWithPackage() { + Log.i(TAG, "running testBroadcastIntentWithPackage"); + + Intent intent = newIntent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION, null, 1); + intent.setPackage(mTestPkg1); + mMusicFxHelper.handleAudioEffectBroadcast(mMockContext, intent); + verify(mMockContext, times(0)) + .bindServiceAsUser(anyObject(), anyObject(), anyInt(), anyObject()); + verify(mMockContext, times(0)).sendBroadcastAsUser(anyObject(), anyObject()); + + intent = newIntent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION, null, 1); + intent.setPackage(mTestPkg2); + mMusicFxHelper.handleAudioEffectBroadcast(mMockContext, intent); + verify(mMockContext, times(0)) + .bindServiceAsUser(anyObject(), anyObject(), anyInt(), anyObject()); + verify(mMockContext, times(0)).sendBroadcastAsUser(anyObject(), anyObject()); + } + + /** + * OPEN/CLOSE AUDIO_EFFECT_CONTROL_SESSION with no broadcast receiver. + */ + @Test + public void testBroadcastIntentWithNoPackageAndNoBroadcastReceiver() { + Log.i(TAG, "running testBroadcastIntentWithNoPackageAndNoBroadcastReceiver"); + + openSessionWithResList(mEmptyList, 0, 0, null, mTestSession1, mTestUid1); + closeSessionWithResList(mEmptyList, 0, 0, null, mTestSession1, mTestUid1); + } + + /** + * OPEN/CLOSE AUDIO_EFFECT_CONTROL_SESSION with one broadcast receiver. + */ + @Test + public void testBroadcastIntentWithNoPackageAndOneBroadcastReceiver() { + Log.i(TAG, "running testBroadcastIntentWithNoPackageAndOneBroadcastReceiver"); + + int broadcasts = 1, bind = 1, unbind = 1; + openSessionWithResList(mSingleList, bind, broadcasts, null, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + closeSessionWithResList(mSingleList, unbind, broadcasts, null, mTestSession1, mTestUid1); + + // repeat with different session ID + broadcasts = broadcasts + 1; + bind = bind + 1; + unbind = unbind + 1; + openSessionWithResList(mSingleList, bind, broadcasts, null, mTestSession2, mTestUid1); + broadcasts = broadcasts + 1; + closeSessionWithResList(mSingleList, unbind, broadcasts, null, mTestSession2, mTestUid1); + + // repeat with different UID + broadcasts = broadcasts + 1; + bind = bind + 1; + unbind = unbind + 1; + openSessionWithResList(mSingleList, bind, broadcasts, null, mTestSession1, mTestUid2); + broadcasts = broadcasts + 1; + closeSessionWithResList(mSingleList, unbind, broadcasts, null, mTestSession1, mTestUid2); + } + + /** + * OPEN/CLOSE AUDIO_EFFECT_CONTROL_SESSION with two broadcast receivers. + */ + @Test + public void testBroadcastIntentWithNoPackageAndTwoBroadcastReceivers() { + Log.i(TAG, "running testBroadcastIntentWithNoPackageAndTwoBroadcastReceivers"); + + openSessionWithResList(mDoubleList, 1, 1, null, mTestSession1, mTestUid1); + closeSessionWithResList(mDoubleList, 1, 2, null, mTestSession1, mTestUid1); + } + + /** + * Open/close session UID not matching. + * No broadcast for mismatching sessionID/UID/packageName. + */ + @Test + public void testBroadcastBadIntents() { + Log.i(TAG, "running testBroadcastBadIntents"); + + int broadcasts = 1; + openSessionWithResList(mSingleList, 1, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + // mismatch UID + closeSessionWithResList(mSingleList, 0, broadcasts, mTestPkg1, mTestSession1, mTestUid2); + // mismatch AudioSession + closeSessionWithResList(mSingleList, 0, broadcasts, mTestPkg1, mTestSession2, mTestUid1); + // mismatch packageName + closeSessionWithResList(mSingleList, 0, broadcasts, mTestPkg2, mTestSession1, mTestUid1); + + // cleanup with correct UID and session ID + broadcasts = broadcasts + 1; + closeSessionWithResList(mSingleList, 1, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + } + + /** + * Open/close sessions with one UID, some with correct intents some with illegal intents. + * No broadcast for mismatching sessionID/UID/packageName. + */ + @Test + public void testBroadcastGoodAndBadIntents() { + Log.i(TAG, "running testBroadcastGoodAndBadIntents"); + + int broadcasts = 1, bind = 1, unbind = 0; + openSessionWithResList(mSingleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + // mismatch packageName, session ID and UID + closeSessionWithResList(mSingleList, unbind, broadcasts, mTestPkg2, mTestSession2, + mTestUid2); + // mismatch session ID and mismatch UID + closeSessionWithResList(mSingleList, unbind, broadcasts, mTestPkg1, mTestSession2, + mTestUid2); + // mismatch packageName and mismatch UID + closeSessionWithResList(mSingleList, unbind, broadcasts, mTestPkg2, mTestSession1, + mTestUid2); + // mismatch packageName and sessionID + closeSessionWithResList(mSingleList, unbind, broadcasts, mTestPkg2, mTestSession2, + mTestUid1); + // inconsistency package name for same UID + openSessionWithResList(mSingleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid1); + // open session2 with good intent + broadcasts = broadcasts + 1; + openSessionWithResList(mSingleList, bind, broadcasts, mTestPkg1, mTestSession2, mTestUid1); + + // cleanup with correct UID and session ID + broadcasts = broadcasts + 1; + closeSessionWithResList(mSingleList, unbind, broadcasts, mTestPkg1, mTestSession1, + mTestUid1); + broadcasts = broadcasts + 1; + unbind = unbind + 1; + closeSessionWithResList(mSingleList, unbind, broadcasts, mTestPkg1, mTestSession2, + mTestUid1); + } + + /** + * Send ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION when there is no listener. + */ + @Test + public void testBroadcastOpenSessionWithValidPackageNameAndNoListener() { + Log.i(TAG, "running testBroadcastOpenSessionWithValidPackageNameAndNoListener"); + + // null listener list should not trigger any action + openSessionWithResList(null, 0, 0, mTestPkg1, mTestSession1, mTestUid1); + // empty listener list should not trigger any action + openSessionWithResList(mEmptyList, 0, 0, mTestPkg1, mTestSession1, mTestUid1); + } + + /** + * One MusicFx client, open session and close. + */ + @Test + public void testOpenCloseAudioSession() { + Log.i(TAG, "running testOpenCloseAudioSession"); + + int broadcasts = 1; + openSessionWithResList(mDoubleList, 1, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, 1, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + } + + /** + * One MusicFx client, open session and close, then gone. + */ + @Test + public void testOpenCloseAudioSessionAndGone() { + Log.i(TAG, "running testOpenCloseAudioSessionAndGone"); + + int broadcasts = 1; + openSessionWithResList(mDoubleList, 1, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, 1, broadcasts, mTestPkg1, mTestSession2, mTestUid1); + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, 0, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + + broadcasts = broadcasts + 1; // 1 open session left + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid1, 1, broadcasts); + } + + /** + * One MusicFx client, open session, then UID gone without close. + */ + @Test + public void testOpenOneSessionAndGo() { + Log.i(TAG, "running testOpenOneSessionAndGo"); + + int broadcasts = 1; + openSessionWithResList(mDoubleList, 1, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + + broadcasts = broadcasts + 1; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid1, 1, broadcasts); + } + + /** + * Two MusicFx clients open and close sessions. + */ + @Test + public void testOpenTwoSessionsAndClose() { + Log.i(TAG, "running testOpenTwoSessionsAndClose"); + + int broadcasts = 1, bind = 1, unbind = 0; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid2); + + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg2, mTestSession2, + mTestUid2); + broadcasts = broadcasts + 1; + unbind = unbind + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession1, + mTestUid1); + + broadcasts = broadcasts + 1; + bind = bind + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid2); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession1, + mTestUid1); + broadcasts = broadcasts + 1; + unbind = unbind + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg2, mTestSession2, + mTestUid2); + } + + /** + * Two MusicFx clients open sessions, then both UID gone without close. + */ + @Test + public void testOpenTwoSessionsAndGo() { + Log.i(TAG, "running testOpenTwoSessionsAndGo"); + + int broadcasts = 1, bind = 1, unbind = 0; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid2); + + broadcasts = broadcasts + 1; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid1, unbind, broadcasts); + + broadcasts = broadcasts + 1; + unbind = unbind + 1; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid2, unbind, broadcasts); + } + + /** + * Two MusicFx clients open sessions, one close but not gone, the other one gone without close. + */ + @Test + public void testTwoSessionsOpenOneCloseOneGo() { + Log.i(TAG, "running testTwoSessionsOpneAndOneCloseOneGo"); + + int broadcasts = 1, bind = 1, unbind = 0; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid2); + + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession1, + mTestUid1); + + broadcasts = broadcasts + 1; + unbind = unbind + 1; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid2, unbind, broadcasts); + } + + /** + * One MusicFx client, open multiple audio sessions, and close all sessions. + */ + @Test + public void testTwoSessionsInSameUidOpenClose() { + Log.i(TAG, "running testTwoSessionsOpneAndOneCloseOneGo"); + + int broadcasts = 1, bind = 1, unbind = 0; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession2, mTestUid1); + + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession1, + mTestUid1); + broadcasts = broadcasts + 1; + unbind = unbind + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession2, + mTestUid1); + } + + /** + * Three MusicFx clients, each with multiple audio sessions, and close all sessions. + */ + @Test + public void testThreeSessionsInThreeUidOpenClose() { + Log.i(TAG, "running testThreeSessionsInThreeUidOpenClose"); + + int broadcasts = 1, bind = 1, unbind = 0; + //client1 + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession2, mTestUid1); + // client2 + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession3, mTestUid2); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid2); + // client3 + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg3, mTestSession1, mTestUid3); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg3, mTestSession3, mTestUid3); + + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession1, + mTestUid1); + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg3, mTestSession3, + mTestUid3); + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg2, mTestSession2, + mTestUid2); + // all sessions of client1 closed + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession2, + mTestUid1); + // all sessions of client3 closed + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg3, mTestSession1, + mTestUid3); + // all sessions of client2 closed + broadcasts = broadcasts + 1; + // now expect unbind to happen + unbind = unbind + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg2, mTestSession3, + mTestUid2); + } + + /** + * Two MusicFx clients, with multiple audio sessions, one close all sessions, and other gone. + */ + @Test + public void testTwoUidOneCloseOneGo() { + Log.i(TAG, "running testTwoUidOneCloseOneGo"); + + int broadcasts = 1, bind = 1, unbind = 0; + //client1 + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession2, mTestUid1); + // client2 + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession1, mTestUid2); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid2); + + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession1, + mTestUid1); + // client2 gone + broadcasts = broadcasts + 2; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid2, unbind, broadcasts); + // client 1 close all sessions + broadcasts = broadcasts + 1; + unbind = unbind + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession2, + mTestUid1); + } + + /** + * Three MusicFx clients, with multiple audio sessions, all UID gone. + */ + @Test + public void testThreeUidAllGo() { + Log.i(TAG, "running testThreeUidAllGo"); + + int broadcasts = 1, bind = 1, unbind = 0; + //client1 + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession2, mTestUid1); + // client2 + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid2); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession3, mTestUid2); + // client3 + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg3, mTestSession3, mTestUid3); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg3, mTestSession1, mTestUid3); + + // client2 gone + broadcasts = broadcasts + 2; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid2, unbind, broadcasts); + // client3 gone + broadcasts = broadcasts + 2; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid3, unbind, broadcasts); + // client 1 gone + broadcasts = broadcasts + 2; + // now expect unbindService to happen + unbind = unbind + 1; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid1, unbind, broadcasts); + } + + /** + * Three MusicFx clients, multiple audio sessions, open and UID gone in difference sequence. + */ + @Test + public void testThreeUidDiffSequence() { + Log.i(TAG, "running testThreeUidDiffSequence"); + + int broadcasts = 1, bind = 1, unbind = 0; + //client1 + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession1, mTestUid1); + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg1, mTestSession2, mTestUid1); + // client2 + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession2, mTestUid2); + // client1 close one session + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession1, + mTestUid1); + // client2 open another session + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg2, mTestSession3, mTestUid2); + // client3 open one session + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg3, mTestSession3, mTestUid3); + // client2 gone + broadcasts = broadcasts + 2; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid2, unbind, broadcasts); + // client3 open another session + broadcasts = broadcasts + 1; + openSessionWithResList(mDoubleList, bind, broadcasts, mTestPkg3, mTestSession1, mTestUid3); + // client1 close another session, and gone + broadcasts = broadcasts + 1; + closeSessionWithResList(mDoubleList, unbind, broadcasts, mTestPkg1, mTestSession2, + mTestUid1); + // last UID client3 gone, unbind + broadcasts = broadcasts + 2; + unbind = unbind + 1; + sendMessage(MusicFxHelper.MSG_EFFECT_CLIENT_GONE, mTestUid3, unbind, broadcasts); + } +} diff --git a/tools/aapt2/integration-tests/AutoVersionTest/Android.bp b/tools/aapt2/integration-tests/AutoVersionTest/Android.bp index bfd35083366e..c901efa707f4 100644 --- a/tools/aapt2/integration-tests/AutoVersionTest/Android.bp +++ b/tools/aapt2/integration-tests/AutoVersionTest/Android.bp @@ -26,4 +26,5 @@ package { android_test { name: "AaptAutoVersionTest", sdk_version: "current", + use_resource_processor: false, } diff --git a/tools/aapt2/integration-tests/BasicTest/Android.bp b/tools/aapt2/integration-tests/BasicTest/Android.bp index 7db9d2698cc7..d0649ea4ef9c 100644 --- a/tools/aapt2/integration-tests/BasicTest/Android.bp +++ b/tools/aapt2/integration-tests/BasicTest/Android.bp @@ -26,4 +26,5 @@ package { android_test { name: "AaptBasicTest", sdk_version: "current", + use_resource_processor: false, } diff --git a/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp index 80404eeb8d8e..ebb4e9f479d6 100644 --- a/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp +++ b/tools/aapt2/integration-tests/StaticLibTest/App/Android.bp @@ -24,9 +24,9 @@ package { } android_test { - name: "AaptTestStaticLib_App", sdk_version: "current", + use_resource_processor: false, srcs: ["src/**/*.java"], asset_dirs: [ "assets", diff --git a/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp index a84da43c70c8..ee12a92906a8 100644 --- a/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp +++ b/tools/aapt2/integration-tests/StaticLibTest/LibOne/Android.bp @@ -26,6 +26,7 @@ package { android_library { name: "AaptTestStaticLib_LibOne", sdk_version: "current", + use_resource_processor: false, srcs: ["src/**/*.java"], resource_dirs: ["res"], } diff --git a/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp index d386c3a35d20..83b2362496fc 100644 --- a/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp +++ b/tools/aapt2/integration-tests/StaticLibTest/LibTwo/Android.bp @@ -26,6 +26,7 @@ package { android_library { name: "AaptTestStaticLib_LibTwo", sdk_version: "current", + use_resource_processor: false, srcs: ["src/**/*.java"], resource_dirs: ["res"], libs: ["AaptTestStaticLib_LibOne"], diff --git a/tools/aapt2/integration-tests/SymlinkTest/Android.bp b/tools/aapt2/integration-tests/SymlinkTest/Android.bp index 1e8cf86ed811..6fcdf1c77704 100644 --- a/tools/aapt2/integration-tests/SymlinkTest/Android.bp +++ b/tools/aapt2/integration-tests/SymlinkTest/Android.bp @@ -26,4 +26,8 @@ package { android_test { name: "AaptSymlinkTest", sdk_version: "current", + use_resource_processor: false, + compile_data: [ + "targets/*", + ], } |