Merge changes Ie3648509,I53db73c3 into gingerbread
* changes: Move native library removal function to helper Initialize native library path in PackageSetting
This commit is contained in:
@@ -293,4 +293,34 @@ public class NativeLibraryHelper {
|
|||||||
inputStream.close();
|
inputStream.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the native binaries of a given package. This simply
|
||||||
|
// gets rid of the files in the 'lib' sub-directory.
|
||||||
|
public static void removeNativeBinariesLI(String nativeLibraryPath) {
|
||||||
|
if (DEBUG_NATIVE) {
|
||||||
|
Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Just remove any file in the directory. Since the directory is owned
|
||||||
|
* by the 'system' UID, the application is not supposed to have written
|
||||||
|
* anything there.
|
||||||
|
*/
|
||||||
|
File binaryDir = new File(nativeLibraryPath);
|
||||||
|
if (binaryDir.exists()) {
|
||||||
|
File[] binaries = binaryDir.listFiles();
|
||||||
|
if (binaries != null) {
|
||||||
|
for (int nn = 0; nn < binaries.length; nn++) {
|
||||||
|
if (DEBUG_NATIVE) {
|
||||||
|
Slog.d(TAG, " Deleting " + binaries[nn].getName());
|
||||||
|
}
|
||||||
|
if (!binaries[nn].delete()) {
|
||||||
|
Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Do not delete 'lib' directory itself, or this will prevent
|
||||||
|
// installation of future updates.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3026,7 +3026,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// Just create the setting, don't add it yet. For already existing packages
|
// Just create the setting, don't add it yet. For already existing packages
|
||||||
// the PkgSetting exists already and doesn't have to be created.
|
// the PkgSetting exists already and doesn't have to be created.
|
||||||
pkgSetting = mSettings.getPackageLP(pkg, origPackage, realName, suid, destCodeFile,
|
pkgSetting = mSettings.getPackageLP(pkg, origPackage, realName, suid, destCodeFile,
|
||||||
destResourceFile, pkg.applicationInfo.flags, true, false);
|
destResourceFile, pkg.applicationInfo.nativeLibraryDir,
|
||||||
|
pkg.applicationInfo.flags, true, false);
|
||||||
if (pkgSetting == null) {
|
if (pkgSetting == null) {
|
||||||
Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
|
Slog.w(TAG, "Creating application package " + pkg.packageName + " failed");
|
||||||
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||||
@@ -3244,14 +3245,21 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the data dir to the default "/data/data/<package name>/lib"
|
* Set the data dir to the default "/data/data/<package name>/lib"
|
||||||
* if we got here without anyone telling us different (e.g., apps
|
* if we got here without anyone telling us different (e.g., apps
|
||||||
* stored on SD card have their native libraries stored in the ASEC
|
* stored on SD card have their native libraries stored in the ASEC
|
||||||
* container with the APK).
|
* container with the APK).
|
||||||
|
*
|
||||||
|
* This happens during an upgrade from a package settings file that
|
||||||
|
* doesn't have a native library path attribute at all.
|
||||||
*/
|
*/
|
||||||
if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
|
if (pkgSetting.nativeLibraryPathString == null && pkg.applicationInfo.dataDir != null) {
|
||||||
pkg.applicationInfo.nativeLibraryDir = new File(dataPath, LIB_DIR_NAME).getPath();
|
final String nativeLibraryPath = new File(dataPath, LIB_DIR_NAME).getPath();
|
||||||
|
pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
|
||||||
|
pkgSetting.nativeLibraryPathString = nativeLibraryPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkgSetting.uidError = uidError;
|
pkgSetting.uidError = uidError;
|
||||||
@@ -3273,7 +3281,6 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
if ((!isSystemApp(pkg) || isUpdatedSystemApp(pkg)) && !isExternal(pkg)) {
|
if ((!isSystemApp(pkg) || isUpdatedSystemApp(pkg)) && !isExternal(pkg)) {
|
||||||
Log.i(TAG, path + " changed; unpacking");
|
Log.i(TAG, path + " changed; unpacking");
|
||||||
File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
|
File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
|
||||||
sharedLibraryDir.mkdir();
|
|
||||||
NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir);
|
NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir);
|
||||||
}
|
}
|
||||||
pkg.mScanPath = path;
|
pkg.mScanPath = path;
|
||||||
@@ -3591,40 +3598,6 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience call for removeNativeBinariesLI(File)
|
|
||||||
private void removeNativeBinariesLI(PackageParser.Package pkg) {
|
|
||||||
File nativeLibraryDir = getNativeBinaryDirForPackage(pkg);
|
|
||||||
removeNativeBinariesLI(nativeLibraryDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the native binaries of a given package. This simply
|
|
||||||
// gets rid of the files in the 'lib' sub-directory.
|
|
||||||
public void removeNativeBinariesLI(File binaryDir) {
|
|
||||||
if (DEBUG_NATIVE) {
|
|
||||||
Slog.w(TAG, "Deleting native binaries from: " + binaryDir.getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just remove any file in the directory. Since the directory
|
|
||||||
// is owned by the 'system' UID, the application is not supposed
|
|
||||||
// to have written anything there.
|
|
||||||
//
|
|
||||||
if (binaryDir.exists()) {
|
|
||||||
File[] binaries = binaryDir.listFiles();
|
|
||||||
if (binaries != null) {
|
|
||||||
for (int nn = 0; nn < binaries.length; nn++) {
|
|
||||||
if (DEBUG_NATIVE) {
|
|
||||||
Slog.d(TAG, " Deleting " + binaries[nn].getName());
|
|
||||||
}
|
|
||||||
if (!binaries[nn].delete()) {
|
|
||||||
Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Do not delete 'lib' directory itself, or this will prevent
|
|
||||||
// installation of future updates.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void removePackageLI(PackageParser.Package pkg, boolean chatty) {
|
void removePackageLI(PackageParser.Package pkg, boolean chatty) {
|
||||||
if (chatty && Config.LOGD) Log.d(
|
if (chatty && Config.LOGD) Log.d(
|
||||||
TAG, "Removing package " + pkg.applicationInfo.packageName );
|
TAG, "Removing package " + pkg.applicationInfo.packageName );
|
||||||
@@ -5128,7 +5101,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (libraryPath != null) {
|
if (libraryPath != null) {
|
||||||
removeNativeBinariesLI(new File(libraryPath));
|
NativeLibraryHelper.removeNativeBinariesLI(libraryPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6202,8 +6175,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
synchronized (mPackages) {
|
synchronized (mPackages) {
|
||||||
// Reinstate the old system package
|
// Reinstate the old system package
|
||||||
mSettings.enableSystemPackageLP(p.packageName);
|
mSettings.enableSystemPackageLP(p.packageName);
|
||||||
// Remove any native libraries. XXX needed?
|
// Remove any native libraries from the upgraded package.
|
||||||
removeNativeBinariesLI(p);
|
NativeLibraryHelper.removeNativeBinariesLI(p.applicationInfo.nativeLibraryDir);
|
||||||
}
|
}
|
||||||
// Install the system package
|
// Install the system package
|
||||||
PackageParser.Package newPkg = scanPackageLI(ps.codePath,
|
PackageParser.Package newPkg = scanPackageLI(ps.codePath,
|
||||||
@@ -7583,18 +7556,20 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
String installerPackageName;
|
String installerPackageName;
|
||||||
|
|
||||||
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
|
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
|
||||||
int pVersionCode, int pkgFlags) {
|
String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
|
||||||
super(pkgFlags);
|
super(pkgFlags);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.realName = realName;
|
this.realName = realName;
|
||||||
init(codePath, resourcePath, pVersionCode);
|
init(codePath, resourcePath, nativeLibraryPathString, pVersionCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(File codePath, File resourcePath, int pVersionCode) {
|
void init(File codePath, File resourcePath, String nativeLibraryPathString,
|
||||||
|
int pVersionCode) {
|
||||||
this.codePath = codePath;
|
this.codePath = codePath;
|
||||||
this.codePathString = codePath.toString();
|
this.codePathString = codePath.toString();
|
||||||
this.resourcePath = resourcePath;
|
this.resourcePath = resourcePath;
|
||||||
this.resourcePathString = resourcePath.toString();
|
this.resourcePathString = resourcePath.toString();
|
||||||
|
this.nativeLibraryPathString = nativeLibraryPathString;
|
||||||
this.versionCode = pVersionCode;
|
this.versionCode = pVersionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7687,8 +7662,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
SharedUserSetting sharedUser;
|
SharedUserSetting sharedUser;
|
||||||
|
|
||||||
PackageSetting(String name, String realName, File codePath, File resourcePath,
|
PackageSetting(String name, String realName, File codePath, File resourcePath,
|
||||||
int pVersionCode, int pkgFlags) {
|
String nativeLibraryPathString, int pVersionCode, int pkgFlags) {
|
||||||
super(name, realName, codePath, resourcePath, pVersionCode, pkgFlags);
|
super(name, realName, codePath, resourcePath, nativeLibraryPathString, pVersionCode,
|
||||||
|
pkgFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -7800,8 +7776,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
final int sharedId;
|
final int sharedId;
|
||||||
|
|
||||||
PendingPackage(String name, String realName, File codePath, File resourcePath,
|
PendingPackage(String name, String realName, File codePath, File resourcePath,
|
||||||
int sharedId, int pVersionCode, int pkgFlags) {
|
String nativeLibraryPathString, int sharedId, int pVersionCode, int pkgFlags) {
|
||||||
super(name, realName, codePath, resourcePath, pVersionCode, pkgFlags);
|
super(name, realName, codePath, resourcePath, nativeLibraryPathString,
|
||||||
|
pVersionCode, pkgFlags);
|
||||||
this.sharedId = sharedId;
|
this.sharedId = sharedId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7830,10 +7807,10 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
|
|
||||||
PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage,
|
PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage,
|
||||||
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
|
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
|
||||||
int pkgFlags, boolean create, boolean add) {
|
String nativeLibraryPathString, int pkgFlags, boolean create, boolean add) {
|
||||||
final String name = pkg.packageName;
|
final String name = pkg.packageName;
|
||||||
PackageSetting p = getPackageLP(name, origPackage, realName, sharedUser, codePath,
|
PackageSetting p = getPackageLP(name, origPackage, realName, sharedUser, codePath,
|
||||||
resourcePath, pkg.mVersionCode, pkgFlags, create, add);
|
resourcePath, nativeLibraryPathString, pkg.mVersionCode, pkgFlags, create, add);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7929,14 +7906,14 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
|
if((p.pkg != null) && (p.pkg.applicationInfo != null)) {
|
||||||
p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||||
}
|
}
|
||||||
PackageSetting ret = addPackageLP(name, p.realName, p.codePath,
|
PackageSetting ret = addPackageLP(name, p.realName, p.codePath, p.resourcePath,
|
||||||
p.resourcePath, p.userId, p.versionCode, p.pkgFlags);
|
p.nativeLibraryPathString, p.userId, p.versionCode, p.pkgFlags);
|
||||||
mDisabledSysPackages.remove(name);
|
mDisabledSysPackages.remove(name);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageSetting addPackageLP(String name, String realName, File codePath,
|
PackageSetting addPackageLP(String name, String realName, File codePath, File resourcePath,
|
||||||
File resourcePath, int uid, int vc, int pkgFlags) {
|
String nativeLibraryPathString, int uid, int vc, int pkgFlags) {
|
||||||
PackageSetting p = mPackages.get(name);
|
PackageSetting p = mPackages.get(name);
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
if (p.userId == uid) {
|
if (p.userId == uid) {
|
||||||
@@ -7946,7 +7923,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
"Adding duplicate package, keeping first: " + name);
|
"Adding duplicate package, keeping first: " + name);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
p = new PackageSetting(name, realName, codePath, resourcePath, vc, pkgFlags);
|
p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
|
||||||
|
vc, pkgFlags);
|
||||||
p.userId = uid;
|
p.userId = uid;
|
||||||
if (addUserIdLP(uid, p, name)) {
|
if (addUserIdLP(uid, p, name)) {
|
||||||
mPackages.put(name, p);
|
mPackages.put(name, p);
|
||||||
@@ -8001,7 +7979,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
|
|
||||||
private PackageSetting getPackageLP(String name, PackageSetting origPackage,
|
private PackageSetting getPackageLP(String name, PackageSetting origPackage,
|
||||||
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
|
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
|
||||||
int vc, int pkgFlags, boolean create, boolean add) {
|
String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) {
|
||||||
PackageSetting p = mPackages.get(name);
|
PackageSetting p = mPackages.get(name);
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
if (!p.codePath.equals(codePath)) {
|
if (!p.codePath.equals(codePath)) {
|
||||||
@@ -8044,8 +8022,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
}
|
}
|
||||||
if (origPackage != null) {
|
if (origPackage != null) {
|
||||||
// We are consuming the data from an existing package.
|
// We are consuming the data from an existing package.
|
||||||
p = new PackageSetting(origPackage.name, name, codePath,
|
p = new PackageSetting(origPackage.name, name, codePath, resourcePath,
|
||||||
resourcePath, vc, pkgFlags);
|
nativeLibraryPathString, vc, pkgFlags);
|
||||||
if (DEBUG_UPGRADE) Log.v(TAG, "Package " + name
|
if (DEBUG_UPGRADE) Log.v(TAG, "Package " + name
|
||||||
+ " is adopting original package " + origPackage.name);
|
+ " is adopting original package " + origPackage.name);
|
||||||
// Note that we will retain the new package's signature so
|
// Note that we will retain the new package's signature so
|
||||||
@@ -8061,7 +8039,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// Update new package state.
|
// Update new package state.
|
||||||
p.setTimeStamp(codePath.lastModified());
|
p.setTimeStamp(codePath.lastModified());
|
||||||
} else {
|
} else {
|
||||||
p = new PackageSetting(name, realName, codePath, resourcePath, vc, pkgFlags);
|
p = new PackageSetting(name, realName, codePath, resourcePath,
|
||||||
|
nativeLibraryPathString, vc, pkgFlags);
|
||||||
p.setTimeStamp(codePath.lastModified());
|
p.setTimeStamp(codePath.lastModified());
|
||||||
p.sharedUser = sharedUser;
|
p.sharedUser = sharedUser;
|
||||||
if (sharedUser != null) {
|
if (sharedUser != null) {
|
||||||
@@ -8782,8 +8761,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
Object idObj = getUserIdLP(pp.sharedId);
|
Object idObj = getUserIdLP(pp.sharedId);
|
||||||
if (idObj != null && idObj instanceof SharedUserSetting) {
|
if (idObj != null && idObj instanceof SharedUserSetting) {
|
||||||
PackageSetting p = getPackageLP(pp.name, null, pp.realName,
|
PackageSetting p = getPackageLP(pp.name, null, pp.realName,
|
||||||
(SharedUserSetting)idObj, pp.codePath, pp.resourcePath,
|
(SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
|
||||||
pp.versionCode, pp.pkgFlags, true, true);
|
pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags, true, true);
|
||||||
if (p == null) {
|
if (p == null) {
|
||||||
Slog.w(TAG, "Unable to create application package for "
|
Slog.w(TAG, "Unable to create application package for "
|
||||||
+ pp.name);
|
+ pp.name);
|
||||||
@@ -8888,6 +8867,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
String realName = parser.getAttributeValue(null, "realName");
|
String realName = parser.getAttributeValue(null, "realName");
|
||||||
String codePathStr = parser.getAttributeValue(null, "codePath");
|
String codePathStr = parser.getAttributeValue(null, "codePath");
|
||||||
String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
|
String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
|
||||||
|
String nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
|
||||||
if (resourcePathStr == null) {
|
if (resourcePathStr == null) {
|
||||||
resourcePathStr = codePathStr;
|
resourcePathStr = codePathStr;
|
||||||
}
|
}
|
||||||
@@ -8902,9 +8882,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
|
|
||||||
int pkgFlags = 0;
|
int pkgFlags = 0;
|
||||||
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
|
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
|
||||||
PackageSetting ps = new PackageSetting(name, realName,
|
PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
|
||||||
new File(codePathStr),
|
new File(resourcePathStr), nativeLibraryPathStr, versionCode, pkgFlags);
|
||||||
new File(resourcePathStr), versionCode, pkgFlags);
|
|
||||||
String timeStampStr = parser.getAttributeValue(null, "ts");
|
String timeStampStr = parser.getAttributeValue(null, "ts");
|
||||||
if (timeStampStr != null) {
|
if (timeStampStr != null) {
|
||||||
try {
|
try {
|
||||||
@@ -9023,9 +9002,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
"Error in package manager settings: <package> has no codePath at "
|
"Error in package manager settings: <package> has no codePath at "
|
||||||
+ parser.getPositionDescription());
|
+ parser.getPositionDescription());
|
||||||
} else if (userId > 0) {
|
} else if (userId > 0) {
|
||||||
packageSetting = addPackageLP(name.intern(), realName,
|
packageSetting = addPackageLP(name.intern(), realName, new File(codePathStr),
|
||||||
new File(codePathStr), new File(resourcePathStr),
|
new File(resourcePathStr), nativeLibraryPathStr, userId, versionCode,
|
||||||
userId, versionCode, pkgFlags);
|
pkgFlags);
|
||||||
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
|
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
|
||||||
+ ": userId=" + userId + " pkg=" + packageSetting);
|
+ ": userId=" + userId + " pkg=" + packageSetting);
|
||||||
if (packageSetting == null) {
|
if (packageSetting == null) {
|
||||||
@@ -9042,7 +9021,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
|||||||
if (userId > 0) {
|
if (userId > 0) {
|
||||||
packageSetting = new PendingPackage(name.intern(), realName,
|
packageSetting = new PendingPackage(name.intern(), realName,
|
||||||
new File(codePathStr), new File(resourcePathStr),
|
new File(codePathStr), new File(resourcePathStr),
|
||||||
userId, versionCode, pkgFlags);
|
nativeLibraryPathStr, userId, versionCode, pkgFlags);
|
||||||
packageSetting.setTimeStamp(timeStamp, timeStampStr);
|
packageSetting.setTimeStamp(timeStamp, timeStampStr);
|
||||||
mPendingPackages.add((PendingPackage) packageSetting);
|
mPendingPackages.add((PendingPackage) packageSetting);
|
||||||
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
|
if (DEBUG_SETTINGS) Log.i(TAG, "Reading package " + name
|
||||||
|
|||||||
Reference in New Issue
Block a user