diff options
3 files changed, 114 insertions, 45 deletions
diff --git a/apex/framework/java/android/provider/OemMetadataServiceWrapper.java b/apex/framework/java/android/provider/OemMetadataServiceWrapper.java index 278f1b94a..634632589 100644 --- a/apex/framework/java/android/provider/OemMetadataServiceWrapper.java +++ b/apex/framework/java/android/provider/OemMetadataServiceWrapper.java @@ -37,6 +37,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -53,6 +54,8 @@ public final class OemMetadataServiceWrapper { private final IOemMetadataService mOemMetadataService; + private final ExecutorService mExecutorService; + private final long mServiceTimeoutInSeconds; public OemMetadataServiceWrapper(@NonNull IOemMetadataService oemMetadataService) { @@ -65,6 +68,7 @@ public final class OemMetadataServiceWrapper { this.mOemMetadataService = oemMetadataService; this.mServiceTimeoutInSeconds = serviceTimeoutInSeconds; + mExecutorService = Executors.newFixedThreadPool(3); } /** @@ -76,7 +80,7 @@ public final class OemMetadataServiceWrapper { return new HashSet<>(); } - return Executors.newSingleThreadExecutor().submit(() -> { + return mExecutorService.submit(() -> { CompletableFuture<Set<String>> future = new CompletableFuture<>(); RemoteCallback callback = new RemoteCallback( result -> setResultForGetSupportedMimeTypes(result, future)); @@ -94,7 +98,7 @@ public final class OemMetadataServiceWrapper { return new HashMap<>(); } - return Executors.newSingleThreadExecutor().submit(() -> { + return mExecutorService.submit(() -> { CompletableFuture<Map<String, String>> future = new CompletableFuture<>(); RemoteCallback callback = new RemoteCallback( result -> setResultForGetOemCustomData(result, future)); diff --git a/src/com/android/providers/media/scan/ModernMediaScanner.java b/src/com/android/providers/media/scan/ModernMediaScanner.java index d7f146f26..a32279e7f 100644 --- a/src/com/android/providers/media/scan/ModernMediaScanner.java +++ b/src/com/android/providers/media/scan/ModernMediaScanner.java @@ -154,6 +154,8 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TimeZone; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Matcher; @@ -259,9 +261,20 @@ public class ModernMediaScanner implements MediaScanner { */ private Set<String> mOemSupportedMimeTypes; + /** + * Default OemMetadataService implementation package. + */ + private Optional<String> mDefaultOemMetadataServicePackage; + + /** + * Count down latch to process delay in connection to OemMetadataService. + */ + private CountDownLatch mCountDownLatchForOemMetadataConnection = new CountDownLatch(1); + public ModernMediaScanner(@NonNull Context context, @NonNull ConfigStore configStore) { mContext = requireNonNull(context); mDrmClient = new DrmManagerClient(context); + mDefaultOemMetadataServicePackage = configStore.getDefaultOemMetadataServicePackage(); // Dynamically collect the set of MIME types that should be considered // to be DRM, as this can vary between devices @@ -271,15 +284,25 @@ public class ModernMediaScanner implements MediaScanner { mDrmMimeTypes.add(mimeTypes.next()); } } - connectOemMetadataServiceWrapper(configStore); } private Set<String> getOemSupportedMimeTypes() { - if (mOemMetadataServiceWrapper == null) { - return new HashSet<String>(); - } - try { + // Return if no package implements OemMetadataService + if (!mDefaultOemMetadataServicePackage.isPresent()) { + return new HashSet<>(); + } + + // Setup connection if missing + if (mOemMetadataServiceWrapper == null) { + connectOemMetadataServiceWrapper(); + } + + // Return empty set if we cannot setup any connection + if (mOemMetadataServiceWrapper == null) { + return new HashSet<>(); + } + return mOemMetadataServiceWrapper.getSupportedMimeTypes(); } catch (Exception e) { Log.w(TAG, "Error in fetching OEM supported mimetypes", e); @@ -287,32 +310,42 @@ public class ModernMediaScanner implements MediaScanner { } } - private void connectOemMetadataServiceWrapper(ConfigStore configStore) { - if (!enableOemMetadata()) { - return; - } + private synchronized void connectOemMetadataServiceWrapper() { + try { + if (!enableOemMetadata()) { + return; + } - Optional<String> pkgOptional = configStore.getDefaultOemMetadataServicePackage(); - if (!pkgOptional.isPresent()) { - Log.v(TAG, "No default package listed for OEM Metadata service"); - return; - } + // Return if wrapper is already initialised + if (mOemMetadataServiceWrapper != null) { + return; + } - Intent intent = new Intent(OemMetadataService.SERVICE_INTERFACE); - ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, - PackageManager.MATCH_ALL); - if (resolveInfo == null || resolveInfo.serviceInfo == null - || resolveInfo.serviceInfo.packageName == null - || !pkgOptional.get().equalsIgnoreCase(resolveInfo.serviceInfo.packageName) - || resolveInfo.serviceInfo.permission == null - || !resolveInfo.serviceInfo.permission.equalsIgnoreCase( - OemMetadataService.BIND_OEM_METADATA_SERVICE_PERMISSION)) { - Log.v(TAG, "No valid package found for OEM Metadata service"); - return; - } + if (!mDefaultOemMetadataServicePackage.isPresent()) { + Log.v(TAG, "No default package listed for OEM Metadata service"); + return; + } + + Intent intent = new Intent(OemMetadataService.SERVICE_INTERFACE); + ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, + PackageManager.MATCH_ALL); + if (resolveInfo == null || resolveInfo.serviceInfo == null + || resolveInfo.serviceInfo.packageName == null + || !mDefaultOemMetadataServicePackage.get().equalsIgnoreCase( + resolveInfo.serviceInfo.packageName) + || resolveInfo.serviceInfo.permission == null + || !resolveInfo.serviceInfo.permission.equalsIgnoreCase( + OemMetadataService.BIND_OEM_METADATA_SERVICE_PERMISSION)) { + Log.v(TAG, "No valid package found for OEM Metadata service"); + return; + } - intent.setPackage(pkgOptional.get()); - mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); + intent.setPackage(mDefaultOemMetadataServicePackage.get()); + mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); + mCountDownLatchForOemMetadataConnection.await(5, TimeUnit.SECONDS); + } catch (Exception e) { + Log.e(TAG, "Exception in connecting OemMetadataServiceWrapper", e); + } } private ServiceConnection mServiceConnection = new ServiceConnection() { @@ -320,15 +353,31 @@ public class ModernMediaScanner implements MediaScanner { public void onServiceConnected(ComponentName componentName, IBinder iBinder) { IOemMetadataService service = IOemMetadataService.Stub.asInterface(iBinder); mOemMetadataServiceWrapper = new OemMetadataServiceWrapper(service); + mCountDownLatchForOemMetadataConnection.countDown(); Log.i(TAG, "Connected to OemMetadataService"); } + @Override public void onServiceDisconnected(ComponentName componentName) { mOemMetadataServiceWrapper = null; - Log.i(TAG, "Disconnected from OemMetadataService"); + Log.w(TAG, "Disconnected from OemMetadataService"); + mCountDownLatchForOemMetadataConnection = new CountDownLatch(1); + } + + @Override + public void onBindingDied(ComponentName name) { + Log.w(TAG, "Binding to OemMetadataService died"); + mContext.unbindService(this); + mOemMetadataServiceWrapper = null; + mCountDownLatchForOemMetadataConnection = new CountDownLatch(1); } }; + @VisibleForTesting + public ServiceConnection getOemMetadataServiceConnection() { + return mServiceConnection; + } + @Override @NonNull public Context getContext() { @@ -1004,17 +1053,35 @@ public class ModernMediaScanner implements MediaScanner { } private void fetchOemMetadata(ContentProviderOperation.Builder op, File file) { - if (!enableOemMetadata() || mOemMetadataServiceWrapper == null) { + if (!enableOemMetadata()) { return; } + try { + // Return if no package implements OemMetadataService + if (!mDefaultOemMetadataServicePackage.isPresent()) { + return; + } - try (ParcelFileDescriptor pfd = FileUtils.openSafely(file, - ParcelFileDescriptor.MODE_READ_ONLY)) { - Map<String, String> oemMetadata = mOemMetadataServiceWrapper.getOemCustomData(pfd); - op.withValue(FileColumns.OEM_METADATA, oemMetadata.toString().getBytes()); - Log.v(TAG, "Fetched OEM metadata successfully"); + if (mOemMetadataServiceWrapper == null) { + connectOemMetadataServiceWrapper(); + } + + // Return if we cannot find any connection + if (mOemMetadataServiceWrapper == null) { + return; + } + + try (ParcelFileDescriptor pfd = FileUtils.openSafely(file, + ParcelFileDescriptor.MODE_READ_ONLY)) { + Map<String, String> oemMetadata = mOemMetadataServiceWrapper.getOemCustomData( + pfd); + op.withValue(FileColumns.OEM_METADATA, oemMetadata.toString().getBytes()); + Log.v(TAG, "Fetched OEM metadata successfully"); + } catch (Exception e) { + Log.w(TAG, "Failure in fetching OEM metadata", e); + } } catch (Exception e) { - Log.w(TAG, "Failure in fetching OEM metadata", e); + Log.w(TAG, "Failure in connecting to OEM metadata service", e); } } diff --git a/tests/src/com/android/providers/media/oemmetadataservices/OemMetadataServiceTest.java b/tests/src/com/android/providers/media/oemmetadataservices/OemMetadataServiceTest.java index c01e06f00..774635be4 100644 --- a/tests/src/com/android/providers/media/oemmetadataservices/OemMetadataServiceTest.java +++ b/tests/src/com/android/providers/media/oemmetadataservices/OemMetadataServiceTest.java @@ -36,15 +36,13 @@ import android.os.Build; import android.os.Environment; import android.os.IBinder; import android.os.ParcelFileDescriptor; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.IOemMetadataService; import android.provider.MediaStore; import android.provider.MediaStore.Files.FileColumns; import android.provider.OemMetadataService; import android.provider.OemMetadataServiceWrapper; -import android.provider.media.internal.flags.Flags; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SdkSuppress; @@ -73,12 +71,11 @@ import java.util.concurrent.TimeoutException; import java.util.function.Supplier; @RunWith(AndroidJUnit4.class) -@RequiresFlagsEnabled(com.android.providers.media.flags.Flags.FLAG_ENABLE_OEM_METADATA) +@EnableFlags(com.android.providers.media.flags.Flags.FLAG_ENABLE_OEM_METADATA) @SdkSuppress(minSdkVersion = Build.VERSION_CODES.S) public class OemMetadataServiceTest { - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private static final long POLLING_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); private static final long POLLING_SLEEP_MILLIS = 100; @@ -179,6 +176,7 @@ public class OemMetadataServiceTest { } } finally { audioFile.delete(); + isolatedContext.unbindService(modernMediaScanner.getOemMetadataServiceConnection()); } } |