What is the source of the $post_id in a hook argument?

I thought if you name the parameter as $post_id, the hook automatically adds the post id value, but that’s not the case?

Correct, that’s not the case. What you name it has no effect on what value WP passes through that argument. If you check out the reference for the post_thumbnail_size hook, you can see there that they will always pass the thumbnail size in the first argument, and the post ID in the second argument.

You could even swap the names, and you’d still get the size values in the first and the post ID in the second:

function wpse_299132_post_thumbnail_size( $post_id, $size ) {
    echo "Size: ";
    print_r($post_id);
    echo "Post ID: $size";
}
add_filter( 'wpse_299132_post_thumbnail_size', 'wpse_299132_post_thumbnail_size', 10, 2 );

Outputs (for example):

Size: Array(
    [0] => 120
    [1] => 120
)
Post ID: 1647

How the hooks know if it should give post id value to the parameter?

Each hook has a predetermined set of arguments; for any given hook, you can check the code reference to see exactly which argument will be passing what value.