下面列出了怎么用android.content.pm.ComponentInfo的API类实例代码及写法,或者点击链接到github查看源代码。
private static void preMakeApplication(Context hostContext, ComponentInfo pluginInfo) {
try {
Object loadedApk = sPluginLoadedApkCache.get(pluginInfo.packageName);
if (loadedApk != null && FieldUtils.readField(loadedApk, "mApplication") == null) {
if (Looper.getMainLooper() != Looper.myLooper()) {
Object lock = new Object();
mExec.set(false);
mHandle.post(new 1(loadedApk, pluginInfo, lock));
if (!mExec.get()) {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
}
}
return;
}
return;
}
MethodUtils.invokeMethod(loadedApk, "makeApplication", Boolean.valueOf(false), ActivityThreadCompat.getInstrumentation());
}
} catch (Exception e2) {
JLog.logApk("插件preMakeApplication 失败 e=" + e2.getMessage());
}
}
private void doAdjust(HashMap<String, String> processMap, HashMap<String, ? extends ComponentInfo> infos) throws Exception {
for (HashMap.Entry<String, ? extends ComponentInfo> entry : infos.entrySet()) {
ComponentInfo info = entry.getValue();
if (info != null) {
String targetProcess = processMap.get(info.processName);
// 如果原始进程名称为空,说明解析插件 apk 时有问题(未解析每个组件的进程名称)。
// 此处抛出异常。
if (!TextUtils.isEmpty(targetProcess)) {
info.processName = targetProcess;
}
if (LOG) {
Log.d(PLUGIN_TAG, info.name + ":" + info.processName);
}
}
}
}
/**
* 指定されたコンポーネントがプラグインの情報か確認します.
*
* @param compInfo コンポーネント
* @return プラグインの場合はtrue、それ以外はfalse
*/
private boolean isDevicePlugin(final ComponentInfo compInfo) {
if (!compInfo.exported) {
return false;
}
Bundle metaData = compInfo.metaData;
if (metaData == null) {
return false;
}
if (metaData.get(PLUGIN_META_DATA) == null) {
return false;
}
if (!(metaData.get(PLUGIN_META_DATA) instanceof Integer)) {
return false;
}
DevicePluginXml xml = DevicePluginXmlUtil.getXml(mContext, compInfo);
return xml != null;
}
public String getStubProcessByTarget(ComponentInfo targetInfo) {
for (ProcessItem processItem : items.values()) {
if (processItem.pkgs.contains(targetInfo.packageName) && TextUtils.equals(processItem.targetProcessName, targetInfo.processName)) {
return processItem.stubProcessName;
} else {
try {
boolean signed = false;
for (String pkg : processItem.pkgs) {
if (PluginManager.getInstance().checkSignatures(targetInfo.packageName, pkg) == PackageManager.SIGNATURE_MATCH) {
signed = true;
break;
}
}
if (signed && TextUtils.equals(processItem.targetProcessName, targetInfo.processName)) {
return processItem.stubProcessName;
}
} catch (Exception e) {
Log.e(TAG, "getStubProcessByTarget:error", e);
}
}
}
return null;
}
ListItem(PackageManager pm, ResolveInfo resolveInfo, IconResizer resizer) {
this.resolveInfo = resolveInfo;
label = resolveInfo.loadLabel(pm);
ComponentInfo ci = resolveInfo.activityInfo;
if (ci == null) ci = resolveInfo.serviceInfo;
if (label == null && ci != null) {
label = resolveInfo.activityInfo.name;
}
if (resizer != null) {
icon = resizer.createIconThumbnail(resolveInfo.loadIcon(pm));
}
packageName = ci.applicationInfo.packageName;
className = ci.name;
}
@SuppressWarnings("deprecation")
public static boolean isComponentEnabled(PackageManager manager, ComponentName component) {
switch (manager.getComponentEnabledSetting(component)) {
case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
return false;
case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
return true;
case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
default:
try {
PackageInfo packageInfo = manager.getPackageInfo(
component.getPackageName(),
PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
| PackageManager.GET_PROVIDERS | PackageManager.GET_DISABLED_COMPONENTS);
List<ComponentInfo> components = new ArrayList<>();
if (packageInfo.activities != null) {
Collections.addAll(components, packageInfo.activities);
}
if (packageInfo.services != null) {
Collections.addAll(components, packageInfo.services);
}
if (packageInfo.providers != null) {
Collections.addAll(components, packageInfo.providers);
}
for (ComponentInfo componentInfo : components) {
if (componentInfo.name.equals(component.getClassName())) {
return componentInfo.isEnabled();
}
}
return false;
} catch (PackageManager.NameNotFoundException e) {
// the package isn't installed on the device
return false;
}
}
}
/**
* 从 ComponentInfo 获取 插件名称
*/
public static String getPluginName(ComponentInfo ci) {
if (ci != null && ci.packageName != null) {
int indexOfLastDot = ci.packageName.lastIndexOf(".");
if (indexOfLastDot > 0) {
return ci.packageName.substring(indexOfLastDot + 1);
}
}
return "";
}
public static String getProcessName(ComponentInfo componentInfo) {
String processName = componentInfo.processName;
if (processName == null) {
processName = componentInfo.packageName;
componentInfo.processName = processName;
}
return processName;
}
public static boolean isSameComponent(ComponentInfo first, ComponentInfo second) {
if (first != null && second != null) {
String pkg1 = first.packageName + "";
String pkg2 = second.packageName + "";
String name1 = first.name + "";
String name2 = second.name + "";
return pkg1.equals(pkg2) && name1.equals(name2);
}
return false;
}
public static void fixComponentInfo(AppSetting appSetting, ComponentInfo info, int userId) {
if (info != null) {
if (TextUtils.isEmpty(info.processName)) {
info.processName = info.packageName;
}
fixApplicationInfo(appSetting, info.applicationInfo, userId);
info.name = fixComponentClassName(info.packageName, info.name);
if (info.processName == null) {
info.processName = info.applicationInfo.processName;
}
}
}
public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
this(args, (PackageItemInfo)outInfo);
if (args.outError[0] != null) {
return;
}
if (args.processRes != 0) {
CharSequence pname;
if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
// pname = args.sa.getNonConfigurationString(args.processRes,
// Configuration.NATIVE_CONFIG_VERSION);
pname = args.sa.getNonResourceString(args.processRes);
} else {
// Some older apps have been seen to use a resource reference
// here that on older builds was ignored (with a warning). We
// need to continue to do this for them so they don't break.
pname = args.sa.getNonResourceString(args.processRes);
}
outInfo.processName = buildProcessName(owner.applicationInfo.packageName,
owner.applicationInfo.processName, pname,
args.sepProcesses, args.outError);
}
if (args.descriptionRes != 0) {
outInfo.descriptionRes = args.sa.getResourceId(args.descriptionRes, 0);
}
outInfo.enabled = args.sa.getBoolean(args.enabledRes, true);
}
/**
* デバイスプラグインのxmlファイルを参照し、スコープに対応する有効期限設定値があれば返す.
*
* @param context コンテキスト
* @param pluginComponent デバイスプラグインを宣言するコンポーネント
* @return not null: xmlで定義されているスコープ名と有効期限[msec]が対応付けされたMap / null:
* 有効期限設定値無し
*/
public static Map<String, DevicePluginXmlProfile> getSupportProfiles(final Context context,
final ComponentInfo pluginComponent) {
if (pluginComponent != null) {
if (pluginComponent.metaData != null) {
DevicePluginXml xml = getXml(context, pluginComponent);
if (xml != null) {
return xml.getSupportedProfiles();
}
}
}
return null;
}
/**
* パッケージ名からプラグインのプロファイルを定義したXMLのリソースIDを取得します.
*
* @param context コンテキスト
* @param packageName パッケージ名
* @return リソースID
*/
public static int getPluginXmlResourceId(final Context context, final String packageName) {
ComponentInfo pluginComponent = getComponentInfo(context, packageName);
if (pluginComponent != null && pluginComponent.metaData != null) {
return pluginComponent.metaData.getInt(PLUGIN_META_DATA);
}
return -1;
}
/**
* 指定されたパッケージ名からコンポーネント情報を取得します.
*
* @param context コンテキスト
* @param packageName パッケージ名
* @return コンポーネント情報
*/
private static ComponentInfo getComponentInfo(final Context context, final String packageName) {
ComponentInfo compInfo = getServiceInfo(context, packageName);
if (compInfo != null) {
return compInfo;
}
return getReceiverInfo(context, packageName);
}
void setTargetProcessName(ComponentInfo stubInfo, ComponentInfo targetInfo) {
for (ProcessItem item : items.values()) {
if (TextUtils.equals(item.stubProcessName, stubInfo.processName)) {
if (!item.pkgs.contains(targetInfo.packageName)) {
item.pkgs.add(targetInfo.packageName);
}
item.targetProcessName = targetInfo.processName;
}
}
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
ResourceName(ComponentInfo cInfo, int _iconId) {
this(cInfo.applicationInfo.packageName, _iconId);
}
public static void preLoadApk(Context hostContext, ComponentInfo pluginInfo) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, NameNotFoundException, ClassNotFoundException {
if (pluginInfo != null || hostContext != null) {
if (pluginInfo == null || getPluginContext(pluginInfo.packageName) == null) {
boolean found = false;
synchronized (sPluginLoadedApkCache) {
Object object = ActivityThreadCompat.currentActivityThread();
if (object != null) {
Object containsKeyObj = MethodUtils.invokeMethod(FieldUtils.readField(object, "mPackages"), "containsKey", pluginInfo.packageName);
if ((containsKeyObj instanceof Boolean) && !((Boolean) containsKeyObj).booleanValue()) {
Object loadedApk;
if (VERSION.SDK_INT >= 11) {
loadedApk = MethodUtils.invokeMethod(object, "getPackageInfoNoCheck", pluginInfo.applicationInfo, CompatibilityInfoCompat.DEFAULT_COMPATIBILITY_INFO());
} else {
loadedApk = MethodUtils.invokeMethod(object, "getPackageInfoNoCheck", pluginInfo.applicationInfo);
}
sPluginLoadedApkCache.put(pluginInfo.packageName, loadedApk);
String optimizedDirectory = PluginDirHelper.getPluginDalvikCacheDir(hostContext, pluginInfo.packageName);
String libraryPath = PluginDirHelper.getPluginNativeLibraryDir(hostContext, pluginInfo.packageName);
String apk = pluginInfo.applicationInfo.publicSourceDir;
if (TextUtils.isEmpty(apk)) {
pluginInfo.applicationInfo.publicSourceDir = PluginDirHelper.getPluginFilePath(hostContext, pluginInfo.packageName);
apk = pluginInfo.applicationInfo.publicSourceDir;
}
if (apk != null) {
ClassLoader classloader = new PluginClassLoader(apk, optimizedDirectory, libraryPath, ClassLoader.getSystemClassLoader());
synchronized (loadedApk) {
FieldUtils.writeDeclaredField(loadedApk, "mClassLoader", classloader);
}
sPluginClassLoaderCache.put(pluginInfo.packageName, classloader);
Thread.currentThread().setContextClassLoader(classloader);
found = true;
}
ProcessCompat.setArgV0(pluginInfo.processName);
}
}
}
if (found) {
preMakeApplication(hostContext, pluginInfo);
}
}
}
}
public static ComponentName toComponentName(ComponentInfo componentInfo) {
return new ComponentName(componentInfo.packageName, componentInfo.name);
}
private boolean isStubComponent(ComponentInfo componentInfo) {
Bundle metaData = componentInfo.metaData;
return metaData != null
&& TextUtils.equals(metaData.getString("dodometa"), "dododola");
}
/**
* 指定されたコンポーネントからプラグインの情報を取得して DevicePlugin のインスタンスを作成します.
* <p>
* 既に同じコンポーネントのプラグインが存在する場合には上書きします。
* </p>
* @param pkgInfo パッケージ情報
* @param componentInfo コンポーネント情報
* @return DevicePlugin のインスタンス
*/
private DevicePlugin parsePlugin(final PackageInfo pkgInfo, final ComponentInfo componentInfo) {
PackageManager pkgMgr = mContext.getPackageManager();
Bundle metaData = componentInfo.metaData;
String pluginName = metaData.getString(PLUGIN_META_PLUGIN_NAME);
if (pluginName == null) {
pluginName = componentInfo.applicationInfo.loadLabel(pkgMgr).toString();
}
VersionName sdkVersionName = getPluginSDKVersion(componentInfo.applicationInfo);
String packageName = componentInfo.packageName;
String className = componentInfo.name;
String versionName = pkgInfo.versionName;
String hash = md5(packageName + className);
if (hash == null) {
throw new RuntimeException("Can't generate md5.");
}
Integer iconId = (Integer) metaData.get(PLUGIN_META_PLUGIN_ICON);
if (BuildConfig.DEBUG) {
mLogger.info("Added DevicePlugin: [" + hash + "]");
mLogger.info(" PackageName: " + packageName);
mLogger.info(" className: " + className);
mLogger.info(" versionName: " + versionName);
mLogger.info(" sdkVersionName: " + sdkVersionName);
}
// MEMO 既に同じ名前のデバイスプラグインが存在した場合の処理
// 現在は警告を表示し、上書きする.
if (mPlugins.containsKey(hash)) {
mLogger.warning("DevicePlugin[" + hash + "] already exists.");
}
ConnectionType type;
if (componentInfo instanceof ServiceInfo) {
if (isSamePackage(componentInfo)) {
type = ConnectionType.INTERNAL;
} else {
type = ConnectionType.BINDER;
}
} else {
type = ConnectionType.BROADCAST;
}
DevicePlugin.Builder plugin = new DevicePlugin.Builder(mContext)
.setPackageName(componentInfo.packageName)
.setClassName(componentInfo.name)
.setVersionName(versionName)
.setPluginId(hash)
.setDeviceName(pluginName)
.setPluginXml(DevicePluginXmlUtil.getXml(mContext, componentInfo))
.setPluginSdkVersionName(sdkVersionName)
.setPluginIconId(iconId)
.setConnectionType(type);
ProviderInfo[] providers = pkgInfo.providers;
if (providers != null) {
for (ProviderInfo provider : providers) {
if (provider.exported && provider.enabled) {
plugin.addProviderAuthority(provider.authority);
}
}
}
return plugin.build();
}