Skip to content

Commit

Permalink
[Refactor] Use ProcFs to fetch CPU info
Browse files Browse the repository at this point in the history
  • Loading branch information
MuntashirAkon committed Jan 14, 2023
1 parent 43c0f9a commit b54e597
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

package io.github.muntashirakon.AppManager.misc;

import static io.github.muntashirakon.AppManager.utils.UIUtils.getStyledKeyValue;
import static io.github.muntashirakon.AppManager.utils.UIUtils.getTitleText;

import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
Expand All @@ -28,7 +31,6 @@

import com.android.internal.util.TextUtils;

import java.io.BufferedReader;
import java.security.Provider;
import java.security.Security;
import java.text.ParseException;
Expand All @@ -46,14 +48,9 @@
import io.github.muntashirakon.AppManager.users.UserInfo;
import io.github.muntashirakon.AppManager.users.Users;
import io.github.muntashirakon.AppManager.utils.Utils;
import io.github.muntashirakon.io.Path;
import io.github.muntashirakon.io.PathReader;
import io.github.muntashirakon.io.Paths;
import io.github.muntashirakon.proc.ProcFs;
import io.github.muntashirakon.util.LocalizedString;

import static io.github.muntashirakon.AppManager.utils.UIUtils.getStyledKeyValue;
import static io.github.muntashirakon.AppManager.utils.UIUtils.getTitleText;

