/* * Copyright 2010 Kevin Gaudin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.acra.collector; import android.os.Build; import android.os.Environment; import android.os.StatFs; import android.support.annotation.NonNull; import org.acra.ACRA; import org.acra.ACRAConstants; import org.acra.ReportField; import org.acra.builder.ReportBuilder; import org.acra.model.Element; import org.acra.model.NumberElement; import org.acra.model.StringElement; import org.acra.util.IOUtils; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; import static org.acra.ACRA.LOG_TAG; /** * Collects results of the <code>dumpsys</code> command. * * @author Kevin Gaudin & F43nd1r */ final class MemoryInfoCollector extends Collector { MemoryInfoCollector() { super(ReportField.DUMPSYS_MEMINFO, ReportField.TOTAL_MEM_SIZE, ReportField.AVAILABLE_MEM_SIZE); } @Override boolean shouldCollect(Set<ReportField> crashReportFields, ReportField collect, ReportBuilder reportBuilder) { return super.shouldCollect(crashReportFields, collect, reportBuilder) && !(reportBuilder.getException() instanceof OutOfMemoryError); } @NonNull @Override Element collect(ReportField reportField, ReportBuilder reportBuilder) { switch (reportField) { case DUMPSYS_MEMINFO: return collectMemInfo(); case TOTAL_MEM_SIZE: return new NumberElement(getTotalInternalMemorySize()); case AVAILABLE_MEM_SIZE: return new NumberElement(getAvailableInternalMemorySize()); default: //will not happen if used correctly throw new IllegalArgumentException(); } } /** * Collect results of the <code>dumpsys meminfo</code> command restricted to * this application process. * * @return The execution result. */ @NonNull private static Element collectMemInfo() { try { final List<String> commandLine = new ArrayList<String>(); commandLine.add("dumpsys"); commandLine.add("meminfo"); commandLine.add(Integer.toString(android.os.Process.myPid())); final Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[commandLine.size()])); return new StringElement(IOUtils.streamToString(process.getInputStream())); } catch (IOException e) { ACRA.log.e(LOG_TAG, "MemoryInfoCollector.meminfo could not retrieve data", e); return ACRAConstants.NOT_AVAILABLE; } } /** * Calculates the free memory of the device. This is based on an inspection of the filesystem, which in android * devices is stored in RAM. * * @return Number of bytes available. */ private static long getAvailableInternalMemorySize() { final File path = Environment.getDataDirectory(); final StatFs stat = new StatFs(path.getPath()); final long blockSize; final long availableBlocks; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { blockSize = stat.getBlockSizeLong(); availableBlocks = stat.getAvailableBlocksLong(); } else { //noinspection deprecation blockSize = stat.getBlockSize(); //noinspection deprecation availableBlocks = stat.getAvailableBlocks(); } return availableBlocks * blockSize; } /** * Calculates the total memory of the device. This is based on an inspection of the filesystem, which in android * devices is stored in RAM. * * @return Total number of bytes. */ private static long getTotalInternalMemorySize() { final File path = Environment.getDataDirectory(); final StatFs stat = new StatFs(path.getPath()); final long blockSize; final long totalBlocks; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { blockSize = stat.getBlockSizeLong(); totalBlocks = stat.getBlockCountLong(); } else { //noinspection deprecation blockSize = stat.getBlockSize(); //noinspection deprecation totalBlocks = stat.getBlockCount(); } return totalBlocks * blockSize; } }