blob: af06d157a52697a5223ed659ea80506fb7f96fb0 [file] [log] [blame]
/*
* Copyright 2018 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.media;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.media.IMediaExtractorUpdateService;
import android.os.Build;
import android.os.IBinder;
import android.os.Handler;
import android.os.PatternMatcher;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import com.android.server.SystemService;
/** This class provides a system service that manages media framework updates. */
public class MediaUpdateService extends SystemService {
private static final String TAG = "MediaUpdateService";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String MEDIA_UPDATE_PACKAGE_NAME =
SystemProperties.get("ro.mediacomponents.package");
private static final String EXTRACTOR_UPDATE_SERVICE_NAME = "media.extractor.update";
private IMediaExtractorUpdateService mMediaExtractorUpdateService;
final Handler mHandler;
public MediaUpdateService(Context context) {
super(context);
mHandler = new Handler();
}
@Override
public void onStart() {
if (("userdebug".equals(android.os.Build.TYPE) || "eng".equals(android.os.Build.TYPE))
&& !TextUtils.isEmpty(MEDIA_UPDATE_PACKAGE_NAME)) {
connect();
registerBroadcastReceiver();
}
}
private void connect() {
IBinder binder = ServiceManager.getService(EXTRACTOR_UPDATE_SERVICE_NAME);
if (binder != null) {
try {
binder.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Slog.w(TAG, "mediaextractor died; reconnecting");
mMediaExtractorUpdateService = null;
connect();
}
}, 0);
} catch (Exception e) {
binder = null;
}
}
if (binder != null) {
mMediaExtractorUpdateService = IMediaExtractorUpdateService.Stub.asInterface(binder);
mHandler.post(new Runnable() {
@Override
public void run() {
packageStateChanged();
}
});
} else {
Slog.w(TAG, EXTRACTOR_UPDATE_SERVICE_NAME + " not found.");
}
}
private void registerBroadcastReceiver() {
BroadcastReceiver updateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_SYSTEM)
!= UserHandle.USER_SYSTEM) {
// Ignore broadcast for non system users. We don't want to update system
// service multiple times.
return;
}
switch (intent.getAction()) {
case Intent.ACTION_PACKAGE_REMOVED:
if (intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
// The existing package is updated. Will be handled with the
// following ACTION_PACKAGE_ADDED case.
return;
}
packageStateChanged();
break;
case Intent.ACTION_PACKAGE_CHANGED:
packageStateChanged();
break;
case Intent.ACTION_PACKAGE_ADDED:
packageStateChanged();
break;
}
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
filter.addDataSchemeSpecificPart(MEDIA_UPDATE_PACKAGE_NAME, PatternMatcher.PATTERN_LITERAL);
getContext().registerReceiverAsUser(updateReceiver, UserHandle.ALL, filter,
null /* broadcast permission */, null /* handler */);
}
private void packageStateChanged() {
ApplicationInfo packageInfo = null;
boolean pluginsAvailable = false;
try {
packageInfo = getContext().getPackageManager().getApplicationInfo(
MEDIA_UPDATE_PACKAGE_NAME, PackageManager.MATCH_SYSTEM_ONLY);
pluginsAvailable = packageInfo.enabled;
} catch (Exception e) {
Slog.v(TAG, "package '" + MEDIA_UPDATE_PACKAGE_NAME + "' not installed");
}
if (packageInfo != null && Build.VERSION.SDK_INT != packageInfo.targetSdkVersion) {
Slog.w(TAG, "This update package is not for this platform version. Ignoring. "
+ "platform:" + Build.VERSION.SDK_INT
+ " targetSdk:" + packageInfo.targetSdkVersion);
pluginsAvailable = false;
}
loadExtractorPlugins(
(packageInfo != null && pluginsAvailable) ? packageInfo.sourceDir : "");
}
private void loadExtractorPlugins(String apkPath) {
try {
if (mMediaExtractorUpdateService != null) {
mMediaExtractorUpdateService.loadPlugins(apkPath);
}
} catch (Exception e) {
Slog.w(TAG, "Error in loadPlugins", e);
}
}
}