public class DeviceInfo2 implements LocalizedString {
public final String osVersion = Build.VERSION.RELEASE;
public final String bootloader = Build.BOOTLOADER;
Expand Down Expand Up @@ -364,21 +361,7 @@ private String getEncryptionStatus() {

@Nullable
private String getCpuHardware() {
Path cpuInfoPath = Paths.getUnprivileged("/proc/cpuinfo");
try (BufferedReader reader = new BufferedReader(new PathReader(cpuInfoPath))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.trim().startsWith("Hardware")) {
int colonLoc = line.indexOf(':');
if (colonLoc == -1) continue;
colonLoc += 2;
return line.substring(colonLoc).trim();
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
return ProcFs.getInstance().getCpuInfoHardware();
}

@SuppressLint("PrivateApi")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

package io.github.muntashirakon.AppManager.utils;

import static android.system.OsConstants.O_ACCMODE;
import static android.system.OsConstants.O_APPEND;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_RDWR;
import static android.system.OsConstants.O_TRUNC;
import static android.system.OsConstants.O_WRONLY;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.os.Environment;
Expand Down Expand Up @@ -213,4 +220,24 @@ public static boolean canRead(@NonNull File file) {
}
return false;
}

public static String translateModePosixToString(int mode) {
String res = "";
if ((mode & O_ACCMODE) == O_RDWR) {
res = "rw";
} else if ((mode & O_ACCMODE) == O_WRONLY) {
res = "w";
} else if ((mode & O_ACCMODE) == O_RDONLY) {
res = "r";
} else {
throw new IllegalArgumentException("Bad mode: " + mode);
}
if ((mode & O_TRUNC) == O_TRUNC) {
res += "t";
}
if ((mode & O_APPEND) == O_APPEND) {
res += "a";
}
return res;
}
}
85 changes: 85 additions & 0 deletions app/src/main/java/io/github/muntashirakon/proc/ProcFdInfoList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-3.0-or-later

package io.github.muntashirakon.proc;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import io.github.muntashirakon.AppManager.utils.FileUtils;
import io.github.muntashirakon.io.Path;

public class ProcFdInfoList {
public static class ProcFdInfo {
public final int id;
public final long offset;
public final int mode;
public final int mountId;
@NonNull
public final Path realPath;
@NonNull
public final String[] extras;

private ProcFdInfo(int id, @NonNull Path realPath, @NonNull String[] info) {
this.id = id;
this.realPath = realPath;
this.extras = new String[info.length - 3]; // Ignore three mandatory fields
int i = 0;
long offset = -1;
int mode = -1;
int mountId = -1;
for (String line : info) {
if (line.startsWith("pos:")) {
offset = Long.decode(line.substring(4).trim());
} else if (line.startsWith("flags:")) {
mode = Integer.decode(line.substring(6).trim());
} else if (line.startsWith("mnt_id:")) {
mountId = Integer.decode(line.substring(7).trim());
} else {
extras[i++] = line;
}
}
assert offset != -1;
assert mode != -1;
assert mountId != -1;

this.offset = offset;
this.mode = mode;
this.mountId = mountId;
}

public String getModeString() {
return FileUtils.translateModePosixToString(mode);
}
}

private final Map<Integer, ProcFdInfo> mFdInfoMap;

ProcFdInfoList(@NonNull Path[] fdFiles, @NonNull String[] fdInfoList) {
assert fdFiles.length == fdInfoList.length;
mFdInfoMap = new HashMap<>(fdFiles.length);
for (int i = 0; i < fdFiles.length; ++i) {
String fdInfo = fdInfoList[i];
if (fdInfo == null) {
// FD no longer exists
continue;
}
Path fdFile = fdFiles[i];
int fd = Integer.decode(fdFile.getName());
ProcFdInfo procFdInfo = new ProcFdInfo(fd, fdFile, fdInfo.split("\\n"));
mFdInfoMap.put(fd, procFdInfo);
}
}

public Collection<Integer> getFds() {
return mFdInfoMap.keySet();
}

@Nullable
public ProcFdInfo getFdInfo(int fd) {
return mFdInfoMap.get(fd);
}
}
92 changes: 92 additions & 0 deletions app/src/main/java/io/github/muntashirakon/proc/ProcFs.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@

import com.android.internal.util.TextUtils;

import java.io.BufferedReader;
import java.io.IOException;

import io.github.muntashirakon.io.Path;
import io.github.muntashirakon.io.PathReader;
import io.github.muntashirakon.io.Paths;

public class ProcFs {
Expand Down Expand Up @@ -90,6 +94,30 @@ public ProcFs(Path procRoot) {
this.procRoot = procRoot;
}

@Nullable
public String getCpuInfoHardware() {
// Only hardware is the relevant output, other outputs can be parsed from
// /sys/devices/system/cpu/
Path cpuInfoPath = Paths.build(procRoot, CPU_INFO);
if (cpuInfoPath == null) {
return null;
}
try (BufferedReader reader = new BufferedReader(new PathReader(cpuInfoPath))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.trim().startsWith("Hardware")) {
int colonLoc = line.indexOf(':');
if (colonLoc == -1) continue;
colonLoc += 2;
return line.substring(colonLoc).trim();
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}

public ProcMemoryInfo getMemoryInfo() {
String statFileContents = getStringOrNull(Paths.build(procRoot, MEM_INFO));
if (statFileContents == null) {
Expand Down Expand Up @@ -124,6 +152,58 @@ public String getCmdline(int pid) {
return getStringOrNull(Paths.build(procRoot, String.valueOf(pid), CMDLINE));
}

@Nullable
public String getCwd(int pid) {
Path cwdPath = Paths.build(procRoot, String.valueOf(pid), CWD);
if (cwdPath != null) {
try {
return cwdPath.getRealFilePath();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}

public String[] getEnvVars(int pid) {
String data = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), ENVIRON));
return data != null ? data.split("\0") : null;
}

@Nullable
public String getExe(int pid) {
Path exePath = Paths.build(procRoot, String.valueOf(pid), EXE);
if (exePath != null) {
try {
return exePath.getRealFilePath();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}

public ProcFdInfoList getFdInfo(int pid) {
Path fdDir = Paths.build(procRoot, String.valueOf(pid), FD);
Path fdInfoDir = Paths.build(procRoot, String.valueOf(pid), FD_INFO);
if (fdDir == null || fdInfoDir == null) {
return null;
}
Path[] fdList = fdDir.listFiles();
String[] fdInfoList = new String[fdList.length];
for (int i = 0; i < fdList.length; ++i) {
Path fdInfoFile = Paths.build(fdInfoDir, fdList[i].getName());
fdInfoList[i] = fdInfoFile != null ? fdInfoFile.getContentAsString(null) : null;
}
return new ProcFdInfoList(fdList, fdInfoList);
}

@Nullable
public ProcMappedFiles getMapFiles(int pid) {
Path mapFilesDir = Paths.build(procRoot, String.valueOf(pid), MAP_FILES);
return mapFilesDir != null ? new ProcMappedFiles(mapFilesDir.listFiles()) : null;
}

@Nullable
public ProcStat getStat(int pid) {
String statFileContents = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), STAT));
Expand All @@ -142,6 +222,18 @@ public ProcMemStat getMemStat(int pid) {
return ProcMemStat.parse(statFileContents);
}

@Nullable
public String getRoot(int pid) {
Path rootPath = Paths.build(procRoot, String.valueOf(pid), ROOT);
if (rootPath != null) {
try {
return rootPath.getRealFilePath();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Nullable
public ProcStatus getStatus(int pid) {
String statFileContents = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), STATUS));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-3.0-or-later

package io.github.muntashirakon.proc;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import io.github.muntashirakon.io.Path;
import kotlin.collections.ArrayDeque;

public class ProcMappedFiles {
public static class MappedFile {
public final Path memoryPath;
public final String realPath;
public final long vmStart;
public final long vmEnd;

private MappedFile(@NonNull Path memoryPath, @NonNull String realPath) {
this.memoryPath = memoryPath;
this.realPath = realPath;
String[] vmAreaStruct = memoryPath.getName().split("-");
vmStart = Long.decode("0x" + vmAreaStruct[0]);
vmEnd = Long.decode("0x" + vmAreaStruct[1]);
}
}

private final Map<String, List<MappedFile>> mMappedFiles;

ProcMappedFiles(@NonNull Path[] mappedFiles) {
mMappedFiles = new HashMap<>(mappedFiles.length);
for (Path file : mappedFiles) {
try {
String realPath = Objects.requireNonNull(file.getRealFilePath());
MappedFile mappedFile = new MappedFile(file, realPath);
List<MappedFile> mappedFileList = mMappedFiles.get(realPath);
if (mappedFileList == null) {
mappedFileList = new ArrayDeque<>();
mMappedFiles.put(realPath, mappedFileList);
}
mappedFileList.add(mappedFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}

@NonNull
public Collection<String> getRealFiles() {
return mMappedFiles.keySet();
}

@Nullable
public List<MappedFile> getMappedFiles(@NonNull String realPath) {
return mMappedFiles.get(realPath);
}
}

0 comments on commit b54e597

Please sign in to comment.