use of com.microsoft.appcenter.ingestion.models.Device in project mobile-center-sdk-android by Microsoft.
the class ErrorLogHelper method parseDevice.
/**
* Look for 'deviceInfo' data in file inside the minidump folder and parse it.
* @param contextInformation - data with information about userId.
* @return deviceInfo or null.
*/
@VisibleForTesting
static Device parseDevice(String contextInformation) {
try {
Device device = new Device();
JSONObject jsonObject = new JSONObject(contextInformation);
JSONObject deviceJson;
if (jsonObject.has(DEVICE_INFO_KEY)) {
deviceJson = new JSONObject(jsonObject.getString(DEVICE_INFO_KEY));
} else {
deviceJson = jsonObject;
}
device.read(deviceJson);
return device;
} catch (JSONException e) {
AppCenterLog.error(Crashes.LOG_TAG, "Failed to deserialize device info.", e);
}
return null;
}
use of com.microsoft.appcenter.ingestion.models.Device in project mobile-center-sdk-android by Microsoft.
the class ErrorLogHelper method getNewMinidumpSubfolderWithContextData.
/**
* A one-time run-specific folder where unprocessed NDK crashes are saved.
* Each launch of the application creates its own sub-folder with a random name
* to store information about the current device (including the application version),
* which is used in the error report.
*
* @return a folder name e.g. /lib/files/error/minidump/new/aae16c29-f9e7-42a9-baee-0777e6ba8fe3
*/
@NonNull
public static synchronized File getNewMinidumpSubfolderWithContextData(Context context) {
File directorySubfolder = getNewMinidumpSubfolder();
File deviceInfoFile = new File(directorySubfolder, ErrorLogHelper.DEVICE_INFO_FILE);
try {
Device deviceInfo = DeviceInfoHelper.getDeviceInfo(context);
String userIdContext = UserIdContext.getInstance().getUserId();
deviceInfo.setWrapperSdkName(WRAPPER_SDK_NAME_NDK);
/* To JSON. */
JSONStringer writer = new JSONStringer();
writer.object();
deviceInfo.write(writer);
writer.endObject();
String deviceInfoString = writer.toString();
JSONObject jsonObject = new JSONObject();
jsonObject.put(DEVICE_INFO_KEY, deviceInfoString);
jsonObject.put(USER_ID_KEY, userIdContext);
/* Write file. */
FileManager.write(deviceInfoFile, jsonObject.toString());
} catch (DeviceInfoHelper.DeviceInfoException | IOException | JSONException e) {
AppCenterLog.error(Crashes.LOG_TAG, "Failed to store device info in a minidump folder.", e);
// noinspection ResultOfMethodCallIgnored
deviceInfoFile.delete();
}
return directorySubfolder;
}
use of com.microsoft.appcenter.ingestion.models.Device in project mobile-center-sdk-android by Microsoft.
the class CrashesTest method testNativeCrashLog.
private ManagedErrorLog testNativeCrashLog(long appStartTime, long crashTime, boolean correlateSession, boolean hasDeviceInfo, boolean hasUserId) throws Exception {
/* Create minidump sub-folder. */
File minidumpSubfolder = mTemporaryFolder.newFolder("mockFolder");
String mockUserId = "user-id";
/* Create a file for a crash in disk. */
File minidumpFile = new File(minidumpSubfolder, "mockFile.dmp");
assertTrue(minidumpFile.createNewFile());
assertTrue(minidumpFile.setLastModified(crashTime));
/* Create an additional file in a folder to be filtered later. */
File otherFile = new File(minidumpSubfolder, "otherFile.txt");
long fakeCrashTime = new Date().getTime();
assertTrue(otherFile.createNewFile());
assertTrue(otherFile.setLastModified(fakeCrashTime));
/* Mock session context. */
mockStatic(SessionContext.class);
SessionContext sessionContext = mock(SessionContext.class);
when(SessionContext.getInstance()).thenReturn(sessionContext);
if (correlateSession) {
SessionContext.SessionInfo sessionInfo = mock(SessionContext.SessionInfo.class);
when(sessionContext.getSessionAt(crashTime)).thenReturn(sessionInfo);
when(sessionInfo.getAppLaunchTimestamp()).thenReturn(appStartTime);
}
/* Mock device info and ErrorLogHelper. */
mockStatic(ErrorLogHelper.class);
mockStatic(DeviceInfoHelper.class);
Device device = mock(Device.class);
when(DeviceInfoHelper.getDeviceInfo(any(Context.class))).thenReturn(mock(Device.class));
when(ErrorLogHelper.getStoredDeviceInfo(any(File.class))).thenReturn(hasDeviceInfo ? device : null);
when(ErrorLogHelper.getStoredUserInfo(any(File.class))).thenReturn(hasUserId ? mockUserId : null);
ErrorReport report = new ErrorReport();
File errorLogFile = mock(File.class);
when(errorLogFile.length()).thenReturn(1L);
when(ErrorLogHelper.getLastErrorLogFile()).thenReturn(errorLogFile);
when(ErrorLogHelper.getStoredErrorLogFiles()).thenReturn(new File[] { mock(File.class) });
when(ErrorLogHelper.getNewMinidumpFiles()).thenReturn(new File[] { minidumpSubfolder });
File pendingDir = mock(File.class);
Whitebox.setInternalState(pendingDir, "path", "");
when(ErrorLogHelper.getPendingMinidumpDirectory()).thenReturn(pendingDir);
when(ErrorLogHelper.getErrorReportFromErrorLog(any(ManagedErrorLog.class), anyString())).thenReturn(report);
when(ErrorLogHelper.parseLogFolderUuid(any(File.class))).thenReturn(UUID.randomUUID());
when(FileManager.read(any(File.class))).thenReturn("");
LogSerializer logSerializer = mock(LogSerializer.class);
ArgumentCaptor<Log> log = ArgumentCaptor.forClass(Log.class);
when(logSerializer.serializeLog(log.capture())).thenReturn("{}");
when(logSerializer.deserializeLog(anyString(), anyString())).thenAnswer(new Answer<ManagedErrorLog>() {
@Override
public ManagedErrorLog answer(InvocationOnMock invocation) {
com.microsoft.appcenter.crashes.ingestion.models.Exception mockException = new com.microsoft.appcenter.crashes.ingestion.models.Exception();
mockException.setType(MINIDUMP_FILE);
mockException.setMessage("message");
ManagedErrorLog log = mock(ManagedErrorLog.class);
when(log.getId()).thenReturn(UUID.randomUUID());
when(log.getException()).thenReturn(mockException);
return log;
}
});
/* Start crashes. */
Crashes crashes = Crashes.getInstance();
crashes.setLogSerializer(logSerializer);
crashes.onStarting(mAppCenterHandler);
crashes.onStarted(mock(Context.class), mock(Channel.class), "", null, true);
/* Verify timestamps on the crash log. */
assertTrue(Crashes.hasCrashedInLastSession().get());
assertTrue(log.getValue() instanceof ManagedErrorLog);
assertEquals(1, log.getAllValues().size());
assertNotEquals(new Date(fakeCrashTime), log.getValue().getTimestamp());
return (ManagedErrorLog) log.getValue();
}
use of com.microsoft.appcenter.ingestion.models.Device in project mobile-center-sdk-android by Microsoft.
the class Crashes method processSingleMinidump.
/**
* Process the minidump, save an error log with a reference to the minidump, move the minidump file to the 'pending' folder.
*
* @param minidumpFile a file where an ndk crash is saved.
* @param minidumpFolder a folder that contains device info and a minidump file.
*/
private void processSingleMinidump(File minidumpFile, File minidumpFolder) {
/* Create missing files from the native crash that we detected. */
AppCenterLog.debug(LOG_TAG, "Process pending minidump file: " + minidumpFile);
long minidumpDate = minidumpFile.lastModified();
File dest = new File(ErrorLogHelper.getPendingMinidumpDirectory(), minidumpFile.getName());
Exception modelException = new Exception();
modelException.setType("minidump");
modelException.setWrapperSdkName(WRAPPER_SDK_NAME_NDK);
modelException.setMinidumpFilePath(dest.getPath());
ManagedErrorLog errorLog = new ManagedErrorLog();
errorLog.setException(modelException);
errorLog.setTimestamp(new Date(minidumpDate));
errorLog.setFatal(true);
errorLog.setId(ErrorLogHelper.parseLogFolderUuid(minidumpFolder));
/* Lookup app launch timestamp in session history. */
SessionContext.SessionInfo session = SessionContext.getInstance().getSessionAt(minidumpDate);
if (session != null && session.getAppLaunchTimestamp() <= minidumpDate) {
errorLog.setAppLaunchTimestamp(new Date(session.getAppLaunchTimestamp()));
} else {
/*
* Fall back to log date if app launch timestamp information lost
* or in the future compared to crash time.
* This also covers the case where app launches then crashes within 1s:
* app launch timestamp would have ms accuracy while minidump file is without
* ms, in that case we also falls back to log timestamp
* (this would be same result as truncating ms).
*/
errorLog.setAppLaunchTimestamp(errorLog.getTimestamp());
}
/*
* TODO The following properties are placeholders because fields are required.
* They should be removed from schema as not used by server.
*/
errorLog.setProcessId(0);
errorLog.setProcessName("");
try {
String savedUserId = ErrorLogHelper.getStoredUserInfo(minidumpFolder);
Device savedDeviceInfo = ErrorLogHelper.getStoredDeviceInfo(minidumpFolder);
if (savedDeviceInfo == null) {
/*
* Fallback to use device info from the current launch.
* It may lead to an incorrect app version being reported.
*/
savedDeviceInfo = getDeviceInfo(mContext);
savedDeviceInfo.setWrapperSdkName(WRAPPER_SDK_NAME_NDK);
}
errorLog.setDevice(savedDeviceInfo);
errorLog.setUserId(savedUserId);
saveErrorLogFiles(new NativeException(), errorLog);
if (!minidumpFile.renameTo(dest)) {
throw new IOException("Failed to move file");
}
} catch (java.lang.Exception e) {
// noinspection ResultOfMethodCallIgnored
minidumpFile.delete();
removeAllStoredErrorLogFiles(errorLog.getId());
AppCenterLog.error(LOG_TAG, "Failed to process new minidump file: " + minidumpFile, e);
}
}
use of com.microsoft.appcenter.ingestion.models.Device in project mobile-center-sdk-android by Microsoft.
the class AnalyticsSerializerTest method someBatch.
@Test
public void someBatch() throws JSONException {
LogContainer expectedContainer = new LogContainer();
Device device = new Device();
device.setSdkName("appcenter.android");
device.setSdkVersion("1.2.3");
device.setModel("S5");
device.setOemName("HTC");
device.setOsName("Android");
device.setOsVersion("4.0.3");
device.setOsBuild("LMY47X");
device.setOsApiLevel(15);
device.setLocale("en_US");
device.setTimeZoneOffset(120);
device.setScreenSize("800x600");
device.setAppVersion("3.2.1");
device.setAppBuild("42");
List<Log> logs = new ArrayList<>();
{
StartSessionLog startSessionLog = new StartSessionLog();
startSessionLog.setTimestamp(new Date());
logs.add(startSessionLog);
}
expectedContainer.setLogs(logs);
{
PageLog pageLog = new PageLog();
pageLog.setTimestamp(new Date());
pageLog.setName("home");
logs.add(pageLog);
}
{
PageLog pageLog = new PageLog();
pageLog.setTimestamp(new Date());
pageLog.setName("settings");
pageLog.setProperties(new HashMap<String, String>() {
{
put("from", "home_menu");
put("orientation", "portrait");
}
});
logs.add(pageLog);
}
{
EventLog eventLog = new EventLog();
eventLog.setTimestamp(new Date());
eventLog.setId(UUID.randomUUID());
eventLog.setName("subscribe");
logs.add(eventLog);
}
{
EventLog eventLog = new EventLog();
eventLog.setTimestamp(new Date());
eventLog.setId(UUID.randomUUID());
eventLog.setName("click");
eventLog.setProperties(new HashMap<String, String>() {
{
put("x", "1");
put("y", "2");
}
});
logs.add(eventLog);
}
{
List<TypedProperty> properties = new ArrayList<>();
BooleanTypedProperty bp = new BooleanTypedProperty();
bp.setName("n1");
bp.setValue(true);
properties.add(bp);
DateTimeTypedProperty dtp = new DateTimeTypedProperty();
dtp.setName("n2");
dtp.setValue(new Date());
properties.add(dtp);
DoubleTypedProperty dp = new DoubleTypedProperty();
dp.setName("n3");
dp.setValue(10);
properties.add(dp);
LongTypedProperty lp = new LongTypedProperty();
lp.setName("n4");
lp.setValue(10000000000L);
properties.add(lp);
StringTypedProperty sp = new StringTypedProperty();
sp.setName("n5");
sp.setValue("value");
properties.add(sp);
EventLog eventLog = new EventLog();
eventLog.setTimestamp(new Date());
eventLog.setId(UUID.randomUUID());
eventLog.setName("event");
eventLog.setTypedProperties(properties);
logs.add(eventLog);
}
UUID sid = UUID.randomUUID();
for (Log log : logs) {
log.setSid(sid);
log.setDevice(device);
}
LogSerializer serializer = new DefaultLogSerializer();
serializer.addLogFactory(StartSessionLog.TYPE, new StartSessionLogFactory());
serializer.addLogFactory(PageLog.TYPE, new PageLogFactory());
serializer.addLogFactory(EventLog.TYPE, new EventLogFactory());
String payload = serializer.serializeContainer(expectedContainer);
android.util.Log.v(TAG, payload);
LogContainer actualContainer = serializer.deserializeContainer(payload, null);
Assert.assertEquals(expectedContainer, actualContainer);
}
Aggregations