Merge "Don't remove mainline modules if they declare support in manifest meta-data" into sc-dev am: 19e03e843b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13954467 Change-Id: I4601f2879bc148637ad6cef1ba9f0cea59ce506d
This commit is contained in:
@@ -19,17 +19,26 @@ package com.android.server.devicepolicy;
|
|||||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
|
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
|
||||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
|
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
|
||||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
|
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
|
||||||
|
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_DEVICE;
|
||||||
|
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_PROFILE;
|
||||||
|
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_USER;
|
||||||
|
import static android.content.pm.PackageManager.GET_META_DATA;
|
||||||
|
|
||||||
|
import static com.android.internal.util.Preconditions.checkArgument;
|
||||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||||
import static com.android.server.devicepolicy.DevicePolicyManagerService.dumpResources;
|
import static com.android.server.devicepolicy.DevicePolicyManagerService.dumpResources;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.app.admin.DeviceAdminReceiver;
|
import android.app.admin.DeviceAdminReceiver;
|
||||||
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
@@ -39,9 +48,13 @@ import android.view.inputmethod.InputMethodInfo;
|
|||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.server.inputmethod.InputMethodManagerInternal;
|
import com.android.server.inputmethod.InputMethodManagerInternal;
|
||||||
|
import com.android.server.pm.ApexManager;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,6 +64,18 @@ import java.util.Set;
|
|||||||
public class OverlayPackagesProvider {
|
public class OverlayPackagesProvider {
|
||||||
|
|
||||||
protected static final String TAG = "OverlayPackagesProvider";
|
protected static final String TAG = "OverlayPackagesProvider";
|
||||||
|
private static final Map<String, String> sActionToMetadataKeyMap = new HashMap<>();
|
||||||
|
{
|
||||||
|
sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_USER, REQUIRED_APP_MANAGED_USER);
|
||||||
|
sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_PROFILE, REQUIRED_APP_MANAGED_PROFILE);
|
||||||
|
sActionToMetadataKeyMap.put(ACTION_PROVISION_MANAGED_DEVICE, REQUIRED_APP_MANAGED_DEVICE);
|
||||||
|
}
|
||||||
|
private static final Set<String> sAllowedActions = new HashSet<>();
|
||||||
|
{
|
||||||
|
sAllowedActions.add(ACTION_PROVISION_MANAGED_USER);
|
||||||
|
sAllowedActions.add(ACTION_PROVISION_MANAGED_PROFILE);
|
||||||
|
sAllowedActions.add(ACTION_PROVISION_MANAGED_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
private final PackageManager mPm;
|
private final PackageManager mPm;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
@@ -64,6 +89,8 @@ public class OverlayPackagesProvider {
|
|||||||
interface Injector {
|
interface Injector {
|
||||||
@NonNull
|
@NonNull
|
||||||
List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
|
List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
|
||||||
|
|
||||||
|
String getActiveApexPackageNameContainingPackage(String packageName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class DefaultInjector implements Injector {
|
private static final class DefaultInjector implements Injector {
|
||||||
@@ -72,6 +99,11 @@ public class OverlayPackagesProvider {
|
|||||||
public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
|
public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
|
||||||
return InputMethodManagerInternal.get().getInputMethodListAsUser(userId);
|
return InputMethodManagerInternal.get().getInputMethodListAsUser(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getActiveApexPackageNameContainingPackage(String packageName) {
|
||||||
|
return ApexManager.getInstance().getActiveApexPackageNameContainingPackage(packageName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -83,7 +115,8 @@ public class OverlayPackagesProvider {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes non-required apps. All the system apps with a launcher that are not in
|
* Computes non-required apps. All the system apps with a launcher that are not in
|
||||||
* the required set of packages will be considered as non-required apps.
|
* the required set of packages, and all mainline modules that are not declared as required
|
||||||
|
* via metadata in their manifests, will be considered as non-required apps.
|
||||||
*
|
*
|
||||||
* Note: If an app is mistakenly listed as both required and disallowed, it will be treated as
|
* Note: If an app is mistakenly listed as both required and disallowed, it will be treated as
|
||||||
* disallowed.
|
* disallowed.
|
||||||
@@ -99,15 +132,76 @@ public class OverlayPackagesProvider {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public Set<String> getNonRequiredApps(@NonNull ComponentName admin, int userId,
|
public Set<String> getNonRequiredApps(@NonNull ComponentName admin, int userId,
|
||||||
@NonNull String provisioningAction) {
|
@NonNull String provisioningAction) {
|
||||||
|
requireNonNull(admin);
|
||||||
|
checkArgument(sAllowedActions.contains(provisioningAction));
|
||||||
final Set<String> nonRequiredApps = getLaunchableApps(userId);
|
final Set<String> nonRequiredApps = getLaunchableApps(userId);
|
||||||
// Newly installed system apps are uninstalled when they are not required and are either
|
// Newly installed system apps are uninstalled when they are not required and are either
|
||||||
// disallowed or have a launcher icon.
|
// disallowed or have a launcher icon.
|
||||||
nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
|
nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
|
||||||
nonRequiredApps.removeAll(getSystemInputMethods(userId));
|
nonRequiredApps.removeAll(getSystemInputMethods(userId));
|
||||||
nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
|
nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
|
||||||
|
nonRequiredApps.removeAll(
|
||||||
|
getRequiredAppsMainlineModules(nonRequiredApps, provisioningAction));
|
||||||
return nonRequiredApps;
|
return nonRequiredApps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a subset of {@code packageNames} whose packages are mainline modules declared as
|
||||||
|
* required apps via their app metadata.
|
||||||
|
* @see DevicePolicyManager#REQUIRED_APP_MANAGED_USER
|
||||||
|
* @see DevicePolicyManager#REQUIRED_APP_MANAGED_DEVICE
|
||||||
|
* @see DevicePolicyManager#REQUIRED_APP_MANAGED_PROFILE
|
||||||
|
*/
|
||||||
|
private Set<String> getRequiredAppsMainlineModules(
|
||||||
|
Set<String> packageNames,
|
||||||
|
String provisioningAction) {
|
||||||
|
final Set<String> result = new HashSet<>();
|
||||||
|
for (String packageName : packageNames) {
|
||||||
|
if (!isMainlineModule(packageName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isRequiredAppDeclaredInMetadata(packageName, provisioningAction)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.add(packageName);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRequiredAppDeclaredInMetadata(String packageName, String provisioningAction) {
|
||||||
|
PackageInfo packageInfo;
|
||||||
|
try {
|
||||||
|
packageInfo = mPm.getPackageInfo(packageName, GET_META_DATA);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final String metadataKey = sActionToMetadataKeyMap.get(provisioningAction);
|
||||||
|
return packageInfo.applicationInfo.metaData.getBoolean(metadataKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if the provided package name is a mainline module.
|
||||||
|
* <p>There are 2 types of mainline modules: a regular mainline module and apk-in-apex module.
|
||||||
|
*/
|
||||||
|
private boolean isMainlineModule(String packageName) {
|
||||||
|
return isRegularMainlineModule(packageName) || isApkInApexMainlineModule(packageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRegularMainlineModule(String packageName) {
|
||||||
|
try {
|
||||||
|
mPm.getModuleInfo(packageName, /* flags= */ 0);
|
||||||
|
return true;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isApkInApexMainlineModule(String packageName) {
|
||||||
|
final String apexPackageName =
|
||||||
|
mInjector.getActiveApexPackageNameContainingPackage(packageName);
|
||||||
|
return apexPackageName != null;
|
||||||
|
}
|
||||||
|
|
||||||
private Set<String> getLaunchableApps(int userId) {
|
private Set<String> getLaunchableApps(int userId) {
|
||||||
final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
|
final Intent launcherIntent = new Intent(Intent.ACTION_MAIN);
|
||||||
launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ package com.android.server.devicepolicy;
|
|||||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
|
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
|
||||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
|
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
|
||||||
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
|
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
|
||||||
|
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_DEVICE;
|
||||||
|
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_PROFILE;
|
||||||
|
import static android.app.admin.DevicePolicyManager.REQUIRED_APP_MANAGED_USER;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.common.truth.Truth.assertWithMessage;
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
@@ -31,13 +34,17 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.ModuleInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.test.mock.MockPackageManager;
|
import android.test.mock.MockPackageManager;
|
||||||
import android.view.inputmethod.InputMethodInfo;
|
import android.view.inputmethod.InputMethodInfo;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
@@ -51,8 +58,10 @@ import org.mockito.MockitoAnnotations;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,6 +85,8 @@ public class OverlayPackagesProviderTest {
|
|||||||
|
|
||||||
private FakePackageManager mPackageManager;
|
private FakePackageManager mPackageManager;
|
||||||
private String[] mSystemAppsWithLauncher;
|
private String[] mSystemAppsWithLauncher;
|
||||||
|
private Set<String> mRegularMainlineModules = new HashSet<>();
|
||||||
|
private Map<String, String> mMainlineModuleToDeclaredMetadataMap = new HashMap<>();
|
||||||
private OverlayPackagesProvider mHelper;
|
private OverlayPackagesProvider mHelper;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -168,7 +179,7 @@ public class OverlayPackagesProviderTest {
|
|||||||
setSystemAppsWithLauncher("app.a", "app.b");
|
setSystemAppsWithLauncher("app.a", "app.b");
|
||||||
setSystemInputMethods("app.a");
|
setSystemInputMethods("app.a");
|
||||||
|
|
||||||
verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.a", "app.b");
|
verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.b");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -257,6 +268,93 @@ public class OverlayPackagesProviderTest {
|
|||||||
R.array.vendor_disallowed_apps_managed_profile);
|
R.array.vendor_disallowed_apps_managed_profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNonRequiredApps_mainlineModules_managedProfile_works() {
|
||||||
|
setupApexModulesWithManagedProfile("package1");
|
||||||
|
setupRegularModulesWithManagedProfile("package2");
|
||||||
|
setSystemAppsWithLauncher("package1", "package2", "package3");
|
||||||
|
|
||||||
|
verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "package3");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNonRequiredApps_mainlineModules_managedDevice_works() {
|
||||||
|
setupApexModulesWithManagedDevice("package1");
|
||||||
|
setupRegularModulesWithManagedDevice("package2");
|
||||||
|
setSystemAppsWithLauncher("package1", "package2", "package3");
|
||||||
|
|
||||||
|
verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_DEVICE, "package3");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNonRequiredApps_mainlineModules_managedUser_works() {
|
||||||
|
setupApexModulesWithManagedUser("package1");
|
||||||
|
setupRegularModulesWithManagedUser("package2");
|
||||||
|
setSystemAppsWithLauncher("package1", "package2", "package3");
|
||||||
|
|
||||||
|
verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_USER, "package3");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNonRequiredApps_mainlineModules_noMetadata_works() {
|
||||||
|
setupApexModulesWithNoMetadata("package1");
|
||||||
|
setupRegularModulesWithNoMetadata("package2");
|
||||||
|
setSystemAppsWithLauncher("package1", "package2", "package3");
|
||||||
|
|
||||||
|
verifyAppsAreNonRequired(
|
||||||
|
ACTION_PROVISION_MANAGED_PROFILE, "package1", "package2", "package3");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRegularModulesWithManagedUser(String... regularModules) {
|
||||||
|
setupRegularModulesWithMetadata(regularModules, REQUIRED_APP_MANAGED_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRegularModulesWithManagedDevice(String... regularModules) {
|
||||||
|
setupRegularModulesWithMetadata(regularModules, REQUIRED_APP_MANAGED_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRegularModulesWithManagedProfile(String... regularModules) {
|
||||||
|
setupRegularModulesWithMetadata(regularModules, REQUIRED_APP_MANAGED_PROFILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRegularModulesWithNoMetadata(String... regularModules) {
|
||||||
|
mRegularMainlineModules.addAll(Arrays.asList(regularModules));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupRegularModulesWithMetadata(String[] regularModules, String metadataKey) {
|
||||||
|
for (String regularModule : regularModules) {
|
||||||
|
mRegularMainlineModules.add(regularModule);
|
||||||
|
mMainlineModuleToDeclaredMetadataMap.put(regularModule, metadataKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupApexModulesWithManagedUser(String... apexPackageNames) {
|
||||||
|
setupApexModulesWithMetadata(apexPackageNames, REQUIRED_APP_MANAGED_USER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupApexModulesWithManagedDevice(String... apexPackageNames) {
|
||||||
|
setupApexModulesWithMetadata(apexPackageNames, REQUIRED_APP_MANAGED_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupApexModulesWithManagedProfile(String... apexPackageNames) {
|
||||||
|
setupApexModulesWithMetadata(apexPackageNames, REQUIRED_APP_MANAGED_PROFILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupApexModulesWithNoMetadata(String... apexPackageNames) {
|
||||||
|
for (String apexPackageName : apexPackageNames) {
|
||||||
|
when(mInjector.getActiveApexPackageNameContainingPackage(eq(apexPackageName)))
|
||||||
|
.thenReturn("apex");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupApexModulesWithMetadata(String[] apexPackageNames, String metadataKey) {
|
||||||
|
for (String apexPackageName : apexPackageNames) {
|
||||||
|
when(mInjector.getActiveApexPackageNameContainingPackage(eq(apexPackageName)))
|
||||||
|
.thenReturn("apex");
|
||||||
|
mMainlineModuleToDeclaredMetadataMap.put(apexPackageName, metadataKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ArrayList<String> getStringArrayInRealResources(int id) {
|
private ArrayList<String> getStringArrayInRealResources(int id) {
|
||||||
return new ArrayList<>(Arrays.asList(mRealResources.getStringArray(id)));
|
return new ArrayList<>(Arrays.asList(mRealResources.getStringArray(id)));
|
||||||
}
|
}
|
||||||
@@ -383,5 +481,29 @@ public class OverlayPackagesProviderTest {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public PackageInfo getPackageInfo(String packageName, int flags) {
|
||||||
|
final PackageInfo packageInfo = new PackageInfo();
|
||||||
|
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||||
|
applicationInfo.metaData = new Bundle();
|
||||||
|
if (mMainlineModuleToDeclaredMetadataMap.containsKey(packageName)) {
|
||||||
|
applicationInfo.metaData.putBoolean(
|
||||||
|
mMainlineModuleToDeclaredMetadataMap.get(packageName), true);
|
||||||
|
}
|
||||||
|
packageInfo.applicationInfo = applicationInfo;
|
||||||
|
return packageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ModuleInfo getModuleInfo(@NonNull String packageName, int flags)
|
||||||
|
throws NameNotFoundException {
|
||||||
|
if (!mRegularMainlineModules.contains(packageName)) {
|
||||||
|
throw new NameNotFoundException("package does not exist");
|
||||||
|
}
|
||||||
|
return new ModuleInfo().setName(packageName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user