Windows Timeline
Windows Timeline
db database
Windows Timeline, is a new feature of Windows 10 introduced with version 1803.
It is part of the Connected Devices Platform
- The Connected Devices Platform Service, is a Windows service that provides a way for devices
such as PC's and smartphones to discover and send messages between each other.
- Connected Devices Platform Service (CDPSvc) Defaults in Windows 10.
The CDP settings for the Current User are stored in the registry at:
NTUSER.DAT -> ‘Software\Microsoft\Windows\CurrentVersion\CDP’
and
Before Windows 10 version 1803
The service and the ‘ActivitiesCache.db’ database existed before the 1803 upgrade (May 2018),
but with limited functionality. Another possibly related* activity store location is at:
‘Software\Microsoft\Windows\CurrentVersion\CloudStore\Store\Cache\DefaultAccount\$$wind
ows.data.taskflow.shellactivities\Current’
*(considering that the current ActivitiesCache.db uses taskflow to retrieve device information as
seen further below in this document)
Its value is in hex and it seems to hold interesting information, including the Filetime of last
update (which corresponds to the Last Write Timestamp of the registry key).
If Windows is updated to version 1803, this ‘log’ stops being updated. This can be checked by
looking in the SYSTEM hive at the Setup key like:
In that case, interestingly,
this Filetime is very close to the date of the ntuser.dat.LOG files (which coincides with the date
the 1803 update occurred), and that can also be seen from the last entry above:
The old dB table structure was similar to the new dB, but it included 6 tables + the master table
(the ‘Activity_PackageId’ table was missing, and there were different fields):
Looking at the entries in an L.username folder and a MS account id folder, the username (local
account) dB has these entries:
From this, we can deduce that ‘CurrentSettings’ is where the Activity Types of the entries
populating the database are defined.
The Smartlookup view (query, included in the dB):
select
[O].[Id],
[O].[AppId],
[O].[AppActivityId],
[O].[ActivityType],
[O].[ParentActivityId],
[O].[Tag],
[O].[Group],
[O].[MatchId],
[O].[LastModifiedTime],
[O].[ExpirationTime],
[O].[Payload],
[O].[Priority],
[O].[OriginatingDevice],
[A].[IsLocalOnly],
[A].[PlatformDeviceId],
[A].[CreatedInCloud],
[O].[StartTime],
[O].[EndTime],
[O].[LastModifiedOnClient],
[O].[ETag]
from [ActivityOperation] as [O]
left outer join [Activity] as [A] on [O].[Id] = [A].[Id]
where [O].[OperationType] <> 3
union
select
[Id],
[AppId],
[AppActivityId],
[ActivityType],
[ParentActivityId],
[Tag],
[Group],
[MatchId],
[LastModifiedTime],
[ExpirationTime],
[Payload],
[Priority],
[OriginatingDevice],
[IsLocalOnly],
[PlatformDeviceId],
[CreatedInCloud],
[StartTime],
[EndTime],
[LastModifiedOnClient],
[ETag]
from [Activity]
where [Id] not in (select [Id]
from [ActivityOperation])
Typical ActivityOperation table entries were of ActivityType 2 :
From this, another deduction can be made, that ActitivityType 2 is for Toast Notification entries.
The new (1803) dB has different fields:
After examination of various new ‘ActivitiesCache.db’ files, any entries seen in the new database
have an ‘ActivityType’ (as seen above) of 5 or 6, which appear to represent ‘Open App/File/Url’
and ‘App In Focus’ respectively – type 13 entries were not observed in any dB yet.
The ‘DatabaseInstanceIdUpdateTime’ date seen above, is the date & time (in UTC) that the
current dB file was created.
A Microsoft Account related DB includes one more field, the ‘CurrentEtag’ but instead of using
an ETAG in the form found elsewhere in the dB, it lists it in the form of a GUID – that is the Cloud
ETAG:
The ‘SmartLookUp’ view in the old DB was also different:
The new Timeline & ActivitiesCache.db
The NEW (updated) database stores information for each user in the
%LOCALAPPDATA% \ConnectedDevicesPlatform folder or more commonly familiar as:
C:\users\username\appdata\local\ConnectedDevicesPlatform
This folder has a file named ‘CDPGlobalSettings.cdp’ which is essentially a .json file
and includes information for the service including the store location for the database that holds
the windows timeline entries for the current user.
If a user logs in with a local account, then the “L.UserName” database is populated.
A Microsoft Exchange (Office365 etc.) account starts with ‘AAD’ and is in the form of
AAD.[sid]. AAD denotes a business account (as in Azure Active Directory) and information
associated with this account ‘s [sid] can be found in NTUSER.dat at ->
‘Software\Microsoft\MSOIdentityCRL\UserExtendedProperties’ and/or
‘Software\Microsoft\OneDrive\Accounts\Business1’
However, there are two cases when, even if a user continues to use a local account to sign in
Windows 10 , the activities can still be synchronized across devices:
In this case the “L.UserName” folder is removed, and the active folder is the folder
that corresponds to this account. All activities are synched across devices.
In this case, the local activities are stored in the “L.Username” folder, but any
activity on other devices is stored in the respective folder that corresponds to this
MS account used on these devices.
The timeline settings (‘Settings –> Privacy –> Activity History’) enable or not activity to be
tracked in the ‘ActivitiesCache.db’. In order for the activity to be shared across devices (via the
cloud) you need to login with a Microsoft account, enable Windows Hello (i.e. create pin and or
biometric/photo login).
https://support.microsoft.com/en-us/help/4026102/windows-10-about-sync-settings
To enable cross-device experiences, your app users must login with either a Microsoft Account or
an Azure Active Directory account.
https://github.com/Microsoft/project-rome/blob/master/cross-device_app_configuration.md
https://github.com/microsoftgraph/microsoft-graph-docs/blob/master/api-
reference/beta/resources/intune_deviceconfig_windows10generalconfiguration.md
A list of settings that can be roamed or backed up (synced) across devices can be found here:
https://docs.microsoft.com/en-us/azure/active-directory/active-directory-windows-enterprise-
state-roaming-windows-settings-reference
The same settings can also be configured through Group Policy at ‘Computer Configuration ->
Administrative Templates -> System ->OS Policies’
Opening the respective folder we can see the ‘ActivitiesCache.db’ (and possibly also the
ActivitiesCache.wal and ActivitiesCache.db-sdb files) which is the storage of all timeline activity
for the current user. When a user switches from a Local to a MS account, the ‘L.UserName’ is
deleted and a new one is created (if it didn’t exist before) under the respective MS account
folder. Any previous entries in the ‘L.UserName’’s ‘ActivitiesCache.db’ now appear in the new
‘ActivitiesCache.db’ linked to the MS account, and sync to the cloud. Switching from a MS to a
local account, the MS account related db is still available and holds timeline data.
When a user logs in Windows with a MS account, and the relevant check boxes in ‘Settings –>
Privacy- >Activity History’ are set to On,
any activity created with his other MS account(s), is updated in the ‘ActivitiesCache.db’ in the
respective ‘%LOCALAPPDATA% \ConnectedDevicesPlatform\’ SubFolder, and can be seen in his
timeline view .
Any -excluded from sync- accounts (above setting set to off) can be seen at the registry at:
NTUSER.dat
Software\Microsoft\Windows\CurrentVersion\ActivityDataModel\ActivityAccountFilter
The synchronized entries in a MS account related dB will show the ‘Device ID’ of the machine
the entry originated from. The Device Name and Model of the originating machine can be seen
in the NTUSER.dat’s ‘Software\Microsoft\Windows\CurrentVersion\TaskFlow\DeviceCache\’:
Even if a user logs in with a local account, when a MS Account was previously used for login, the
entries of ‘ActivitiesCache.db’ of that account will also appear in the user’s timeline (for the
previous 7 days). So it may be prudent to examine all ‘ActivitiesCache.db’ databases in a system.
Following is the analysis of the new ‘ActivitiesCache.db’ file, using DB Browser for SQLite , SQLite
Expert Professional, Notepad++ and JSON Viewer.
The database has the following structure (7 tables + the master table):
The ‘Metadata’ table includes the date/time the database was created by the system:
Note: see page 2 above for the differences with the old database
The ‘ManualSequence’ table shows the last Activity (ETAG) recorded in the database:
From the 7 tables above, only three hold information of user activities:
Any new application execution or focus change, triggers an entry to the ‘Activity’ table, and
relevant entries in the ‘Activity_PackageID’ table.
Note: It should be noted that any new entries/transactions are written first to the write ahead
log (‘ActivitiesCache.wal’)
and the database is updated when the wal file reaches 1000 pages and commits the
transactions. The default settings of the database show that each page is 4096 bytes long:
The query below (which is in essence two united queries) extracts all possible useful information
from this database in a readable form. This query will not work properly in any SQLite browser
that does not include support for the json1 extension.
An updated version of this query can be found online at:
https://kacos2000.github.io/WindowsTimeline/
The above query pulls information from the ‘Activity’ , ‘ActivityOperation’ and
‘Activity_PackageId’ tables. The ‘Activity_PackageId’ table is more or less a ‘cache’ of the unique
IDs of each application execution and its expiration time.
Some field explanations provided by Microsoft:
It is the unique ID of each entry/user activity. The same ID can be seen more than 2 times in the
Activity_PackageID table depending on the ‘Platform’ field which has the following possible
values (Note: most of project Rome is still undocumented, so not all entries can be defined):
• “Host” (is listed as many times as the number of entries in the Activity table),
• “packageid”**, (is listed as many times as the number of entries and includes the
executable and its path for all x_exe & windows_win32 apps, as seen in the
Activity_PackageID’s PackageName field)
• “x_exe_path” for Programs called from a specific path (e.g. Standalone executables)
** as seen below:
By running the following query:
select
Activity.ETag,
hex(Activity_PackageId.ActivityId) as 'ID',
replace(replace(replace(replace(replace(replace(
Activity_PackageId.PackageName,
lower('308046B0AF4A39CB'), 'Mozilla Firefox'),
'{'||lower('6D809377-6AF0-444B-8957-A3773F02200E')||'}', '*ProgramFiles (x64)'),
'{'||lower('7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E')||'}', '*ProgramFiles (x32)'),
'{'||lower('1AC14E77-02E7-4E5D-B744-2EB1AE5198B7')||'}', '*System'),
'{'||lower('F38BF404-1D43-42F2-9305-67DE0B28FC23')||'}', '*Windows'),
'{'||lower('D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27')||'}', '*System32') as
'Activity_PackageId.PackageName',
case
when json_extract(Activity.AppId, '$[0].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[0].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32')
when json_extract(Activity.AppId, '$[1].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[1].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32')
when json_extract(Activity.AppId, '$[2].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[2].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32')
when json_extract(Activity.AppId, '$[3].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[3].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32')
when json_extract(Activity.AppId, '$[4].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[4].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32')
when json_extract(Activity.AppId, '$[5].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[5].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32')
when json_extract(Activity.AppId, '$[6].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[6].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32')
when json_extract(Activity.AppId, '$[7].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[7].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32')
when json_extract(Activity.AppId, '$[8].platform') like '%packageid%' then
replace(replace(replace(replace(replace(replace
(json_extract(Activity.AppId, '$[8].application'),
'308046B0AF4A39CB', 'Mozilla Firefox'),
'{'||'6D809377-6AF0-444B-8957-A3773F02200E'||'}', '*ProgramFiles (x64)'),
'{'||'7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E'||'}', '*ProgramFiles (x32)'),
'{'||'1AC14E77-02E7-4E5D-B744-2EB1AE5198B7'||'}', '*System'),
'{'||'F38BF404-1D43-42F2-9305-67DE0B28FC23'||'}', '*Windows'),
'{'||'D65231B0-B2F1-4857-A4CE-A8E7C6EA7D27'||'}', '*System32') end as 'Activity_json_Packageid'
from Activity_PackageId
join Activity on Activity.Id = Activity_PackageId.ActivityId
where Activity_PackageId.ActivityId = Activity.Id and Activity_PackageId.Platform = 'packageid'
Order by etag desc
If the Sync activity is enabled (user logs in with a MS Account) then another entry may also be
seen: "afs_crossplatform" which shows a cloud sync enabled activity, and is an additional entry
to the same ones seen when using a local account.
When using a MS account:
As can also be seen below (these are for a single ID of a Microsoft Word entry):
Select
hex(Activity_PackageId.ActivityId) as 'ActivityId',
Activity_PackageId.Platform ,
Activity_PackageId.PackageName ,
datetime (Activity_PackageId.ExpirationTime , 'unixepoch') as 'ExpirationTime'
FROM Activity_PackageId
join Activity on Activity_PackageId.ActivityId = Activity.Id
order by Activity.ActivityId
[{"application":"mmxsdktest.azurewebsites.net","platform":"host"},
{"application":"16815419600048394801","platform":"afs_crossplatform"},
{"application":"000000004018945C","platform":"msa"},
{"application":"","platform":"packageId"},
{"application":"","platform":"alternateId"},
{"application":"","platform":"windows_universal"}]
The afs_crossplatform field has been observed to contain a numeric representation of the
application used (?), with the exception of MS Office applications and MS Edge:
The ‘Activity_PackageId’ table seemingly has more information than the ‘Activity’ table. That is
not true though, as the ‘Activity’ table’s ‘AppID’ field holds this information and a lot more. The
‘Activity' and ‘ActivityOperation’ table 'AppID' fields are in fact Binary Large Objects (BLOB) in
‘json array’ format e.g.:
Since this is a json array, we can do a query to see what values it holds in the ‘application’ and
‘platform’ fields. The $[x]. depicts the number of the element in the array, and ‘platform’ or
‘application’ the respective field name:
select
hex(Activity.ID) as 'ID',
json_extract(Activity.AppId, '$[0].platform') as 'p0' ,
json_extract(Activity.AppId, '$[0].application') as '0' ,
json_extract(Activity.AppId, '$[1].platform') as 'p1' ,
json_extract(Activity.AppId, '$[1].application') as '1' ,
json_extract(Activity.AppId, '$[2].platform') as 'p2' ,
json_extract(Activity.AppId, '$[2].application') as '2' ,
json_extract(Activity.AppId, '$[3].platform') as 'p3' ,
json_extract(Activity.AppId, '$[3].application') as '3' ,
json_extract(Activity.AppId, '$[4].platform') as 'p4' ,
json_extract(Activity.AppId, '$[4].application') as '4',
json_extract(Activity.AppId, '$[5].platform') as 'p5' ,
json_extract(Activity.AppId, '$[5].application') as '5' ,
json_extract(Activity.AppId, '$[6].platform') as 'p6' ,
json_extract(Activity.AppId, '$[6].application') as '6' ,
json_extract(Activity.AppId, '$[7].platform') as 'p7' ,
json_extract(Activity.AppId, '$[7].application') as '7' ,
json_extract(Activity.AppId, '$[8].platform') as 'p8' ,
json_extract(Activity.AppId, '$[8].application') as '8'
from Activity
order by ID asc
Or
Similarly, the ‘Activity’ and the ‘ActivityOperation’ table 'payload' fields (blob) are also in json
format with different entries related to the different platform type as follows:
"windows_universal" (In this case MS Edge - which uses the Adaptive Card framework -
bing search for CDPTraces.log) can be seen below:
All Dates/Times are stored by the database in UTC. To get the local times, we can adjust the
query by using, 'localtime' e.g. :
The ‘ExpirationTime’ is exactly 2592000 seconds or 30 Days from the relevant entry’s
‘LastModified’ time, and is easily seen by using the following:
Select
(Activity.ExpirationTime - Activity.LastModifiedTime) as 'Expires in'
From Activity
Sorting the query by the 'ETAG' field gives a historical list (sort of a timeline) according to the
Events recorded in the db, but is not the same as if sorted by Start, End or Expiry datetimes.
The ETAG can change for a particular entry’s GUID depending on the current action the
database has recorded for that ID (e.g. user removed Tile from timeline).
An example that an ID can have multiple ETAGs associated with it, is shown below:
“Software\Microsoft\Windows\CurrentVersion\TaskFlow\DeviceCache\”.
As seen below:
But it is not fixed - it looks encoded with the QuickXorHash Algorithm, similar to the
‘FileShellLink’ in the ‘Payload’ field blob - and it changes occasionally,
still depicting the same Machine (as seen at the relevant registry entries). I have not yet found
the pattern as to why or when it changes when a user logs in with a local account.
It is used to show the Device* origin of a Tile in the Timeline view, such as:
*(if no device name is seen in one or more tiles in the user’s Timeline view, then the activity is local)
The device name seen above is derived from the “DeviceModel” entry in the registry for the
specific DeviceID. That information originates from the OEM information value in
‘SystemProductName’ at “HKLM\SYSTEM\ControlSet001\Control\SystemInformation” which is
usually filled by the device manufacturer, or is blank when the computer is user assembled.
select
case when Activity.AppActivityId not like '%-%-%-%-%\%' then Activity.AppActivityId
when Activity.AppActivityId not like '%-%-%-%-%' then Activity.AppActivityId
else substr(Activity.AppActivityId , 38)
end as 'DeviceID',
datetime(Activity.StartTime, 'unixepoch', 'localtime') AS 'StartTime',
json_extract(Activity.Payload, '$.displayText') as 'File_Name'
from Activity
join Activity_PackageId on activity.id = Activity_PackageId.ActivityId
group by File_Name
order by StartTime asc
The ‘PackageIDHash’ field is a unique value related to each application. It appears to be the
‘QuickXorHash’ of the executable – with this query:
select
Activity.PackageIdHash as 'Hash',
Activity_PackageId.PackageName as 'Name',
datetime(Activity.StartTime, 'unixepoch', 'localtime') AS 'StartTime'
from Activity
join Activity_PackageId on activity.id = Activity_PackageId.ActivityId
group by Hash
order by StartTime desc
we can see that different versions of the same application have a different Hash value:
the associated ID(s) to this Tile remain the same, but the entries are copied from the ‘Activity’ to
the ‘ActivityOperation’ table with a NEW ‘Etag’ and new type/status value:
When the user logs in with a local account, and a tile is removed from the Timeline, the
associated entries for that are copied from the ‘Activity’ to the ‘ActivityOperation’ table with a
different ‘ETAG’ value, and stay there until expiration time.
An easy way to figure out which entries are User Removed can be derived from viewing the
‘SmartLookup’ view (automatically created query included in the database) which, in essence, is
the source of the actual timeline a user observes:
The key here is the line: FROM [Activity] WHERE [Id] NOT IN (SELECT [Id] FROM [ActivityOperation])
If we check the ‘SmartLookup’ query data view, it lists all ‘Activity’ table entries plus all
‘ActivityOperation’ table entries minus the ‘Activity’ table entries that appear in both tables with
the same ID. Why? Because when the ActivityOperation.Id is also found in the Activity.Id then
the entry has been (user) removed from the timeline.
What this query also does, is to mark (and list) all entries in the ‘Activity’ table with a value of 0
in the field [IsInUploadQueue], and all entries in the ‘ActivityOperations with a value of 1 in the
[IsInUploadQueue]. What this means, is that the entries in the ‘ActivityOperations’ table are in
the ‘Upload to Cloud Queue’ unless they also appear in the ‘Activity’ table.
However, when a user is logged in with a MS Account, and the user removes a tile from the
Timeline, the respective entries are copied to the ‘ActivityOperation’ table with a new ‘Etag’
value and a new type/status of 3 (Deleted) momentarily until they are synced, and then they are
moved to the ‘Activity’ table until they expire. The type/status value 3 tells the other
synchronized devices not to display this tile in their Timeline. This may be confusing when
examining an offline system:
The following query checks every ID on ‘Activity_PackageID’ against both ‘Activity’ and
‘ActivityOperation’ tables and provides the relevant results:
Archived:
Activity.ID
ID not in either table.
Activity_PackageID.ActivityID
ActivityOperation.ID
Tile Removed:
Activity.ID
ID in both tables.
Activity_PackageID.ActivityID
ActivityOperation.ID
New Activity:
ID only in the Activity table. Activity.ID
Activity_PackageID.ActivityID
ActivityOperation.ID
In Upload Queue:
ID only in ActivityOperation table. Activity.ID
Activity_PackageID.ActivityID
ActivityOperation.ID
select
case
when
Activity_PackageId.ActivityId in (select Activity.Id from activity) and
Activity_PackageId.ActivityId in (select ActivityOperation.Id
from ActivityOperation)
then 'Tile Removed - '||hex(Activity_PackageId.ActivityId)
else
case
when Activity_PackageId.ActivityId not in
(select Activity.Id from activity) and
Activity_PackageId.ActivityId not in
(select ActivityOperation.Id from ActivityOperation)
then 'Is Archived - '||hex(Activity_PackageId.ActivityId)
else
case
when Activity_PackageId.ActivityId in
(select Activity.Id from activity) and
Activity_PackageId.ActivityId not in
(select ActivityOperation.Id from ActivityOperation)
then 'New Activity - '||hex(Activity_PackageId.ActivityId)
else
case
when Activity_PackageId.ActivityId
not in (select Activity.Id from Activity)
and Activity_PackageId.ActivityId
in (select ActivityOperation.Id from ActivityOperation)
then '
In Upload Queue - '||hex(Activity_PackageId.ActivityId)
end
end
end
end as 'Status_ID', -- This field includes both the Status and the unique ID of the associated activity
Activity_PackageId.PackageName as 'PackageName', -- The program/ associated with the above ID
datetime(Activity_PackageId.ExpirationTime, 'unixepoch', 'localtime') as 'ExpirationTime',
Activity_PackageId.Platform
from Activity_PackageId
where Activity_PackageId.Platform in ('windows_win32', 'windows_universal', 'x_exe_path')
group by Status_ID
order by ExpirationTime asc
- 'New activity'
- 'Had the associated timeline tile removed'
- 'In the Upload Queue'
- Archived' (until expiration time)
Another view of the timeline and the items discussed above can be seen with this query:
https://kacos2000.github.io/WindowsTimeline/WindowsTimeline2.sql
_____________________________
Upcoming changes with Windows 10 version 1809 (October 2018 update)
(The following in based on Win10 Insider’s build 17744.rc5_release.180818-1845)
With the main tables being ‘Activities’ and ‘ActivitiesOperation’, while ‘Activities_PackageID’
was the link and archive of all the activity entries.
The database structure has changed a bit with the new October 2018 Windows 10 update
(version 1809). A new table is introduced:
Activity ActivityOperation
UploadAllowedByPolicy
UserActionState UserActionState
IsRead IsRead
GroupItems GroupItems
Before (1803) After (1809)
The Metadata table is the one major change. The Current Settings key, as previously, is where
the allowed Activity Types are listed:
• DatabaseNotificationSubscriptionInfo,
• DatabaseActivityPolicies and
• PendingActivityTypes
Activity Types 11 and 12 are only allowed for the application “Microsoft.Credentials.WiFi” and
only for the Platform entry “data_boundary”.
Where the PermissionScope is the Application, and Type is the ActivityType blocked for this
application. BlockedOperationFlags has seen with values 0, 1 and 7. In the above screenshot,
MicrosoftPersonalization and Microsoft.Credentials apps are NOT blocked for ActivityTypes 11
and 12.
BlockedOperationFlags value 1 means that this Element is Blocked for example, ActivityType 8 is
blocked (we can see that in the AllowedTypes as well):
Whereas value 0 means that this ActivityType is NOT blocked:
Is not yet explained. I suspect that it means that this is user configurable from “Sync your
Settings”, but not sure yet.
Finally ‘PendingActivityTypes’ value is also a JSON blob, but empty at this time.
With observed values 0 and 1. The obvious deduction is that entries with value 1 are Yes and
entries with value 0 are No. The Metadata table is where these policies are defined.
Note: The encryption (?) certificates are store at
C:\Users\%Username%\AppData\Roaming\Microsoft\Crypto\Keys
In the latest update, we have a new “ActivityType” -> 10 which is clipboard data
(I have only observed clipboard text).
The Metadata table now includes ActivityType 10 :
The field “ClipboardPayload” (JSON blob) of entries with ActivityType 10 (Clipboard text) contain
the copied text in Base64 encoding in the form:
[{"content":"eyJBbGxvd2VkU3Vic2NyaXB0aW9uU3luY1Njb3BlcyI6W3siYWN0aXZpdHlUeXBlcyI6
WzAsMSwyLDMsNCw1LDYsNywxMCwxMywxNV0sImFwcGxpY2F0aW9uIjoiKiJ9LHsiYWN0aXZpd
HlUeXBlcyI6WzExLDEyXSwiYXBwbGljYXRpb24iOiJNaWNyb3NvZnQuQ3JlZGVudGlhbHMuVmF1bH
QiLCJwbGF0Zm9ybSI6ImRhdGFfYm91bmRhcnkifSx7ImFjdGl2aXR5VHlwZXMiOlsxMSwxMl0sImF
wcGxpY2F0aW9uIjoiTWljcm9zb2Z0LkNyZWRlbnRpYWxzLldpRmkiLCJwbGF0Zm9ybSI6ImRhdGFfY
m91bmRhcnkifSx7ImFjdGl2aXR5VHlwZXMiOlsxMV0sImFwcGxpY2F0aW9uIjoibWljcm9zb2Z0LmR
lZmF1bHQuZGVmYXVsdCIsInBsYXRmb3JtIjoiZGF0YV9ib3VuZGFyeSJ9XSwiUG9saWNpZXMiOlt7IkJ
sb2NrZWRPcGVyYXRpb25GbGFncyI6MCwiU2NvcGUiOnsiUGVybWlzaW9uU2NvcGUiOiIiLCJUeXBl
IjoxMX0sIlNvdXJjZSI6MX0seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3MiOjAsIlNjb3BlIjp7IlBlcm1pc2lv
blNjb3BlIjoiTWljcm9zb2Z0LkNyZWRlbnRpYWxzIiwiVHlwZSI6MTF9LCJTb3VyY2UiOjF9LHsiQmxvY2
tlZE9wZXJhdGlvbkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6Ik1pY3Jvc29mdC5QZXJ
zb25hbGl6YXRpb24iLCJUeXBlIjoxMX0sIlNvdXJjZSI6MX0seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3Mi
OjAsIlNjb3BlIjp7IlBlcm1pc2lvblNjb3BlIjoiIiwiVHlwZSI6MTJ9LCJTb3VyY2UiOjF9LHsiQmxvY2tlZE9w
ZXJhdGlvbkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6Ik1pY3Jvc29mdC5DcmVkZW5
0aWFscyIsIlR5cGUiOjEyfSwiU291cmNlIjoxfSx7IkJsb2NrZWRPcGVyYXRpb25GbGFncyI6MCwiU2Nv
cGUiOnsiUGVybWlzaW9uU2NvcGUiOiJNaWNyb3NvZnQuUGVyc29uYWxpemF0aW9uIiwiVHlwZS
I6MTJ9LCJTb3VyY2UiOjF9LHsiQmxvY2tlZE9wZXJhdGlvbkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNp
b25TY29wZSI6IiIsIlR5cGUiOjExfSwiU291cmNlIjoyfSx7IkJsb2NrZWRPcGVyYXRpb25GbGFncyI6MC
wiU2NvcGUiOnsiUGVybWlzaW9uU2NvcGUiOiIiLCJUeXBlIjoxMn0sIlNvdXJjZSI6Mn0seyJCbG9ja2V
kT3BlcmF0aW9uRmxhZ3MiOjcsIlNjb3BlIjp7IlBlcm1pc2lvblNjb3BlIjoiIiwiVHlwZSI6MTB9LCJTb3Vy
Y2UiOjN9LHsiQmxvY2tlZE9wZXJhdGlvbkZsYWdzIjo3LCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6IiI
sIlR5cGUiOjEyfSwiU291cmNlIjozfSx7IkJsb2NrZWRPcGVyYXRpb25GbGFncyI6NywiU2NvcGUiOnsi
UGVybWlzaW9uU2NvcGUiOiIiLCJUeXBlIjoxNX0sIlNvdXJjZSI6M30seyJCbG9ja2VkT3BlcmF0aW9uR
mxhZ3MiOjAsIlNjb3BlIjp7IlBlcm1pc2lvblNjb3BlIjoiIiwiVHlwZSI6MTB9LCJTb3VyY2UiOjR9LHsiQmx
vY2tlZE9wZXJhdGlvbkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6IiIsIlR5cGUiOjEwfSw
iU291cmNlIjo1fSx7IkJsb2NrZWRPcGVyYXRpb25GbGFncyI6MCwiU2NvcGUiOnsiUGVybWlzaW9u
U2NvcGUiOiIiLCJUeXBlIjoxMX0sIlNvdXJjZSI6NX0seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3MiOjcsIlN
jb3BlIjp7IlBlcm1pc2lvblNjb3BlIjoiTWljcm9zb2Z0LkFjY2Vzc2liaWxpdHkiLCJUeXBlIjoxMX0sIlNvdXJj
ZSI6NX0seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3MiOjcsIlNjb3BlIjp7IlBlcm1pc2lvblNjb3BlIjoiTWljc
m9zb2Z0LkNyZWRlbnRpYWxzIiwiVHlwZSI6MTF9LCJTb3VyY2UiOjV9LHsiQmxvY2tlZE9wZXJhdGlv
bkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6Ik1pY3Jvc29mdC5EZWZhdWx0IiwiVHlw
ZSI6MTF9LCJTb3VyY2UiOjV9LHsiQmxvY2tlZE9wZXJhdGlvbkZsYWdzIjo3LCJTY29wZSI6eyJQZXJtaX
Npb25TY29wZSI6Ik1pY3Jvc29mdC5MYW5ndWFnZSIsIlR5cGUiOjExfSwiU291cmNlIjo1fSx7IkJsb2N
rZWRPcGVyYXRpb25GbGFncyI6NywiU2NvcGUiOnsiUGVybWlzaW9uU2NvcGUiOiJNaWNyb3NvZn
QuUGVyc29uYWxpemF0aW9uIiwiVHlwZSI6MTF9LCJTb3VyY2UiOjV9LHsiQmxvY2tlZE9wZXJhdGlv
bkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6IiIsIlR5cGUiOjEyfSwiU291cmNlIjo1fSx7I
kJsb2NrZWRPcGVyYXRpb25GbGFncyI6NywiU2NvcGUiOnsiUGVybWlzaW9uU2NvcGUiOiJNaWNy
b3NvZnQuQWNjZXNzaWJpbGl0eSIsIlR5cGUiOjEyfSwiU291cmNlIjo1fSx7IkJsb2NrZWRPcGVyYXRp
b25GbGFncyI6NywiU2NvcGUiOnsiUGVybWlzaW9uU2NvcGUiOiJNaWNyb3NvZnQuQ3JlZGVudGl
hbHMiLCJUeXBlIjoxMn0sIlNvdXJjZSI6NX0seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3MiOjAsIlNjb3BlIj
p7IlBlcm1pc2lvblNjb3BlIjoiTWljcm9zb2Z0LkRlZmF1bHQiLCJUeXBlIjoxMn0sIlNvdXJjZSI6NX0seyJC
bG9ja2VkT3BlcmF0aW9uRmxhZ3MiOjcsIlNjb3BlIjp7IlBlcm1pc2lvblNjb3BlIjoiTWljcm9zb2Z0Lkxhb
md1YWdlIiwiVHlwZSI6MTJ9LCJTb3VyY2UiOjV9LHsiQmxvY2tlZE9wZXJhdGlvbkZsYWdzIjo3LCJTY2
9wZSI6eyJQZXJtaXNpb25TY29wZSI6Ik1pY3Jvc29mdC5QZXJzb25hbGl6YXRpb24iLCJUeXBlIjoxMn0
sIlNvdXJjZSI6NX0seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3MiOjEsIlNjb3BlIjp7IlBlcm1pc2lvblNjb3BlI
joiIiwiVHlwZSI6OH0sIlNvdXJjZSI6N30seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3MiOjEsIlNjb3BlIjp7Il
Blcm1pc2lvblNjb3BlIjoiIiwiVHlwZSI6OX0sIlNvdXJjZSI6N30seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3
MiOjAsIlNjb3BlIjp7IlBlcm1pc2lvblNjb3BlIjoiIiwiVHlwZSI6MTB9LCJTb3VyY2UiOjd9LHsiQmxvY2tlZE
9wZXJhdGlvbkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6IiIsIlR5cGUiOjExfSwiU291c
mNlIjo3fSx7IkJsb2NrZWRPcGVyYXRpb25GbGFncyI6MCwiU2NvcGUiOnsiUGVybWlzaW9uU2NvcG
UiOiIiLCJUeXBlIjoxMn0sIlNvdXJjZSI6N30seyJCbG9ja2VkT3BlcmF0aW9uRmxhZ3MiOjAsIlNjb3BlIjp
7IlBlcm1pc2lvblNjb3BlIjoiIiwiVHlwZSI6MTV9LCJTb3VyY2UiOjd9LHsiQmxvY2tlZE9wZXJhdGlvbkZs
YWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6IiIsIlR5cGUiOjV9LCJTb3VyY2UiOjh9LHsiQmx
vY2tlZE9wZXJhdGlvbkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6IiIsIlR5cGUiOjZ9LCJ
Tb3VyY2UiOjh9LHsiQmxvY2tlZE9wZXJhdGlvbkZsYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29
wZSI6IiIsIlR5cGUiOjh9LCJTb3VyY2UiOjh9LHsiQmxvY2tlZE9wZXJhdGlvbkZsYWdzIjowLCJTY29wZSI
6eyJQZXJtaXNpb25TY29wZSI6IiIsIlR5cGUiOjl9LCJTb3VyY2UiOjh9LHsiQmxvY2tlZE9wZXJhdGlvbkZ
sYWdzIjowLCJTY29wZSI6eyJQZXJtaXNpb25TY29wZSI6IiIsIlR5cGUiOjEwfSwiU291cmNlIjo5fV19","f
ormatName":"Text"}]
(Translated below:)
.
{"gdprType":"ProductAndServiceUsage","clipboardDataId":"{B268A259-DAAD-47FA-A089-
55E3BB298BCB}"}
Another new ‘ActivityType’ 16 contains data on the application from where data was
copied/pasted from/to, and the ‘Group’ field shows what action was operated:
The copy paste operations can be linked with the ‘clipboardDataId' value in the Payload field
(JSON) eg:
{"gdprType":"ProductAndServiceUsage","clipboardDataId":"{BA306A6E-2B7B-483B-B9B6-
76BB7AF64D12}"}