Android Clear data vs. Clear cache
What is the difference?
Android application 정보를 살펴보면 Clear data와 Clear cache 두 가지 Clear option이 존재한다.
두 가지가 무슨 차이가 있는지 상세히 알아보면 다음과 같다.
(Android 4.4.2 기준)
예상할 수 있는 공통점
- Package 관리 측면에서 사용된다.
- 특정한 위치의 디렉토리 및 파일을 삭제한다.
- 삭제를 위해 적절한 권한을 획득한다.
- 삭제 후에는 저장 공간 정보를 갱신해야 한다.
Package 관리 측면에서 사용되므로 Application package를 관리하는 PackageManager 부터 시작하면 될 것으로 판단한다.
/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java 파일을 보면 아래 두 가지 함수가 존재한다.
- clearApplicationUserData
- deleteApplicationCacheFiles
두 함수 모두 비슷한 동작을 수행하게 된다.
- clearApplicationUserData
- clearApplicationUserDataLI 함수 수행
- clearExternalStorageDataSync 함수 수행
- deleteApplicationCacheFiles
- deleteApplicationCacheFilesLI 함수 수행
- clearExternalStorageDataSync 함수 수행
먼저 서로 다른 함수를 사용하는 부분을 살펴보자.
clearApplicationUserDataLI와 deleteApplicationCacheFilesLI 함수는 둘 다 /frameworks/base/services/java/com/android/server/pm/Installer.java 경로의 com.android.server.pm.Installer class를 사용한다.
- Data의 경우 clearUserData
- Cache의 경우 deleteCacheFiles
Installer.clearUserData(packageName, userId) 함수 정의
public int clearUserData(String name, int userId) {
StringBuilder builder = new StringBuilder("rmuserdata");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return execute(builder.toString());
}
Installer.deleteCacheFiles(packageName, userId) 함수 정의
public int deleteCacheFiles(String name, int userId) {
StringBuilder builder = new StringBuilder("rmcache");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return execute(builder.toString());
}
차이가 있는 부분은 rmuserdata, rmcache 밖에 없다.
각각 만들어 지는 명령어는 아래와 같다.
rmuserdata <packageName> <userId>
rmcache <packageName> <userId>
Linux based system이므로 각각의 명령어를 userId 권한으로 실행한다고 생각할 수 있다. 그렇다면 그 명령어는 어떻게 수행되는지 execute 함수를 따라가 봄으로써 알 수 있다.
execute함수는 transaction 함수를 거쳐 writeCommand를 통해 연결된 OutputStream에 단순히 쓰는 역할을 하게 된다.
그렇다면, Stream이 어느 곳에 연결되어 있는지 확인해 보기만 하면 된다.
Installer에서 쉽게 찾을 수 있는데,
LocalSocketAddress address = new LocalSocketAddress("installd",
LocalSocketAddress.Namespace.RESERVED);
/frameworks/base/core/java/android/net/LocalSocketAddress.java 에서 LocalSocketAddress.Namespace.RESERVED의 경우 아래와 같은 주석이 붙어 있다.
/**
* A socket in the Android reserved namespace in /dev/socket.
* Only the init process may create a socket here.
*/
RESERVED(1),
init process를 봐야 할 순서가 되었다.
init process는 /system/core/rootdir/init.rc 경로의 설정 파일에 따라 Service를 spawn하며 installId의 경우 아래와 같이 정의되어 있다.
service installd /system/bin/installd class main socket installd stream 600 system system
init.rc 문법을 떠올려 보면 Service의 경우
service <name> <pathname> [<argument>] 형태이므로,
installId의 경우 /system/bin/InstallId를 사용한다는 것을 알 수 있다. 또한, Stream을 사용할 수 있으며 권한은 600, system group의 system user가 사용할 수 있다.
위 service 정보를 토대로 transaction 함수는 system service 중 installId의 Stream과 연결되어 있다는 것을 알 수 있다.
해당 Service 구현부는 /frameworks/native/cmds/installd/installd.c 파일에 있다.
Data의 경우
static int do_rm_user_data(char **arg, char reply[REPLY_MAX])
{
return delete_user_data(arg[0], atoi(arg[1])); /* pkgname, userid */
}
Cache의 경우
static int do_rm_cache(char **arg, char reply[REPLY_MAX])
{
return delete_cache(arg[0], atoi(arg[1])); /* pkgname, userid */
}
형태로 정의되어 있다.
delete_user_data, delete_cache 함수는 /frameworks/native/cmds/installd/commands.c 파일에 정의되어 있다.
delete_user_data
int delete_user_data(const char *pkgname, userid_t userid)
{
char pkgdir[PKG_PATH_MAX];if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
return -1;/* delete contents, excluding "lib", but not the directory itself */
return delete_dir_contents(pkgdir, 0, "lib");
}
delete_cache
int delete_cache(const char *pkgname, userid_t userid)
{
char cachedir[PKG_PATH_MAX];if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, userid))
return -1;/* delete contents, not the directory, no exceptions */
return delete_dir_contents(cachedir, 0, 0);
}
create_pkg_path 함수는 아래 경로에 있으며,
/frameworks/native/cmds/installd/utils.c
적절히 인자를 조합하여 pkg path를 만들어 낸다.
int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
const char *postfix, userid_t userid);
간단히 보면 pkgName과 postfix, userid를 조합하는 것이다. 함수 내부를 보면
- delete_user_data
userId가 0인 경우, 즉 system이 호출한 경우 PRIMARY_USER_PREFIX인 /data와 android_data_dir.path 인 data, 그리고 pkgname을 붙여 경로를 만들게 된다. /data/data/<pkgname> 경로를 얻을 수 있다. (일반적으로 해당 경로에는 안에는 cache, databases, shared_prefs 등 application에서 사용하는 디렉토리가 있으며 앱에서 사용하기 나름이다.)
- delete_cache
userId가 0이 아닌 경우, CACHE_DIR_POSTFIX는 “/cache” 로 정의되어 있으므로 /data/user/<pkgname>/cache가 된다.
경로를 얻은 후 똑같은 delete_dir_contents 함수를 수행한다.
- delete_user_data
delete_dir_contents(pkgdir, 0, “lib”) 이므로, 만들어진 pkgdir 하위 디렉토리 중 lib을 제외하고 모든 하위 디렉토리와 파일을 삭제한다.
- delete_cache
delete_dir_contents(cachedir, 0, 0); 이므로 만들어진 cachedir 하위 디렉토리와 파일을 삭제한다.
이제 두 함수의 차이가 있는 부분은 정리되었고, 둘 다 clearExternalStorageDataSync 함수를 수행하게 된다.
해당 함수는 private void clearExternalStorageDataSync(String packageName, int userId, boolean allData); 형태를 가지며 실제 무언가를 삭제하는 부분은 다음과 같다.
final UserEnvironment userEnv = new UserEnvironment(curUser);
clearDirectory(conn.mContainerService,
userEnv.buildExternalStorageAppCacheDirs(packageName));
if (allData) {
clearDirectory(conn.mContainerService,
userEnv.buildExternalStorageAppDataDirs(packageName));
clearDirectory(conn.mContainerService,
userEnv.buildExternalStorageAppMediaDirs(packageName));
}
- Data의 경우 : clearExternalStorageDataSync(packageName, userId, true);
- Cache의 경우 : clearExternalStorageDataSync(packageName, userId, false); 형태로 allData 인자가 다르다.
Data의 경우 삭제하는 경로
1. buildExternalStorageAppCacheDirs : /<ExternalDirsForApp>/Android/data/<packageName>/cache
2. buildExternalStorageAppDataDirs : /<ExternalDirsForApp>/Android/data/<packageName>/
3. buildExternalStorageAppMediaDirs : /<ExternalDirsForApp>/Android/media/<packageName>/
Cache의 경우 삭제하는 경로 (이 경우 allData 가 false이므로, buildExternalStorageAppDataDirs, buildExternalStorageAppMediaDirs는 수행되지 않는다.)
1. buildExternalStorageAppCacheDirs : /<ExternalDirsForApp>/Android/data/<packageName>/cache
결론은 다음과 같다.
Clear data가 삭제하는 경로
- /data/data/<pkgname>
- /<ExternalDirsForApp>/Android/data/<packageName>/cache
- /<ExternalDirsForApp>/Android/data/<packageName>/
- /<ExternalDirsForApp>/Android/media/<packageName>/
Clear cache가 삭제하는 경로
- /data/user/<pkgname>/cache
- /<ExternalDirsForApp>/Android/data/<packageName>/cache